全部博文(685)
分类: 嵌入式
2014-11-03 19:37:43
从driver_register看起:
int driver_register(struct device_driver * drv) { klist_init(&drv->klist_devices, klist_devices_get, klist_devices_put); init_completion(&drv->unloaded); return bus_add_driver(drv); }klist_init与init_completion没去管它,可能是2.6的这个设备模型要做的一些工作。直觉告诉我要去bus_add_driver。
void driver_attach(struct device_driver * drv) { bus_for_each_dev(drv->bus, NULL, drv, __driver_attach); }这个熟悉,遍历总线上的设备并设用__driver_attach。
if (drv->probe) ret = drv->probe(dev); if (ret) { dev->driver = NULL; goto ProbeFailed; }只要probe存在则调用之。至此就完成了probe的调用。
总结一些,一句话,注册一个某个bus的驱动就是先把驱动自己链入到bus驱动链表中去,在从bus的设备链表中一一寻找,看有没有自己可以关联上的设备。找到就probe,再把二者bind起来。反之,添加设备道理也是一样的。
论坛讨论帖:
1. 在看platform驱动是,发现一个很低能的问题,static int __devinitdm9000_probe(struct platform_device *pdev) 中的struct platform_device *pdev是从那里来的device,跟踪platform_driver_register(&dm9000_driver);一直没有发现platform_device的出现,但是现在probe函数中突然出现了这个变量,那么这个变量是从和而来?
2. platform驱动分为platform_driver和platform_device两个结构体表示,前者表示平台驱动,后者表示平台设备,这个struct platform_device *pdev就是在平台相关文件里注册的。平台下会定义一个platform_device,然后platform_device_register(&platform_device),所以你注册的平台驱动,当在platform_bus上探测到有个设备的时候,这个你之前在平台文件里注册的platform_device就会传过来。
3. "platform_bus上探测到有个设备的时候"此句怎么理解,是怎么探测到的呢?
4. 驱动肯定是自己注册了。至于设备的注册,有些设备所使用的协议有枚举过程,从这处过程中可以得到设备信息,进而生成相应设备结构体,然后注册在相应总线上。
在总线上注册设备时,会遍历该总线上已注册的驱动,用总线的match方法判断是否有匹配的驱动,如果有,则调用驱动的probe函数;在总线上注册驱动时,会遍历该总线上已注册的设备,用总线的match方法判断是否有匹配的设备,如果有,则调用驱动的probe函数。即,不管是先注册设备还是先注册驱动,总线的match方法会作用于所有组合,如果匹配了,则调用驱动的probe方法,这样就探测到了。
platform_bus是虚拟的总线,没有具体的协议。上面所讲设备的结构体是在枚举时动态生成的,设备的注册也是在枚举时触发的,而platform_device的定义与注册是在平台初始化文件里手动做的。后面的情况就是一样的了。其它一些没有类似枚举之类过程的总线,如I2C,也是这种流程。
5. 内核启动的时候, platform_device 是优先于 platform_driver 注册的。 比如 platform_device A , 是在arch/arm/mach-XXXX/mach-XXXX.c 文件里注册的, 而这个文件的代码是 优先于 platform_driver_register 执行的。
所以在你platform_driver_register执行的时候, platform_device A已经被挂在platform_bus总线上了, 而platform_driver_register()有个功能是到platform_bus上去挨个找寻,找寻挂在上面的platform_bus上的platform_device。找到了就执行probe()。
6. 可不可以这样,我没有试过。
但是因为驱动中有 开发者实现的 probe 函数。 如果先注册驱动, 驱动就找不到设备, 从而不执行probe函数,而驱动中最重要的就是probe函数,硬件的初始化,寄存器的配置,时钟的使能都在probe函数里完成。从这一点来说,驱动先于设备注册,应该不可行。
7. 你好,关于I2C驱动,目前有三个问题想请教下:
1,请问用i2c_add_driver注册I2C的client端的驱动的时候,这个client是怎么和哪个adapter attach的(在此之前,系统中注册了四个bit-style的adapter)?注意,我的i2c_driver中,并没有赋值attach_adapter,但是赋值了probe
2,注册adapter是用的 i2c_add_adapter,跟了下这个函数,发现它call的是->i2c_register_adapter->
adap->dev.bus = &i2c_bus_type;
adap->dev.type = &i2c_adapter_type;
res = device_register(&adap->dev);
这里是注册的是一个device,那么根据device-driver的模型,那adapter的driver是怎么被赋值的呢?
3,i2c_add_driver是向哪跟总线上注册的,是i2c_bus_type吗?i2c_register_adapter又是向哪跟总线注册的呢? 也是i2c_bus_type吗?
谢谢
8. i2c_driver并不是要跟adapter绑定,而是要和i2c_client绑定 。注册一个i2c_driver时并不知道它支持的设备在哪条总线上。例如一个系统有两个i2c控制器,每个控制器上有一个相同型号的EEPROM,它们只需一个i2c_driver。关键在于如何发现哪条总线上有i2c_driver所支持设备。
老I2C框架里,由i2c_driver负责发现设备,每注册一个adapter遍历已注册i2c_driver,每注册一个i2c_driver遍历已注册的i2c_adapter,不让他们错过任何一次组合,让i2c_driver在adapter上探测一下是否有它支持的设备,如果有,则生成一个i2c_client实例。当然由于i2c协议很弱,这种探测很不可靠。
现在(尤其在SOC系统中)倾向于静态定义这些信息:如果我知道哪条总线上有哪个设备,我就犯不着让i2c_driver去找它们了。于是在平台初始化函数里注册i2c_board_info,这个结构体就是一个i2c_client模板。i2c_board_info里有个bus_num作为匹配的凭证,如果bus_num与i2c_adapter的bus_num相同,那就匹配上了。所有注册的i2c_board_info会放在一个链表里,每注册一个i2c_adapter就去扫描这个链表,如果匹配就生成i2c_client。
在老框架,i2c_client肯定是在i2c_driver时调用attach_adapter时出现的;新框架里则可以在没有i2c_driver的情况下根据静态信息生成i2c_client。另外让i2c_driver探测设备时,顶多能知道设备地址,而欲查询设备其它属性,i2c协议里没有通用的方法。而i2c_board_info静态了提供了这些属性。
而对于旧框架,新框架一方面在接口上保持兼容,另一方面在功能上也有更新。新框架里通过bus_num来区别是扫描静态的i2c_board_info链表。如果不是,那就又归到老式的方法:让i2c_driver去找设备。这个过程跟上面讲的老框架的过程一样,添加adapter或者driver时相互遍历已注册的对方。新方法里有个i2c_detect,看起来是把以前散落在各个i2c_driver->attach_adapter中的代码抽象出来了,最后再调用i2c_driver->detect,这个的功能应该和i2c_driver->attach_adapter是一样的。只不过它只负责是否检测到驱动支持的设备,而i2c_client的生成则放在外面框架代码里了。最后再调用i2c_driver->attach_adapter,兼容旧驱动。注释里说这个方法以后可能会消失。其实在SOC系统里,一般到静态扫描就完了,也不会去调用detect方法。
不管通过什么方法生成i2c_client,注册它后,下面就是经典设备模型里的match/probe了。
i2c_driver与i2c_adapter都是注册在i2c_bus_type上,至于i2c_adapter的driver,我以前看代码时也没找着。现在看来,它根本没有另一半。其实看i2c_bus_type->match方法,它是通过i2c_verify_client把device转成i2c_client的,这里只验证device->type是不是i2c_client_type,也就是说,这条总线根本没准备为i2c_adapter匹配任何东西。