字符设备驱动2:易错点【注册 、 注销】
概要:
- cdev_add时分配设备号不足的错误示范
- unregister_chrdev_region没有完全注销设备
相关错误现象:
error, can't open /dev/led1
insmod: cannot insert '/module/myleds_new.ko': File exists (-1): File exists
1.cdev_add时分配设备号不足的错误示范
正确代码及现象:
1 static int __init s3c24xx_leds_init() 2 { 3 int ret ; 4 int minor = 0 ; 5 dev_t devno = MKDEV(leds_major , 0); 6 /*申请设备号,当xxx_major不为0时,表示静态指定;当为0时,表示动态申请*/ 7 if(leds_major){ 8 ret = register_chrdev_region(devno , LEDS_DEV_COUNT , LEDS_DEV_NAME); 9 }else{ 10 ret = alloc_chrdev_region(devno, LEDS_BASE_MINOR, LEDS_DEV_COUNT, LEDS_DEV_NAME); 11 leds_major = MAJOR(devno); 12 } 13 if(ret<0){ 14 return ret ; 15 } 16 17 //初始化并添加cdev结构体 18 cdev_init(&leds_cdev , &s3c24xx_leds_fops ); 19 leds_cdev.owner = THIS_MODULE ; 20 leds_cdev.ops = &s3c24xx_leds_fops; 21 ret = cdev_add(&leds_cdev , devno , LEDS_DEV_COUNT); 22 printk("cdev_add(&leds_cdev , devno , 4);\n"); 23 //这里因为下面要建立四个子设备,因此必须至少 4个(LEDS_DEV_COUNT)。否则,使用该设备是,子设备0后面的设备是无法使用的 24 //现象见下面的:“cdev_add时分配设备号不足的错误示范”。 25 26 if(ret){ 27 printk(LEDS_DEV_NAME"Error %d adding leds_cdev",ret); 28 } 29 30 //oo00 :begin : 分配了四个子设备号 minor == 0 1 2 3 31 //class_create动态创建设备的逻辑类,并完成部分字段的初始化,然后将其添加到内核中。创建的逻辑类位于/sys/class/。 32 leds_class = class_create(THIS_MODULE, "leds"); 33 if (IS_ERR(leds_class)) 34 return PTR_ERR(leds_class); 35 36 leds_class_devs[0] = class_device_create(leds_class, NULL, MKDEV(leds_major, 0), NULL, "leds"); 37 38 for (minor = 1; minor < 4; minor++){ 39 leds_class_devs[minor] = class_device_create(leds_class, NULL, MKDEV(leds_major, minor), NULL, "led%d", minor); 40 if (unlikely(IS_ERR(leds_class_devs[minor]))) 41 return PTR_ERR(leds_class_devs[minor]); 42 } 43 //oo00 :end 44 45 //prow: device_create ? or class_device_create? 46 47 printk(LEDS_DEV_NAME" initialized\n"); 48 49 return 0; 50 } 51 52 现象: 53 # insmod myleds_new.ko 54 cdev_add(&leds_cdev , devno , 4); 55 leds initialized 56 # ./ledtest /dev/leds on 57 info new: in s3c24xx_leds_ioctl! 58 # ./ledtest /dev/led1 off 59 info new: in s3c24xx_leds_ioctl!
错误代码及现象:
ret = cdev_add(&leds_cdev , devno , 1); printk("cdev_add(&leds_cdev , devno , 1);\n"); 现象: insmod正常,cat /proc/devices 能看见 leds 231;在app里面使用子设备号为0的设备ok,使用0以上的打不开。 # insmod myleds_new.ko cdev_add(&leds_cdev , devno , 1);//printk , 分配数量不够 leds initialized //printk # ./ledtest /dev/leds on info new: in s3c24xx_leds_ioctl! # ./ledtest /dev/led1 off error, can't open /dev/led1
2.unregister_chrdev_region没有完全注销设备
void unregister_chrdev_region(dev_t from, unsigned count); //count: the number of device numbers to unregister
正确代码及现象:
static void __exit s3c24xx_leds_exit() { dev_t devno = MKDEV(leds_major , 0); int minor; for( minor = 0;minor<4;minor++){ class_device_unregister(leds_class_devs[minor]); } class_destroy(leds_class); cdev_del(&leds_cdev);//删除结构体 unregister_chrdev_region(devno, LEDS_DEV_COUNT);//注销设备区域,正确的,将4个子设备域都注销了 } //执行rmmod之后,cat /proc/devices 没有leds 231
错误代码及现象:
unregister_chrdev_region(devno, 1);//注销设备区域, 4个子设备域没有完全注销 //执行rmmod之后,cat /proc/devices 仍有leds 231,并导致下次insmod失败。并且此时leds设备实体已经被注销了。