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()中 仅调用
在 platform_driver_register() 中调用
在 driver_register() 中调用
在 bus_add_driver() 中调用
在driver_attach() 中 就一句话:
这个函数实际上是在做一个遍历工作,从start开始, 遍历 bus 上的每一个设备 dev, 对每一个dev,执行 fn 操作,可以看到fn有两个输入参数,分别是 dev 和 data;
在这里,bus 是 drv->bus 即 驱动挂载的总线, start是NULL 即从头开始,data 是 drv 即驱动结构体,fn 是 __driver_attach
__driver_attach是一个函数,这个函数有两个输入参数 dev 和 drv, 即设备和驱动,函数中会去调用
driver_match_device 这个函数之后细说,总之是用于判断 驱动 和 设备 是否匹配,不匹配的就直接返回,
如果匹配,且dev结构还没有绑定驱动(即if (!dev->driver)为真),就去调用 driver_probe_device(drv, dev),这个函数我们也待会儿细说。
这样我们就知道了 driver_attach() 这个函数在做这件事情: 将驱动 drv 挂载的总线上的所有设备分别去和 drv判断两者是否匹配,至于怎么判断,就是调用这个函数:
而匹配了之后做什么,就是调用这个函数:
接下来我们就来看看这两个函数。
driver_match_device() 非常简单, 也就一句话
实际上就是调用 总线的 match 函数,如果该驱动挂载的总线没有 match 函数,那就始终返回1,认为始终是匹配的。
那我们就看下 platform 总线的匹配函数
在 platform_match() 函数中,如果 驱动drv 有 id_table, 就通过 id_table 匹配,
否则就直接判断名字是否一样: return (strcmp(pdev->name, drv->name) == 0);
接着再看确认匹配后,且设备还没有绑定驱动时所调用的
在 driver_probe_device() 函数中 调用了 really_probe(dev, drv)
在really_probe() 函数中, 首先做了设备和驱动的绑定:
接着:
如果总线有probe函数, 就调用总线的 probe 函数,否则如果有驱动的probe函数,就调用驱动的probe函数。
platform总线并没有probe函数:
那么就直接调用驱动的probe函数,至此,终于又回到了我们写的驱动程序中来,我们就可以在probe函数中进行初始化的操作了。
总结一下:
在编写platform总线上的驱动时,init函数中只需调用platform_driver_register(…),之后,系统会遍历platform上的所有设备,若找到了与驱动匹配的设备 device,那么就会调用 probe函数,而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 函数是由我们在驱动程序中实现的,用来完成设备的初始化工作。
这就又产生了一个新问题,就是总线上的设备又是怎么来的呢?下回分解。
相关文章推荐
- OMAP3630 Linux I2C总线驱动分析
- Linux设备驱动开发环境的搭建
- 迅为4412开发板Linux驱动教程/硬件知识及原理图的使用
- 教你如何使用platform密钥对apk进行签名
- 设备控制接口(ioctl 函数) 主要是在驱动中
- Broadcom NetXtreme II BCM5706/5708/5709/5716 Driver 驱动问题处理办法
- NAPI
- 嵌入式linux和嵌入式android系统有什么区别和联系?
- [arm驱动]Platform设备驱动
- struct file结构体
- Linux设备驱动之简单字符设备驱动开开发
- Fedora 20 上安装基于dell 1420的无线网卡驱动
- 记得感激我 评论我 nvidia显卡驱动linux系统地安装 完全驱动方法 世界第一人
- pwm驱动程序及其注释
- pwm驱动程序及其注释
- 在使用SIS M672+SIS 968芯片组,SIS Mirage 3+集成显卡的电脑上安装Debian 7.7的驱动
- Xcode相关平台及SDK路径
- Bus--device--driver驱动模型源码分析
- linux驱动---DMA操作---驱动编写