简介
在这里我们只讨论,设备树的平台设备和平台驱动的匹配过程。
下面是我想要分析的驱动匹配过程代码
static struct platform_driver i2c_versatile_driver = {
.probe = i2c_versatile_probe,
.remove = i2c_versatile_remove,
.driver = {
.name = "versatile-i2c",
.of_match_table = i2c_versatile_match,
},
};
static int __init i2c_versatile_init(void)
{
return platform_driver_register(&i2c_versatile_driver);
}
追踪 i2c_versatile_init以及 i2c_versatile_probe两个函数得到下面的函数调用栈
• i2c_versatile_init的函数调用栈
i2c_versatile_init() (linux-4.0/drivers/i2c/busses/i2c-versatile.c:127) // 此函数就是我们想要追踪的函数之一,然后会调用 driver_register 函数做一系列的注册
do_one_initcall(initcall_t fn) (linux-4.0/init/main.c:885) // 这个函数遍历初始化段里面的函数,来初始化系统
do_initcall_level() (linux-4.0/init/main.c:953)
do_initcalls() (linux-4.0/init/main.c:961)
do_basic_setup() (linux-4.0/init/main.c:979)
kernel_init_freeable() (linux-4.0/init/main.c:1144)
kernel_init(void * unused) (linux-4.0/init/main.c:1063)
ret_from_fork() (linux-4.0/arch/arm/kernel/entry-common.S:158)
• i2c_versatile_probe的函数调用栈
i2c_versatile_probe(struct platform_device * dev) (drivers/i2c/busses/i2c-versatile.c:73) // 前面 i2c_versatile_init 注册的 回调函数,
platform_drv_probe(struct device * _dev) (drivers/base/platform.c:579)
really_probe(struct device * dev, struct device_driver * drv) (drivers/base/dd.c:500)
driver_probe_device(struct device_driver * drv, struct device * dev) (drivers/base/dd.c:662)
__driver_attach(struct device * dev, void * data) (drivers/base/dd.c:896)
bus_for_each_dev(struct bus_type * bus, struct device * start, void * data, int (*)(struct device *, void *) fn) (drivers/base/bus.c:314)
driver_attach(struct device_driver * drv) (drivers/base/dd.c:915)
bus_add_driver(struct device_driver * drv) (drivers/base/bus.c:670)
driver_register(struct device_driver * drv) (drivers/base/driver.c:170)
// 第二次到这里的时候 drv->name = "versatile-i2c"
do_one_initcall(initcall_t fn) (init/main.c:885) // 遍历调用初始段里面的函数
do_initcall_level() (init/main.c:953)
do_initcalls() (init/main.c:961)
do_basic_setup() (init/main.c:979)
kernel_init_freeable() (init/main.c:1144)
kernel_init(void * unused) (init/main.c:1063)
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。
根据上面的描述,总结一下,
- 如果platform bus还没有被注册到到系统,此时我们要是platform_driver_register() 函数,系统不会触发match操作。
- driver_init() 刚好注册好 platform bus 以后,do_initcalls 遍历的 init 函数里调用 platform_drver_register函数,这样就立即触发match操作。
- 系统初始化完毕之后,插入 module。这里会触发match操作。
三种情况都提到了match操作,那么
- 那个函数调用的match操作?
- 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
首先判断这个设备是否已经加载过了,
if (pdev->driver_override)
return !strcmp(pdev->driver_override, drv->name);
若是没有加载过,优先匹配设备树里面的设备,
if (of_driver_match_device(dev, drv))
再其次,若是存在id_table。那么则匹配设备的名字。
platform_match_id(pdrv->id_table, pdev)
strcmp(pdev->name, id->name)
最后才是匹配驱动名称和设备名称
strcmp(pdev->name, drv->name)
若是我们将驱动和设备之间的匹配分一个优先级,那么
- 首先比较设备driver_override和平台驱动的设备驱动的名字作比较,相同则匹配。
- 其次通过设备树来进行匹配,众所周知的.compatible
- 再其次若是存在id_table,将将其和平台设备的名字作比较即可。
- 最后才是设备名称和驱动名称的比较。
__driver_attach匹配到了设备,也就是match操作返回1。就调用driver_probe_device函数,由此函数来调用
drv->probe(dev)驱动的probe函数。
小结
最终到这里我们就完整的遍历了一遍总线和驱动的匹配过程。
- 在增加总线驱动的时候,调用 match 函数。
- 当匹配到对应的设备的时候,就调用对应的probe函数。