×
单片机 > 单片机程序设计 > 详情

2416开发记录九:实现设备节点的自动创建

发布时间:2020-08-26 发布时间:
|

我们在刚开始写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中:


/*

      * device classes

      */

    struct class {

      const char        *name;

      struct module     *owner;


  nbsp;struct kset         subsys;

      struct list_head         devices;

      struct list_head         interfaces;

      struct kset              class_dirs;

      struct semaphore sem;    /* locks children, devices, interfaces */

      struct class_attribute   *class_attrs;

      struct device_attribute      *dev_attrs;


  int (*dev_uevent)(struct device *dev, struct kobj_uevent_env *env);


  void (*class_release)(struct class *class);

      void (*dev_release)(struct device *dev);


  int (*suspend)(struct device *dev, pm_message_t state);

      int (*resume)(struct device *dev);


};


class_create(…)在/drivers/base/class.c中实现:

     /**

    * class_create - create a struct class structure

    * @owner: pointer to the module that is to "own" this struct class

    * @name: pointer to a string for the name of this class.

    *

    * This is used to create a struct class pointer that can then be used

    * in calls to device_create().

    *

    * Note, the pointer created here is to be destroyed when finished by

    * making a call to class_destroy().

    */

   struct class *class_create(struct module *owner, const char *name)

   {

      struct class *cls;

      int retval;

      cls = kzalloc(sizeof(*cls), GFP_KERNEL);

      if (!cls) {

           retval = -ENOMEM;

           goto error;

      }


  cls->name = name;

      cls->owner = owner;

      cls->class_release = class_create_release;


  retval = class_register(cls);

      if (retval)

           goto error;


  return cls;


error:

      kfree(cls);

      return ERR_PTR(retval);

    }


第一个参数指定类的所有者是哪个模块,第二个参数指定类名。

在class.c中,还定义了class_destroy(…)函数,用于在模块卸载时删除类。


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


  /**

     * device_create - creates a device and registers it with sysfs

     * @class: pointer to the struct class that this device should be registered to

     * @parent: pointer to the parent struct device of this new device, if any

     * @devt: the dev_t for the char device to be added

     * @fmt: string for the device's name

     *

     * This function can be used by char device classes. A struct device

     * will be created in sysfs, registered to the specified class.

     *

     * A "dev" file will be created, showing the dev_t for the device, if

     * the dev_t is not 0,0.

     * If a pointer to a parent struct device is passed in, the newly created

     * struct device will be a child of that device in sysfs.

     * The pointer to the struct device will be returned from the call.

     * Any further sysfs files that might be required can be created using this

     * pointer.

     *

     * Note: the struct class passed to this function must have previously

     * been created with a call to class_create().

     */

    struct device *device_create(struct class *class, struct device *parent,

                        dev_t devt, const char *fmt, ...)

    {

         va_list vargs;

         struct device *dev;


     va_start(vargs, fmt);

         dev = device_create_vargs(class, parent, devt, NULL, fmt, vargs);

         va_end(vargs);

         return dev;

    }


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


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


 #include

    #include

    #include

    #include

    #include

    #include


MODULE_LICENSE ("GPL");


int hello_major = 555;

    int hello_minor = 0;

    int number_of_devices = 1;


struct cdev cdev;

    dev_t dev = 0;


struct file_operations hello_fops = {

      .owner = THIS_MODULE

    };


static void char_reg_setup_cdev (void)

    {

       int error, devno = MKDEV (hello_major, hello_minor);

       cdev_init (&cdev, &hello_fops);

       cdev.owner = THIS_MODULE;

       cdev.ops = &hello_fops;

       error = cdev_add (&cdev, devno , 1);

       if (error)

           printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);


}


struct class *my_class;


static int __init hello_2_init (void)

    {

       int result;

       dev = MKDEV (hello_major, hello_minor);

       result = register_chrdev_region (dev, number_of_devices, "hello");

       if (result<0) {

           printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);

           return result;

     }


 char_reg_setup_cdev ();


 /* create your own class under /sysfs */

     my_class = class_create(THIS_MODULE, "my_class");

     if(IS_ERR(my_class))

     {

          printk("Err: failed in creating class./n");

          return -1;

      }


  /* register your own device in sysfs, and this will cause udev to create corresponding device node */

      device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );


  printk (KERN_INFO "Registered character driver/n");

      return 0;

    }


static void __exit hello_2_exit (void)

    {

       dev_t devno = MKDEV (hello_major, hello_minor);


       cdev_del (&cdev);


   device_destroy(my_class, MKDEV(adc_major, 0));         //delete device node under /dev

       class_destroy(my_class);                               //delete class created by us


   unregister_chrdev_region (devno, number_of_devices);


   printk (KERN_INFO "char driver cleaned up/n");

    }


module_init (hello_2_init);

    module_exit (hello_2_exit);


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


例子2


drivers/i2c/i2c-dev.c


/*

 * module load/unload record keeping

 */


static int __init i2c_dev_init(void)

{

 int res;


 printk(KERN_INFO "i2c /dev entries driver/n");


 res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);

 if (res)

  goto out;


 i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");

 if (IS_ERR(i2c_dev_class)) {

  res = PTR_ERR(i2c_dev_class);

  goto out_unreg_chrdev;

 }


 res = i2c_add_driver(&i2cdev_driver);

 if (res)

  goto out_unreg_class;


 return 0;


out_unreg_class:

 class_destroy(i2c_dev_class);

out_unreg_chrdev:

 unregister_chrdev(I2C_MAJOR, "i2c");

out:

 printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__);

 return res;

}


在 i2c_dev_init创建类i2c_dev_class


i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");




static int i2cdev_attach_adapter(struct i2c_adapter *adap)

{

 struct i2c_dev *i2c_dev;

 int res;


 i2c_dev = get_free_i2c_dev(adap);

 if (IS_ERR(i2c_dev))

  return PTR_ERR(i2c_dev);


 /* register this i2c device with the driver core */

 i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,

         MKDEV(I2C_MAJOR, adap->nr), NULL,

         "i2c-%d", adap->nr);

 if (IS_ERR(i2c_dev->dev)) {

  res = PTR_ERR(i2c_dev->dev);

  goto error;

 }

 res = device_create_file(i2c_dev->dev, &dev_attr_name);

 if (res)

  goto error_destroy;


 pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",

   adap->name, adap->nr);

 return 0;

error_destroy:

 device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));

error:

 return_i2c_dev(i2c_dev);

 return res;

}



在i2cdev_attach_adapter调用device_create(i2c_dev_class, &adap->dev,

         MKDEV(I2C_MAJOR, adap->nr), NULL,

         "i2c-%d", adap->nr);


这样在dev目录就产生i2c-0 或i2c-1节点


关键字:2416  设备节点  自动创建 

『本文转载自网络,版权归原作者所有,如有侵权请联系删除』

热门文章 更多
单片机制作超级流水灯