关于platform_driver 是如何匹配 platform_device的和如何调用到platform_driver中的probe函数的研究

关于platform_driver 是如何匹配 platform_device的和如何调用到platform_driver中的probe函数的研究关于platform_driver是如何匹配platform_device的和如何调用到platform_driver中的probe函数的研究2012年02月24日10:16:24阅读数:7184       在linux中platform平台驱动又三大部分组成,第一是bus、第二是驱动、第三是设备。     第一总线也就是platform_bus,总线也是一种特殊的d…

关于platform_driver 是如何匹配 platform_device的和如何调用到platform_driver中的probe函数的研究

2012年02月24日 10:16:24

阅读数:7184

        在linux中platform平台驱动又三大部分组成,第一是bus、第二是驱动、第三是设备。

      第一总线也就是platform_bus,总线也是一种特殊的device,到底层下面还是要调用device_register来注册该总线设备,然后是用来注册总线的属性结构体 bus_type(platform_bus_type),至此platform平台的总线已经准备好。具体介绍可以看我另一篇博客。

      第二是设备,platform_device,它的注册流程是:platform_device_register(struct platform_device *pdev)->device_initialize(&pdev->dev)->platform_device_add(pdev)->pdev->dev.bus = &platform_bus_type->device_add(&pdev->dev)->把设备挂在虚拟的platform bus下。

       第三是驱动,现在总线、设备都准备好了,然后等着驱动来匹配设备进行驱动,具体的驱动匹配设备流程如下:

 1、

 
  1. int platform_driver_register(struct platform_driver *drv)

  2. {

  3. drv->driver.bus = &platform_bus_type;//驱动的总线类型指向platform_bus_type

  4. if (drv->probe)

  5. drv->driver.probe = platform_drv_probe;

  6. if (drv->remove)

  7. drv->driver.remove = platform_drv_remove;

  8. if (drv->shutdown)

  9. drv->driver.shutdown = platform_drv_shutdown;

  10. if (drv->suspend)

  11. drv->driver.suspend = platform_drv_suspend;

  12. if (drv->resume)

  13. drv->driver.resume = platform_drv_resume;

  14. return driver_register(&drv->driver);

  15. }

 

 2、

 
  1. int driver_register(struct device_driver *drv)

  2. {

  3. int ret;

  4. struct device_driver *other;

  5.  
  6. BUG_ON(!drv->bus->p);

  7. //检测总线的操作函数和驱动的操作函数是否同时存在,同时存在则提示使用总线提供的操作函数

  8. if ((drv->bus->probe && drv->probe) ||

  9. (drv->bus->remove && drv->remove) ||

  10. (drv->bus->shutdown && drv->shutdown))

  11. printk(KERN_WARNING "Driver '%s' needs updating - please use "

  12. "bus_type methods\n", drv->name);

  13. //查找这个驱动是否已经在总线上注册,并增加引用计数,若已经注册,则返回提示信息。

  14. other = driver_find(drv->name, drv->bus);

  15. if (other) {

  16. //如果已经被注册,则返回提示错误并且减少引用计数。

  17. put_driver(other);

  18. printk(KERN_ERR "Error: Driver '%s' is already registered, "

  19. "aborting...\n", drv->name);

  20. return -EEXIST;

  21. }

  22. //若还没有注册,则在总线上注册该驱动

  23. ret = bus_add_driver(drv);

  24. if (ret)

  25. return ret;

  26. ret = driver_add_groups(drv, drv->groups);

  27. if (ret)

  28. bus_remove_driver(drv);

  29. return ret;

  30. }

