ZYNQ学习笔记-MISC设备驱动开发
MISC杂项设备,是Linux中用于归类ADC、蜂鸣器等不好分类的设备。其特点为共用一个主设备号10,不同设备使用不同设备号,同时会自动创建cdev和创建节点,大大简化字符设备的编写。
MISC设备简介
MISC设备由一个miscdevice结构体描述,该结构体在include/linux/miscdevice.h 中定义:
struct miscdevice {
int minor; // 次设备号
const char *name; // 设备名字
const struct file_operations *fops; // 设备操作函数集合
struct list_head list;
struct device *parent;
struct device *this_device;
const struct attribute_group **groups;
const char *nodename;
umode_t mode;
};
这里我们需要关注minor,name,fops变量。minor为从设备号,需要用户自己指定,在miscdevice.h中定义了一些预定的设备号,但是一般我们只需要关注一个值:
#define MISC_DYNAMIC_MINOR 255
将minor设置为这个值,系统将会将动态分配设备号。
name就是模块名字,注册设备后将会在dev/下生成该名字的文件。
MISC与传统字符驱动的不同
普通字符设备进行注册需要进行以下步骤:
alloc_chrdev_region(); /* 申请设备号 */
cdev_init(); /* 初始化 cdev */
cdev_add(); /* 添加 cdev */
class_create(); /* 创建类 */
device_create(); /* 创建设备 */
在MISC设备中,直接调用一个函数即可:
int misc_register(struct miscdevice * misc)
同样的,对于注销,字符设备需要执行以下步骤:
cdev_del(); /* 删除 cdev */
unregister_chrdev_region(); /* 注销设备号 */
device_destroy(); /* 删除设备 */
class_destroy(); /* 删除类 */
在MISC中,只需要一个函数:
int misc_deregister(struct miscdevice *misc)
可见MISC设备大大简化了字符设备的创建过程,同时还节约了设备号,不用手动创建节点。
一个例子
以PIR红外传感器驱动为例:
#include <linux/init.h>
#include <linux/platform_device.h>
#include <linux/module.h>
#include <linux/miscdevice.h>
#include <linux/ioport.h>
#include <linux/of.h>
#include <linux/fs.h>
#include <linux/delay.h>
#include <asm/io.h>
#include <linux/time.h>
#include <asm/uaccess.h>
/* 驱动名称 */
#define DEVICE_NAME "ccd_pir"
/* gpio 寄存器虚拟地址 */
static void __iomem *gpio_add_minor_pir;
//static void __iomem *gpio_add_minor_led;
/* gpio 寄存器物理基地址 */
#define GPIO_BASE_PIR 0x41210000
//#define GPIO_BASE_LED 0x41200000
unsigned int GPIO_TRI_Offset = 0x4;
unsigned int GPIO_DATA_Offset = 0x0;
static volatile long pir[1] = {0};
void PIR(void);
int label_pir, state_pir;
/*打开函数,当打开驱动设备节点时,执行此函数,相当于初始化设备文件*/
static int pir_open(struct inode *inode,struct file *filp)
{
gpio_add_minor_pir = (unsigned int)ioremap(GPIO_BASE_PIR, 32);
//gpio_add_minor_led = (unsigned int)ioremap(GPIO_BASE_LED, 32);
return 0;
}
/* write 函数实现, 对应到 Linux 系统调用函数的 write 函数 */
static ssize_t pir_write(struct file *file_p, const char __user *buf, size_t len, loff_t *loff_t_p)
{
return 0;
}
/* release 函数实现, 对应到 Linux 系统调用函数的 close 函数 */
static int pir_release(struct inode *inode_p, struct file *file_p)
{
iounmap((unsigned int *)gpio_add_minor_pir);
//iounmap((unsigned int *)gpio_add_minor_led);
return 0;
}
/* 控 制 函 数 , 相 当 于 给 ult 发 送 控 制 命 令*/
static int pir_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
/*
if(arg == 0)
{
int state = 0;
if(ioread32(gpio_add_minor_pir))
{
mdelay(2);
if(ioread32(gpio_add_minor_pir))
state =1;
}
if(state)
{
iowrite32(4, gpio_add_minor_led);
mdelay(1000);
iowrite32(0, gpio_add_minor_led);
}
}
else
iowrite32(2, gpio_add_minor_led);
*/
return 0;
}
/* 读函数*/
static int pir_read(struct file *filp, char __user *buff, size_t count, loff_t *offp)
{
pir[0] = 0;
PIR();
pir[0] = state_pir;
printk(KERN_DEBUG"state_pir: %d\n", state_pir);
unsigned long err;
err = copy_to_user(buff, (const void *)pir, min(sizeof(pir), count));
return err ? -EFAULT : min(sizeof(pir), count);
}
/*struct file_operations 结构体 , 指 向 对 应 的 驱 动 操 作 函 数*/
struct file_operations pir_fops=
{
.owner = THIS_MODULE,
.open = pir_open,
.unlocked_ioctl = pir_ioctl,
.read = pir_read,
.write = pir_write,
.release = pir_release,
};
/*注册模块*/
static struct miscdevice misc =
{
.minor = MISC_DYNAMIC_MINOR,
.name = DEVICE_NAME,
.fops = &pir_fops,
};
/*led 驱 动 加 载函数*/
static int __init pir_init(void)
{
int ret;
ret = misc_register(&misc);//注册设备, 混合设备驱动类,此时不需要手动分配主从设备号
printk (DEVICE_NAME"\tinitialized\n");
return ret;
}
/*led 驱 动 卸 载 函 数*/
static void __exit pir_exit(void)
{
misc_deregister(&misc);//卸载设备
}
void PIR(void)
{
//label_pir = 0;
state_pir = 0;
if(ioread32(gpio_add_minor_pir))
{
mdelay(2);
if(ioread32(gpio_add_minor_pir))
state_pir = 1;
}
}
module_init(pir_init);
module_exit(pir_exit);
MODULE_LICENSE("GPL");
MODULE_AUTHOR("ccd");

浙公网安备 33010602011771号