Chinaunix首页 | 论坛 | 博客
  • 博客访问: 531165
  • 博文数量: 81
  • 博客积分: 1438
  • 博客等级: 上尉
  • 技术积分: 866
  • 用 户 组: 普通用户
  • 注册时间: 2011-06-12 11:32
文章分类

全部博文(81)

文章存档

2014年(1)

2013年(1)

2012年(33)

2011年(46)

分类: 嵌入式

2011-09-27 14:00:44

我们在刚开始写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,第三个参数是设备号,第四个参数是设备名称,第五个参数是从设备号。

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

 

  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.     MODULE_LICENSE ("GPL");

  8.     int hello_major = 555;
  9.     int hello_minor = 0;
  10.     int number_of_devices = 1;

  11.     struct cdev cdev;
  12.     dev_t dev = 0;

  13.     struct file_operations hello_fops = {
  14.       .owner = THIS_MODULE
  15.     };

  16.     static void char_reg_setup_cdev (void)
  17.     {
  18.        int error, devno = MKDEV (hello_major, hello_minor);
  19.        cdev_init (&cdev, &hello_fops);
  20.        cdev.owner = THIS_MODULE;
  21.        cdev.ops = &hello_fops;
  22.        error = cdev_add (&cdev, devno , 1);
  23.        if (error)
  24.            printk (KERN_NOTICE "Error %d adding char_reg_setup_cdev", error);

  25.     }

  26.     struct class *my_class;

  27.     static int __init hello_2_init (void)
  28.     {
  29.        int result;
  30.        dev = MKDEV (hello_major, hello_minor);
  31.        result = register_chrdev_region (dev, number_of_devices, "hello");
  32.        if (result<0) {
  33.            printk (KERN_WARNING "hello: can't get major number %d/n", hello_major);
  34.            return result;
  35.      }

  36.      char_reg_setup_cdev ();

  37.  /* create your own class under /sysfs */
  38.      my_class = class_create(THIS_MODULE, "my_class");
  39.      if(IS_ERR(my_class))
  40.      {
  41.           printk("Err: failed in creating class./n");
  42.           return -1;
  43.       }

  44.   /* register your own device in sysfs, and this will cause udev to create corresponding device node */
  45.       device_create( my_class, NULL, MKDEV(hello_major, 0), "hello" "%d", 0 );

  46.       printk (KERN_INFO "Registered character driver/n");
  47.       return 0;
  48.     }

  49.     static void __exit hello_2_exit (void)
  50.     {
  51.        dev_t devno = MKDEV (hello_major, hello_minor);

  52.        cdev_del (&cdev);

  53.        device_destroy(my_class, MKDEV(adc_major, 0)); //delete device node under /dev
  54.        class_destroy(my_class); //delete class created by us

  55.        unregister_chrdev_region (devno, number_of_devices);

  56.        printk (KERN_INFO "char driver cleaned up/n");
  57.     }

  58.     module_init (hello_2_init);
  59.     module_exit (hello_2_exit);

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

例子2

 

  1. drivers/i2c/i2c-dev.c



  2. /*
  3.  * module load/unload record keeping
  4.  */

  5. static int __init i2c_dev_init(void)
  6. {
  7.  int res;

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

  9.  res = register_chrdev(I2C_MAJOR, "i2c", &i2cdev_fops);
  10.  if (res)
  11.   goto out;

  12.  i2c_dev_class = class_create(THIS_MODULE, "i2c-dev");
  13.  if (IS_ERR(i2c_dev_class)) {
  14.   res = PTR_ERR(i2c_dev_class);
  15.   goto out_unreg_chrdev;
  16.  }

  17.  res = i2c_add_driver(&i2cdev_driver);
  18.  if (res)
  19.   goto out_unreg_class;

  20.  return 0;

  21. out_unreg_class:
  22.  class_destroy(i2c_dev_class);
  23. out_unreg_chrdev:
  24.  unregister_chrdev(I2C_MAJOR, "i2c");
  25. out:
  26.  printk(KERN_ERR "%s: Driver Initialisation failed/n", __FILE__);
  27.  return res;
  28. }

  29. 在 i2c_dev_init创建类i2c_dev_class

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

  31. static int i2cdev_attach_adapter(struct i2c_adapter *adap)
  32. {
  33.  struct i2c_dev *i2c_dev;
  34.  int res;

  35.  i2c_dev = get_free_i2c_dev(adap);
  36.  if (IS_ERR(i2c_dev))
  37.   return PTR_ERR(i2c_dev);

  38.  /* register this i2c device with the driver core */
  39.  i2c_dev->dev = device_create(i2c_dev_class, &adap->dev,
  40.          MKDEV(I2C_MAJOR, adap->nr), NULL,
  41.          "i2c-%d", adap->nr);
  42.  if (IS_ERR(i2c_dev->dev)) {
  43.   res = PTR_ERR(i2c_dev->dev);
  44.   goto error;
  45.  }
  46.  res = device_create_file(i2c_dev->dev, &dev_attr_name);
  47.  if (res)
  48.   goto error_destroy;

  49.  pr_debug("i2c-dev: adapter [%s] registered as minor %d/n",
  50.    adap->name, adap->nr);
  51.  return 0;
  52. error_destroy:
  53.  device_destroy(i2c_dev_class, MKDEV(I2C_MAJOR, adap->nr));
  54. error:
  55.  return_i2c_dev(i2c_dev);
  56.  return res;
  57. }
在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节点
阅读(1052) | 评论(0) | 转发(2) |
给主人留下些什么吧!~~