一,混杂设备的定义
在Linux中,存在这么一类字符设备,他们拥有相同的主设备号为10,但次设备号不同,这类设备就称为混杂设备(miscdevice).所有的混杂设备形成一个链表,对设备访问时内核根据次设备号查找到相应的混杂设备。
混杂设备定义头文件<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 char *nodename; mode_t mode; };三,混杂设备的注册与注销
注册:int misc_register(struct miscdevice *misc)
释放:int misc_deregister(struct miscdevice *misc)
四,驱动调用的实质
通过 设备文件找到与之对应设备号的设备,再通过设备初始化时绑定的操作函数对硬件进行控制的。
五,实例分析
下面这个例子是运行在tiny6410上的按键驱动程序。
//混杂设备驱动模型 #include <linux/module.h> #include <linux/kernel.h> #include <linux/fs.h> #include <linux/init.h> #include <linux/delay.h> #include <linux/poll.h> #include <linux/irq.h> #include <asm/irq.h> #include <asm/io.h> #include <linux/interrupt.h> #include <asm/uaccess.h> #include <mach/hardware.h> #include <linux/platform_device.h> #include <linux/cdev.h> #include <linux/miscdevice.h> #include <mach/map.h> #include <mach/regs-clock.h> #include <mach/regs-gpio.h> #include <plat/gpio-cfg.h> #include <mach/gpio-bank-n.h> #include <mach/gpio-bank-l.h> #define DEVICE_NAME "keys" //定义设备名称 #define MISC_DYNAMIC_MINOR 200 //主设备号 #define GPNCON 0x7F008830 //中断函数 static irqreturn_t buttons_interrupt(int irq, void *dev_id) { //1检测设备中是否发生了中断 //2清楚中断产生的标准 //3相应的硬件操作——————在这里就是打印出那个按键被按下 printk(KERN_EMERG "key dowm\n"); //打印 return 0; } //初始化函数 static int s3c64xx_buttons_open(struct inode *inode, struct file *file) { //一般选择open()函数中完成按键的初始化 //但在这里单独定义一个函数进行初始化 return 0; } //按键初始化函数 static int int_key() { //初始化按键对应的GPIO引脚为中断功能 //K1 对应着 GPN0 对应的中断时EINT0 unsigned int *gpio_config; unsigned short data; gpio_config=ioremap(GPNCON,4); //物理地址转换为虚拟地址 data=readw(gpio_config); //readw()读取寄存器原来的值 data &= ~0b11; data |= 0b10; //把GPN0设置为10 writew(data,gpio_config); //将data数值写入寄存器 printk(KERN_EMERG "function init\n"); return 0; } //操作函数集 static struct file_operations dev_fops = { .owner = THIS_MODULE, .open = s3c64xx_buttons_open, }; static struct miscdevice misc = { //在Linux中使用struct miscdevice这个结构来描述混杂设备 .minor = MISC_DYNAMIC_MINOR, //次设备号 .name = DEVICE_NAME, //设备名,使用宏定义来定义设备名 .fops = &dev_fops, //file_operation操作函数集 }; static int __init dev_init() //注册混杂设备 { int ret; ret = misc_register(&misc); request_irq(IRQ_EINT(0),buttons_interrupt,IRQF_TRIGGER_FALLING,"key",0); //注册中断函数 //注册中断函数有五个参数,中断号(与硬件相关),中断处理函数,与中断有关的各种选项 int_key(); //初始化按键函数 //设备名,共享中断时使用 //设置为下降沿触发中断 IRQF_TRIGGER_FALLING printk (DEVICE_NAME"\tinitialized\n"); return ret; } static void __exit dev_exit() //注销混杂设备 { misc_deregister(&misc); } module_init(dev_init); module_exit(dev_exit); MODULE_LICENSE("GPL"); //表明遵循GPL协议 MODULE_AUTHOR("FriendlyARM Inc.");