3、

 

 
  1. int bus_add_driver(struct device_driver *drv)

  2. {

  3. struct bus_type *bus;

  4. struct driver_private *priv;

  5. int error = 0;

  6. //用于增加该bus所属的顶层bus的kobject的引用计数,返回的是其所属的顶层bus的指针。

  7. bus = bus_get(drv->bus);

  8. if (!bus)

  9. return -EINVAL;

  10.  
  11. pr_debug("bus: '%s': add driver %s\n", bus->name, drv->name);

  12.  
  13. priv = kzalloc(sizeof(*priv), GFP_KERNEL);

  14. if (!priv) {

  15. error = -ENOMEM;

  16. goto out_put_bus;

  17. }

  18. klist_init(&priv->klist_devices, NULL, NULL);

  19. //将这两个结构体连接起来

  20. priv->driver = drv;

  21. drv->p = priv;

  22. //指向顶层的bus的p->drivers_kset

  23. //设置私有数据的父容器,在这一步中,设置了kset为platform下的drivers_kset结构,也就是drivers呢个目录

  24. priv->kobj.kset = bus->p->drivers_kset;

  25. //初始化kobj对象,设置容器操作集并建立相应的目录,这里由于没有提供parent,所以会使用父容器中的kobj为父对象

  26. error = kobject_init_and_add(&priv->kobj, &driver_ktype, NULL,

  27. "%s", drv->name);

  28. if (error)

  29. goto out_unregister;

  30. //检测所属总线的drivers_autoprobe属性是否为真

  31. //为真则进行与设备的匹配,到这里,就会与我们之前注册的test_device连接上了,

  32. //至于如何连接,进行了什么操作,将在别的文章中详细描述

  33. if (drv->bus->p->drivers_autoprobe) {

  34. error = driver_attach(drv);

  35. if (error)

  36. goto out_unregister;

  37. }

  38. //挂载到所属总线驱动链表上

  39. klist_add_tail(&priv->knode_bus, &bus->p->klist_drivers);

  40. module_add_driver(drv->owner, drv);

  41. //建立uevent属性文件

  42. error = driver_create_file(drv, &driver_attr_uevent);

  43. if (error) {

  44. printk(KERN_ERR "%s: uevent attr (%s) failed\n",

  45. __func__, drv->name);

  46. }

  47. //建立设备属性文件

  48. error = driver_add_attrs(bus, drv);

  49. if (error) {

  50. /* How the hell do we get out of this pickle? Give up */

  51. printk(KERN_ERR "%s: driver_add_attrs(%s) failed\n",

  52. __func__, drv->name);

  53. }

  54. error = add_bind_files(drv);

  55. if (error) {

  56. /* Ditto */

  57. printk(KERN_ERR "%s: add_bind_files(%s) failed\n",

  58. __func__, drv->name);

  59. }

  60.  
  61. kobject_uevent(&priv->kobj, KOBJ_ADD);

  62. return 0;

  63. out_unregister:

  64. kfree(drv->p);

  65. drv->p = NULL;

  66. kobject_put(&priv->kobj);

  67. out_put_bus:

  68. bus_put(bus);

  69. return error;

  70. }

 

 4、驱动的匹配关键是上面函数中的

 
  1. if (drv->bus->p->drivers_autoprobe) {//drivers_autoprobe在初始化的时候定义为1,系统则会调用下面的driver_attach函数进行驱动与设备的匹配

  2. error = driver_attach(drv);

  3. if (error)

  4. goto out_unregister;

  5. }

 

 
  1. int driver_attach(struct device_driver *drv)

  2. {

  3. return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

  4. }

 
  1. //bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);

  2. int bus_for_each_dev(struct bus_type *bus, struct device *start,

  3. void *data, int (*fn)(struct device *, void *))

  4. {/*

  5.  
  6. struct klist_iter {

  7. struct klist *i_klist;

  8. struct klist_node *i_cur;

  9. };

  10.  
  11. */

  12. struct klist_iter i;

  13. struct device *dev;

  14. int error = 0;

  15.  
  16. if (!bus)

  17. return -EINVAL;

  18. //如果第三个参数不为空就增加引用计数

  19. klist_iter_init_node(&bus->p->klist_devices, &i,

  20. (start ? &start->p->knode_bus : NULL));//一直是NULL

  21. //经过上面的宏之后,i实际上变成了i->i_klist=&bus->p->klist_devices,bus->p->klist_devices指向的是挂接在它上面的所有的设备的指针

  22. while ((dev = next_device(&i)) && !error)

  23. //fu函数传入的是device的指针和device_driver的指针,

  24. error = fn(dev, data);

  25. //如果klist_iter_init_node第三个参数不为空则减少引用计数

  26. klist_iter_exit(&i);

  27. return error;

  28. }

 

 //寻找到下一个设备的节点

 
  1. static struct device *next_device(struct klist_iter *i)

  2. {

  3. struct klist_node *n = klist_next(i);

  4. struct device *dev = NULL;

  5. struct device_private *dev_prv;

  6.  
  7. if (n) {

  8. dev_prv = to_device_private_bus(n);

  9. dev = dev_prv->device;

  10. }

  11. return dev;

  12. }

 

 函数error = fn(dev, data)的原型如下:

传进来的参数第一个参数为不断遍历到的设备节点的指针,第二个参数为固定的一个驱动所对应的struct device_driver *drv指针,这样就实现驱动和设备的匹配

 
  1. static int __driver_attach(struct device *dev, void *data)

  2. {

  3. struct device_driver *drv = data;

  4.  
  5. /*

  6. * Lock device and try to bind to it. We drop the error

  7. * here and always return 0, because we need to keep trying

  8. * to bind to devices and some drivers will return an error

  9. * simply if it didn't support the device.

  10. *

  11. * driver_probe_device() will spit a warning if there

  12. * is an error.

  13. */

  14. //当设备和驱动的名字不匹配的时候返回的是0,然后就会调用下面的return 0;

  15. if (!driver_match_device(drv, dev))

  16. return 0;

  17.  
  18. if (dev->parent) /* Needed for USB */

  19. down(&dev->parent->sem);

  20. down(&dev->sem);

  21. if (!dev->driver)

  22. driver_probe_device(drv, dev);//调用探测函数进行探测,并且调用platform_driver中的probe函数

  23. up(&dev->sem);

  24. if (dev->parent)

  25. up(&dev->parent->sem);

  26.  
  27. return 0;

  28. }

  29.  

