在驱动模块初始化函数中实现设备节点的自动创建

我们在刚开始写Linux设备驱动程序的时候,很多时候都是利用mknod命令手动创建设备节点,实际上Linux内核为我们提供了一组函数,可以用来在模块加载的时候自动在/dev目录下创建相应设备节点,并在卸载模块时删除该节点,当然前提条件是用户空间移植了udev。

内核中定义了struct class结构体,顾名思义,一个struct class结构体类型变量对应一个类,内核同时提供了class_create(…)函数,可以用它来创建一个类,这个类存放于sysfs下面,一旦创建好了这个类,再调用device_create(…)函数来在/dev目录下创建相应的设备节点。这样,加载模块的时候,用户空间中的udev会自动响应device_create(…)函数,去/sysfs下寻找对应的类从而创建设备节点。

注意,在2.6较早的内核版本中,device_create(…)函数名称不同,是class_device_create(…),所以在新的内核中编译以前的模块程序有时会报错,就是因为函数名称不同,而且里面的参数设置也有一些变化。

struct class和device_create(…) 以及device_create(…)都定义在/include/linux/device.h中,使用的时候一定要包含这个头文件,否则编译器会报错。

在2.6.26.6内核版本中,struct class定义在头文件include/linux/device.h中:

 

  1. /* 
  2.       * device classes 
  3.       */  
  4.     struct class {  
  5.       const char        *name;  
  6.       struct module     *owner;  
  7.   
  8.   nbsp;struct kset         subsys;  
  9.       struct list_head         devices;  
  10.       struct list_head         interfaces;  
  11.       struct kset              class_dirs;  
  12.       struct semaphore sem;    /* locks children, devices, interfaces */  
  13.       struct class_attribute   *class_attrs;  
  14.       struct device_attribute      *dev_attrs;  
  15.   
  16.   int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);  
  17.   
  18.   void (*class_release)(struct class *class);  
  19.       void (*dev_release)(struct device *dev);  
  20.   
  21.   int (*suspend)(struct device *dev, pm_message_t state);  
  22.       int (*resume)(struct device *dev);  
  23.   
  24.   
  25. };  
  26.   
  27. class_create(…)在/drivers/base/class.c中实现:   
  28.      /** 
  29.     * class_create - create a struct class structure 
  30.     * @owner: pointer to the module that is to "own" this struct class 
  31.     * @name: pointer to a string for the name of this class. 
  32.     * 
  33.     * This is used to create a struct class pointer that can then be used 
  34.     * in calls to device_create(). 
  35.     * 
  36.     * Note, the pointer created here is to be destroyed when finished by 
  37.     * making a call to class_destroy(). 
  38.     */  
  39.    struct class *class_create(struct module *owner, const char *name)  
  40.    {  
  41.       struct class *cls;  
  42.       int retval;  
  43.       cls = kzalloc(sizeof(*cls), GFP_KERNEL);  
  44.       if (!cls) {  
  45.            retval = -ENOMEM;  
  46.            goto error;  
  47.       }  
  48.   
  49.   cls->name = name;  
  50.       cls->owner = owner;  
  51.       cls->class_release = class_create_release;  
  52.   
  53.   retval = class_register(cls);  
  54.       if (retval)  
  55.            goto error;  
  56.   
  57.   return cls;  
  58.   
  59. error:  
  60.       kfree(cls);  
  61.       return ERR_PTR(retval);  
  62.     }  

 

    第一个参数指定类的所有者是哪个模块,第二个参数指定类名。 
    在class.c中,还定义了class_destroy(…)函数,用于在模块卸载时删除类。

