[关闭]
@zifehng 2017-06-28T07:02:53.000000Z 字数 3306 阅读 2278

device_create()、device_register()、deivce_add()区别

kernel device_create device_register device_add


本文基于linux 3.10.40,其他版本仅供参考

在字符设备驱动开发的入门教程中,最常见的就是用device_create()函数来创建设备节点了,但是在之后阅读内核源码的过程中却很少见device_create()的踪影了,取而代之的是device_register()与device_add(),将device_create()函数展开不难发现:其实device_create()只是device_register()的封装,而device_register()则是device_add()的封装。

  1. struct device *device_create(struct class *class, struct device *parent,
  2. dev_t devt, void *drvdata, const char *fmt, ...)
  3. {
  4. ......
  5. dev = device_create_vargs(class, parent, devt, drvdata, fmt, vargs);
  6. ......
  7. return dev;
  8. }
  1. struct device *device_create_vargs(struct class *class, struct device *parent,
  2. dev_t devt, void *drvdata, const char *fmt,
  3. va_list args)
  4. {
  5. ......
  6. dev->devt = devt;
  7. dev->class = class;
  8. dev->parent = parent;
  9. dev->release = device_create_release;
  10. dev_set_drvdata(dev, drvdata);
  11. ......
  12. retval = device_register(dev);
  13. ......
  14. }
  1. int device_register(struct device *dev)
  2. {
  3. device_initialize(dev);
  4. return device_add(dev);
  5. }

device_add()会在/sys目录对应设备目录下创建uevent属性节点,应用层的udev会根据uevent来创建/dev目录下的设备节点,这里关于udev的部分不再赘述,我们继续分析device_create()、device_register()、device_add()三个函数在实际运用中的区别。

以一个简单的led设备字符设备驱动为例,下面分别用device_create()、device_register()、device_add()三个函数来创建设备节点“/dev/led”:

1. device_create()

  1. static class *led_class;
  2. static int __init led_init(void)
  3. {
  4. int ret;
  5. dev_t devno;
  6. struct cdev *cdev;
  7. struct dev *dev;
  8. /* 注册设备号 */
  9. ret = alloc_chrdev_region(&devno, 0, 1, "led");
  10. if (ret < 0)
  11. return ret;
  12. /* 分配、初始化、注册cdev*/
  13. cdev = cdev_alloc();
  14. if (IS_ERR(cdev)) {
  15. ret = PTR_ERR(cdev);
  16. goto out_unregister_devno;
  17. }
  18. cdev_init(&cdev, &led_fops);
  19. cdev.owner = THIS_MODULE;
  20. ret = cdev_add(&cdev, devno, 1);
  21. if (ret)
  22. goto out_free_cdev;
  23. /* 创建设备类 */
  24. led_class = class_create(THIS_MODULE, "led_class");
  25. if (IS_ERR(led_class)) {
  26. ret = PTR_ERR(led_class);
  27. goto out_unregister_cdev;
  28. }
  29. /* 创建设备节点 */
  30. dev = device_create(led_class, NULL, devno, NULL, "led");
  31. if (IS_ERR(dev)) {
  32. ret = PTR_ERR(dev);
  33. goto out_del_class;
  34. }
  35. return 0;
  36. out_del_class:
  37. class_destroy(c78x_class);
  38. out_unregister_cdev:
  39. cdev_del(cdev);
  40. out_free_cdev:
  41. kfree(cdev);
  42. out_unregister_devno:
  43. unregister_chrdev_region(devno, 1);
  44. return ret;
  45. }
  46. module_init(led_init);

2. device_register()

  1. static class *led_class;
  2. static int __init led_init(void)
  3. {
  4. ......
  5. /* 注册设备号 */
  6. ......
  7. /* 分配、初始化、注册cdev*/
  8. ......
  9. /* 创建设备类 */
  10. ......
  11. /* 创建设备节点 */
  12. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  13. if (!dev) {
  14. ret = -ENOMEM;
  15. goto out_del_class;
  16. }
  17. dev->class = led_class; // 关联设备类
  18. dev->parent = NULL;
  19. dev->devt = devno; // 关联设备号
  20. dev_set_drvdata(dev, NULL);
  21. dev_set_name(dev, "led"); // 设置节点名字
  22. dev->release = device_create_release;
  23. ret = device_register(dev);
  24. if (ret)
  25. goto out_put_dev;
  26. return 0;
  27. out_put_dev:
  28. put_device(dev);
  29. kree(dev);
  30. out_del_class:
  31. class_destroy(c78x_class);
  32. out_unregister_cdev:
  33. cdev_del(cdev);
  34. out_free_cdev:
  35. kfree(cdev);
  36. out_unregister_devno:
  37. unregister_chrdev_region(devno, 1);
  38. return ret;
  39. }
  40. module_init(led_init);

3. device_add()

  1. static class *led_class;
  2. static int __init led_init(void)
  3. {
  4. ......
  5. /* 注册设备号 */
  6. ......
  7. /* 分配、初始化、注册cdev*/
  8. ......
  9. /* 创建设备类 */
  10. ......
  11. /* 创建设备节点 */
  12. dev = kzalloc(sizeof(*dev), GFP_KERNEL);
  13. if (!dev) {
  14. ret = -ENOMEM;
  15. goto out_del_class;
  16. }
  17. dev->class = led_class; // 关联设备类
  18. dev->parent = NULL;
  19. dev->devt = devno; // 关联设备号
  20. dev_set_drvdata(dev, NULL);
  21. dev_set_name(dev, "led"); // 设置节点名字
  22. dev->release = device_create_release;
  23. device_initialize(dev);
  24. ret = device_add(dev);
  25. if (ret)
  26. goto out_put_dev;
  27. return 0;
  28. out_put_dev:
  29. put_device(dev);
  30. kree(dev);
  31. out_del_class:
  32. class_destroy(c78x_class);
  33. out_unregister_cdev:
  34. cdev_del(cdev);
  35. out_free_cdev:
  36. kfree(cdev);
  37. out_unregister_devno:
  38. unregister_chrdev_region(devno, 1);
  39. return ret;
  40. }
  41. module_init(led_init);
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注