在上面有两个比较关键的函数driver_match_device(dre,dev),函数原型如下:

 
  1. static inline int driver_match_device(struct device_driver *drv,

  2. struct device *dev)

  3. {

  4. return drv->bus->match ? drv->bus->match(dev, drv) : 1;//无论设备与驱动是否匹配成功都会返回1

  5. }

当驱动的指针不为空的时候,这个drv->bus所指向的的这个驱动所属的的总线的bus_type中的match函数,然后传进去的是该驱动的指针和设备的指针

 
  1. static int platform_match(struct device *dev, struct device_driver *drv)

  2. {

  3. struct platform_device *pdev = to_platform_device(dev);

  4. struct platform_driver *pdrv = to_platform_driver(drv);

  5.  
  6. /* match against the id table first */

  7. if (pdrv->id_table)//为空,不会被调用

  8. return platform_match_id(pdrv->id_table, pdev) != NULL;

  9.  
  10. /* fall-back to driver name match */

  11. return (strcmp(pdev->name, drv->name) == 0);

  12. }

最后调用驱动的probe函数进行设备的探测

driver_probe_device(drv, dev);//调用探测函数进行探测,并且调用platform_driver中的probe函数

 
  1. int driver_probe_device(struct device_driver *drv, struct device *dev)

  2. {

  3. int ret = 0;

  4. //再次检查设备有没有在总线上注册,当发现还没有注册的时候,返回一个错误

  5. if (!device_is_registered(dev))

  6. return -ENODEV;

  7.  
  8. pr_debug("bus: '%s': %s: matched device %s with driver %s\n",

  9. drv->bus->name, __func__, dev_name(dev), drv->name);

  10.  
  11. ret = really_probe(dev, drv);

  12.  
  13. return ret;

  14. }

 

 
  1. static int really_probe(struct device *dev, struct device_driver *drv)

  2. {

  3. int ret = 0;

  4.  
  5. atomic_inc(&probe_count);

  6. pr_debug("bus: '%s': %s: probing driver %s with device %s\n",

  7. drv->bus->name, __func__, drv->name, dev_name(dev));

  8. WARN_ON(!list_empty(&dev->devres_head));

  9. //找到了设备的驱动,并且将dev->driver指针指向自己的这个驱动

  10. dev->driver = drv;

  11. if (driver_sysfs_add(dev)) {//在sys目录下建立连接指向自己的在sys中的drivers

  12. printk(KERN_ERR "%s: driver_sysfs_add(%s) failed\n",

  13. __func__, dev_name(dev));

  14. goto probe_failed;

  15. }

  16. //在bus_type platform_bus_type中并没有设置probe函数,所以下面函数并不会被调用

  17. if (dev->bus->probe) {

  18. ret = dev->bus->probe(dev);

  19. if (ret)

  20. goto probe_failed;

  21. } else if (drv->probe) {//上面总线没有probe函数,所以直接调用驱动当中的probe函数

  22. ret = drv->probe(dev);

  23. if (ret)

  24. goto probe_failed;

  25. }

  26.  
  27. driver_bound(dev);

  28. ret = 1;

  29. pr_debug("bus: '%s': %s: bound device %s to driver %s\n",

  30. drv->bus->name, __func__, dev_name(dev), drv->name);

  31. goto done;

  32.  
  33. probe_failed:

  34. devres_release_all(dev);

  35. driver_sysfs_remove(dev);

  36. dev->driver = NULL;

  37.  
  38. if (ret != -ENODEV && ret != -ENXIO) {

  39. /* driver matched but the probe failed */

  40. printk(KERN_WARNING

  41. "%s: probe of %s failed with error %d\n",

  42. drv->name, dev_name(dev), ret);

  43. }

  44. /*

  45. * Ignore errors returned by ->probe so that the next driver can try

  46. * its luck.

  47. */

  48. ret = 0;

  49. done:

  50. atomic_dec(&probe_count);

  51. wake_up(&probe_waitqueue);

  52. return ret;

  53. }

        至此platform_driver的probe函数实现了调用并且匹配了platform_device
 

今天的文章关于platform_driver 是如何匹配 platform_device的和如何调用到platform_driver中的probe函数的研究分享到此就结束了,感谢您的阅读,如果确实帮到您,您可以动动手指转发给其他人。

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请发送邮件至 举报,一经查实,本站将立刻删除。
如需转载请保留出处:https://bianchenghao.cn/26119.html

(0)
编程小号编程小号

相关推荐

发表回复

您的电子邮箱地址不会被公开。 必填项已用 * 标注