您的位置:首页 > 运维架构 > Linux

linux2.6.32 platform驱动装载过程跟踪

2015-12-08 15:02 507 查看
本文基于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 函数是由我们在驱动程序中实现的,用来完成设备的初始化工作。

这就又产生了一个新问题,就是总线上的设备又是怎么来的呢?下回分解。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  linux驱动 platform probe