驱动模块需要完成的功能:
- 注册设备
- 添加文件操作函数与ops结构绑定
注册设备的具体过程是先向系统申请一个设备号,可以注册一个特定的设备号也可以由系统动态分配。一般使用动态分配,但是添加模块的过程只是向/proc/devices文件中添加了设备的信息,最后还得从从devices文件中cat 出设备的设备号,然后在手动在/dev中添加设备,mknod /dev/key c N 0。访问设备就是通过/dev 的文件进行访问的,访问过程通过设备号找到设备关联的驱动程序,设备号是架起设备和驱动之间的桥梁。也可以在模块内部直接完成/dev 里设备添加的过程 ,调用函数device_create(..)。
有了设备号还不行,还得创建一个设备,可以用cdev结构也可以自己定义一个设备结构然后把cdev结构嵌入进自己的设备结构。有了设备和设备号就得用这个设备号初始化这个设备,然后再把这个设备添加到设备链表。
初始化的过程就是对设备结构的成员变量进行赋值。(网上的代码,出处http://www.cnblogs.com/nick123/archive/2010/03/26/1696966.html#commentform)
1 int err; 2 cdev_init(buttons_cdev_p,&tq2440_buttons_fops); 3 buttons_cdev_p->owner = THIS_MODULE; 4 buttons_cdev_p->ops = &tq2440_buttons_fops; 5 err = cdev_add(buttons_cdev_p,dev_num,1); 6 if(IS_ERR(&err)) 7 printk(KERN_NOTICE "Error %d adding buttons",err);
下面是整个驱动模块的初试化过程。
1 static int __init tq2440_buttons_init(void) 2 { 3 int ret; 4 5 6 if(BUTTON_MAJOR) //手动分配设备号 7 { 8 dev_num=MKDEV(BUTTON_MAJOR, BUTTON_MINOR); ret=register_chrdev_region(dev_num,DEV_COUNT,DEVICE_NAME); 9 } 10 else { //动态分配设备号 11 ret = alloc_chrdev_region(&dev_num,BUTTON_MINOR,DEV_COUNT,DEVICE_NAME); 12 } 13 if(ret<0) { 14 printk(DEVICE_NAME " can't register major number \n"); 15 return ret; 16 } 17 /*动态申请cdev结构体的内存*/ 18 buttons_cdev_p = kmalloc(sizeof(struct cdev),GFP_KERNEL); 19 if(!buttons_cdev_p) //申请失败 20 { 21 ret = -ENOMEM; 22 goto fial_malloc; 23 } 24 memset(buttons_cdev_p,0,sizeof(struct cdev)); 25 int err; 26 cdev_init(buttons_cdev_p,&tq2440_buttons_fops); 27 buttons_cdev_p->owner = THIS_MODULE; 28 buttons_cdev_p->ops = &tq2440_buttons_fops; 29 err = cdev_add(buttons_cdev_p,dev_num,1); 30 if(IS_ERR(&err)) 31 printk(KERN_NOTICE "Error %d adding buttons",err); 32 //注册一个类,使mdev可以在"/dev/"目录下面 33 //建立设备节点 34 button_class = class_create(THIS_MODULE,DEVICE_NAME); 35 if(IS_ERR(button_class)) 36 { 37 printk("Error:Failed to creat button_class \n"); 38 return -1; 39 } 40 //创建一个设备节点,节点名为DEVICE_NAME 41 42 device_create(button_class,NULL,dev_num,NULL,DEVICE_NAME); 43 printk(DEVICE_NAME " initialized \n"); 44 return 0; 45 fial_malloc:unregister_chrdev_region(dev_num, 1); 46 }
驱动注销的过程:
由于注册的过程显示分配了设备号,定义了设备结构体,并且注册了设备。所以注销的过程相应的得,注销设备,释放内存结构体,释放设备号。
1 static void __exit tq2440_buttons_exit(void) 2 { 3 cdev_del(buttons_cdev_p);//注销cdev 4 kfree(buttons_cdev_p);//释放设备结构体内存 5 unregister_chrdev_region(dev_num,DEV_COUNT);//释放设备号 6 7 }
以上就是一个驱动模块的基本框架。主要的编码工作是编写文件操作函数,或者如果用到中断的话还有中断的注册,中断函数。
浙公网安备 33010602011771号