简介

在这里我们只讨论,设备树的平台设备和平台驱动的匹配过程。

  1. 下面是我想要分析的驱动匹配过程代码
  2. static struct platform_driver i2c_versatile_driver = {
  3. .probe = i2c_versatile_probe,
  4. .remove = i2c_versatile_remove,
  5. .driver = {
  6. .name = "versatile-i2c",
  7. .of_match_table = i2c_versatile_match,
  8. },
  9. };
  10. static int __init i2c_versatile_init(void)
  11. {
  12. return platform_driver_register(&i2c_versatile_driver);
  13. }

追踪 i2c_versatile_init以及 i2c_versatile_probe两个函数得到下面的函数调用栈

  1. i2c_versatile_init的函数调用栈
  2. i2c_versatile_init() (linux-4.0/drivers/i2c/busses/i2c-versatile.c:127) // 此函数就是我们想要追踪的函数之一,然后会调用 driver_register 函数做一系列的注册
  3. do_one_initcall(initcall_t fn) (linux-4.0/init/main.c:885) // 这个函数遍历初始化段里面的函数,来初始化系统
  4. do_initcall_level() (linux-4.0/init/main.c:953)
  5. do_initcalls() (linux-4.0/init/main.c:961)
  6. do_basic_setup() (linux-4.0/init/main.c:979)
  7. kernel_init_freeable() (linux-4.0/init/main.c:1144)
  8. kernel_init(void * unused) (linux-4.0/init/main.c:1063)
  9. ret_from_fork() (linux-4.0/arch/arm/kernel/entry-common.S:158)
  10. i2c_versatile_probe的函数调用栈
  11. i2c_versatile_probe(struct platform_device * dev) (drivers/i2c/busses/i2c-versatile.c:73) // 前面 i2c_versatile_init 注册的 回调函数,
  12. platform_drv_probe(struct device * _dev) (drivers/base/platform.c:579)
  13. really_probe(struct device * dev, struct device_driver * drv) (drivers/base/dd.c:500)
  14. driver_probe_device(struct device_driver * drv, struct device * dev) (drivers/base/dd.c:662)
  15. __driver_attach(struct device * dev, void * data) (drivers/base/dd.c:896)
  16. bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*)(struct device *, void *) fn) (drivers/base/bus.c:314)
  17. driver_attach(struct device_driver * drv) (drivers/base/dd.c:915)
  18. bus_add_driver(struct device_driver * drv) (drivers/base/bus.c:670)
  19. driver_register(struct device_driver * drv) (drivers/base/driver.c:170)
  20. // 第二次到这里的时候 drv->name = "versatile-i2c"
  21. do_one_initcall(initcall_t fn) (init/main.c:885) // 遍历调用初始段里面的函数
  22. do_initcall_level() (init/main.c:953)
  23. do_initcalls() (init/main.c:961)
  24. do_basic_setup() (init/main.c:979)
  25. kernel_init_freeable() (init/main.c:1144)
  26. kernel_init(void * unused) (init/main.c:1063)
  27. ret_from_fork() (arch/arm/kernel/entry-common.S:158)

上面的 platform_driver_register() 函数其实隐藏了三个技术点,

  • 第一个就是如果 platform bus 还没有注册到系统,就直接调用 platform_driver_register() 函数,这样是不会触发系统进行 bus match 操作的;、
  • 第二种情况就是刚刚这种,driver_init() 刚好注册好 platform bus 之后,do_initcalls 遍历的 init 函数里调用 platform_drver_register, 这样会立即去触发 match bus 操作;
  • 最后一种就是系统初始化完毕之后,插入 module,在 module 的 init 函数里调用了 platform_driver_register, 这也会触发 bus match。

根据上面的描述,总结一下,

  1. 如果platform bus还没有被注册到到系统,此时我们要是platform_driver_register() 函数,系统不会触发match操作。
  2. driver_init() 刚好注册好 platform bus 以后,do_initcalls 遍历的 init 函数里调用 platform_drver_register函数,这样就立即触发match操作。
  3. 系统初始化完毕之后,插入 module。这里会触发match操作。

三种情况都提到了match操作,那么

  1. 那个函数调用的match操作?
  2. match操作的实现过程。

    bus_add_driver

    一切都要从bus_add_driver函数讲起。
    platform_drver_register调用driver_register函数。然后driver_register函数首先判断这个驱动名字是否注册过。
    other = driver_find(drv->name, drv->bus);若是没有注册则继续调用bus_add_driver函数。
    然后bus_add_driver函数将会顺序调用driver_attach函数bus_for_each_dev函数。此函数将会遍历总线上面的所有设备,调用__driver_attach函数。最后我们可以在__driver_attach函数中看到。ret = driver_match_device(drv, dev); 最后就是在这里调用的match操作。到这里我们就理清楚了match操作产生。上面第一个问题也就迎刃而解了。
  • 最终是bus_add_driver函数一层层调用下去,由__driver_attach函数调用match操作

下面来解答第二个问题。 platform_match函数的实现过程。

platform_match

首先判断这个设备是否已经加载过了,

  1. if (pdev->driver_override)
  2. return !strcmp(pdev->driver_override, drv->name);

若是没有加载过,优先匹配设备树里面的设备,

  1. if (of_driver_match_device(dev, drv))

再其次,若是存在id_table。那么则匹配设备的名字。

  1. platform_match_id(pdrv->id_table, pdev)
  2. strcmp(pdev->name, id->name)

最后才是匹配驱动名称和设备名称

  1. strcmp(pdev->name, drv->name)

若是我们将驱动和设备之间的匹配分一个优先级,那么

  1. 首先比较设备driver_override和平台驱动的设备驱动的名字作比较,相同则匹配。
  2. 其次通过设备树来进行匹配,众所周知的.compatible
  3. 再其次若是存在id_table,将将其和平台设备的名字作比较即可。
  4. 最后才是设备名称和驱动名称的比较。

__driver_attach匹配到了设备,也就是match操作返回1。就调用driver_probe_device函数,由此函数来调用
drv->probe(dev)驱动的probe函数。

小结

最终到这里我们就完整的遍历了一遍总线和驱动的匹配过程。

  • 在增加总线驱动的时候,调用 match 函数。
  • 当匹配到对应的设备的时候,就调用对应的probe函数。