device_create(…)函数在/drivers/base/core.c中实现:

  1. /** 
  2.    * device_create - creates a device and registers it with sysfs 
  3.    * @class: pointer to the struct class that this device should be registered to 
  4.    * @parent: pointer to the parent struct device of this new device, if any 
  5.    * @devt: the dev_t for the char device to be added 
  6.    * @fmt: string for the device's name 
  7.    * 
  8.    * This function can be used by char device classes. A struct device 
  9.    * will be created in sysfs, registered to the specified class. 
  10.    * 
  11.    * A "dev" file will be created, showing the dev_t for the device, if 
  12.    * the dev_t is not 0,0. 
  13.    * If a pointer to a parent struct device is passed in, the newly created 
  14.    * struct device will be a child of that device in sysfs. 
  15.    * The pointer to the struct device will be returned from the call. 
  16.    * Any further sysfs files that might be required can be created using this 
  17.    * pointer. 
  18.    * 
  19.    * Note: the struct class passed to this function must have previously 
  20.    * been created with a call to class_create(). 
  21.    */  
  22.   struct device *device_create(struct class *classstruct device *parent,  
  23.                       dev_t devt, const char *fmt, ...)  
  24.   {  
  25.        va_list vargs;  
  26.        struct device *dev;  
  27.   
  28.   
  29.    va_start(vargs, fmt);  
  30.        dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs);  
  31.        va_end(vargs);  
  32.        return dev;  
  33.   }  

 

    第一个参数指定所要创建的设备所从属的类,第二个参数是这个设备的父设备,如果没有就指定为NULL,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号。

下面以一个简单字符设备驱动来展示如何使用这几个函数 

  1.   #include <linux/module.h>  
  2.     #include <linux/kernel.h>  
  3.     #include <linux/init.h>  
  4.     #include <linux/fs.h>  
  5.     #include <linux/cdev.h>  
  6.     #include <linux/device.h>  
  7.   
  8.   
  9. MODULE_LICENSE ("GPL");  
  10.   
  11. int hello_major = 555;  
  12.     int hello_minor = 0;  
  13.     int number_of_devices = 1;  
  14.   
  15. struct cdev cdev;  
  16.     dev_t dev = 0;  
  17.   
  18. struct file_operations hello_fops = {  
  19.       .owner = THIS_MODULE  
  20.     };  
  21.   
  22. static void char_reg_setup_cdev (void)  
  23.     {  
  24.        int error, devno = MKDEV (hello_major, hello_minor);  
  25.        cdev_init (&cdev, &hello_fops);  
  26.        cdev.owner = THIS_MODULE;  
  27.        cdev.ops = &hello_fops;  
  28.        error = cdev_add (&cdev, devno , 1);  
  29.        if (error)  
  30.            printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);  
  31.   
  32. }  
  33.   
  34. struct class *my_class;  
  35.   
  36. static int __init hello_2_init (void)  
  37.     {  
  38.        int result;  
  39.        dev = MKDEV (hello_major, hello_minor);  
  40.        result = register_chrdev_region (dev, number_of_devices, "hello");  
  41.        if (result<0) {  
  42.            printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);  
  43.            return result;  
  44.      }  
  45.   
  46.  char_reg_setup_cdev ();  
  47.   
  48.   
  49.  /* create your own class under /sysfs */  
  50.      my_class = class_create(THIS_MODULE, "my_class");  
  51.      if(IS_ERR(my_class))   
  52.      {  
  53.           printk("Err: failed in creating class./n");  
  54.           return -1;   
  55.       }   
  56.   
  57.   /* register your own device in sysfs, and this will cause udev to create corresponding device node */  
  58.       device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );  
  59.   
  60.   printk (KERN_INFO "Registered character driver/n");  
  61.       return 0;  
  62.     }  
  63.   
  64. static void __exit hello_2_exit (void)  
  65.     {  
  66.        dev_t devno = MKDEV (hello_major, hello_minor);  
  67.   
  68.        cdev_del (&cdev);  
  69.   
  70.    device_destroy(my_class, MKDEV(adc_major, 0));         //delete device node under /dev  
  71.        class_destroy(my_class);                               //delete class created by us  
  72.   
  73.    unregister_chrdev_region (devno, number_of_devices);  
  74.   
  75.    printk (KERN_INFO "char driver cleaned up/n");  
  76.     }  
  77.   
  78. module_init (hello_2_init);  
  79.     module_exit (hello_2_exit);  
   

 

这样,模块加载后,就能在/dev目录下找到hello0这个设备节点了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值