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

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

这就又产生了一个新问题,就是总线上的设备又是怎么来的呢?下回分解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值