本文基于linux 2.6.32内核代码,分析了platform驱动的状态过程,跟踪了从模块init函数到 执行probe的过程。其他总线的驱动也是类似的。
module_init(xxx_init); 那么在模块装载时 将 调用 xxx_init()函数
在xxx_init()中 仅调用
int platform_driver_register(struct platform_driver *drv)
在 platform_driver_register() 中调用
int driver_register(struct device_driver *drv)
在 driver_register() 中调用
int bus_add_driver(struct device_driver *drv)
在 bus_add_driver() 中调用
int driver_attach(struct device_driver *drv)
在driver_attach() 中 就一句话:
return bus_for_each_dev(drv->bus, NULL, drv, __driver_attach);
int bus_for_each_dev(struct bus_type *bus, struct device *start, void *data, int (*fn)(struct device *, void *))
这个函数实际上是在做一个遍历工作,从start开始, 遍历 bus 上的每一个设备 dev, 对每一个dev,执行 fn 操作,可以看到fn有两个输入参数,分别是 dev 和 data;
在这里,bus 是 drv->bus 即 驱动挂载的总线, start是NULL 即从头开始,data 是 drv 即驱动结构体,fn 是 __driver_attach
__driver_attach是一个函数,这个函数有两个输入参数 dev 和 drv, 即设备和驱动,函数中会去调用
if (!driver_match_device(drv, dev))
return 0;
driver_match_device 这个函数之后细说,总之是用于判断 驱动 和 设备 是否匹配,不匹配的就直接返回,
如果匹配,且dev结构还没有绑定驱动(即if (!dev->driver)为真),就去调用 driver_probe_device(drv, dev),这个函数我们也待会儿细说。
这样我们就知道了 driver_attach() 这个函数在做这件事情: 将驱动 drv 挂载的总线上的所有设备分别去和 drv判断两者是否匹配,至于怎么判断,就是调用这个函数:
static inline int driver_match_device(struct device_driver *drv, struct device *dev)
而匹配了之后做什么,就是调用这个函数:
int driver_probe_device(struct device_driver *drv, struct device *dev)
接下来我们就来看看这两个函数。
driver_match_device() 非常简单, 也就一句话
return drv->bus->match ? drv->bus->match(dev, drv) : 1;
实际上就是调用 总线的 match 函数,如果该驱动挂载的总线没有 match 函数,那就始终返回1,认为始终是匹配的。
那我们就看下 platform 总线的匹配函数
static int platform_match(struct device *dev, struct device_driver *drv)
在 platform_match() 函数中,如果 驱动drv 有 id_table, 就通过 id_table 匹配,
否则就直接判断名字是否一样: return (strcmp(pdev->name, drv->name) == 0);
接着再看确认匹配后,且设备还没有绑定驱动时所调用的
int driver_probe_device(struct device_driver *drv, struct device *dev)
在 driver_probe_device() 函数中 调用了 really_probe(dev, drv)
在really_probe() 函数中, 首先做了设备和驱动的绑定:
dev->driver = drv;
driver_sysfs_add(dev);
接着:
if (dev->bus->probe) {
ret = dev->bus->probe(dev);
if (ret)
goto probe_failed;
} else if (drv->probe) {
ret = drv->probe(dev);
if (ret)
goto probe_failed;
}
如果总线有probe函数, 就调用总线的 probe 函数,否则如果有驱动的probe函数,就调用驱动的probe函数。
platform总线并没有probe函数:
struct bus_type platform_bus_type = {
.name = "platform",
.dev_attrs = platform_dev_attrs,
.match = platform_match,
.uevent = platform_uevent,
.pm = &platform_dev_pm_ops,
};
那么就直接调用驱动的probe函数,至此,终于又回到了我们写的驱动程序中来,我们就可以在probe函数中进行初始化的操作了。
总结一下:
在编写platform总线上的驱动时,init函数中只需调用platform_driver_register(…),之后,系统会遍历platform上的所有设备,若找到了与驱动匹配的设备 device,那么就会调用 probe函数,而probe 函数是由我们在驱动程序中实现的,用来完成设备的初始化工作。
这就又产生了一个新问题,就是总线上的设备又是怎么来的呢?下回分解。