字符设备驱动2:易错点【注册 、 注销】

概要:

  1. cdev_add时分配设备号不足的错误示范
  2. 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);
");
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
");
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);
");

现象:
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设备实体已经被注销了。
原文地址:https://www.cnblogs.com/mylinux/p/4010881.html