天天看点

Linux设备、总线和驱动之间的关系

(一)、驱动、总线和设备的主要数据结构

(include/linux/device.h)

Linux设备、总线和驱动之间的关系

(/driver/base/base.h)

Linux设备、总线和驱动之间的关系

(include/device.h)

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

总线中的那两条链表是怎么形成的。内核要求每次出现一个设备就要向总线汇报,或者说注册,每次出现一个驱动,也要向总线汇报,或者说注册。比如系统初始化的时候,会扫描连接了哪些设备,并为每一个设备建立起一个structdevice 的变量,每一次有一个驱动程序,就要准备一个tructdevice_driver 结构的变量。把这些变量统统加入相应的链表,device 插入devices 链表,driver 插入drivers 链表。这样通过总线就能找到每一个设备,每一个驱动。

设备和驱动又是如何联系?

原来是把每一个要用的设备在计算机启动之前就已经插好了,插放在它应该在的位置上,然后计算机启动,然后操作系统开始初始化,总线开始扫描设备,每找到一个设备,就为其申请一个structdevice 结构,并且挂入总线中的devices 链表中来,然后每一个驱动程序开始初始化,开始注册其struct device_driver 结构,然后它去总线的devices 链表中去寻找(遍历),去寻找每一个还没有绑定驱动的设备,structdevice 中的structdevice_driver 指针仍为空的设备,然后它会去观察这种设备的特征,看是否是他所支持的设备,如果是,那么调用一个叫做device_bind_driver 的函数,然后他们就结为了秦晋之好。换句话说,把structdevice 中的structdevice_driverdriver 指向这个驱动,而struct device_driver driver 把struct device 加入他的那structklist klist_devices链表中来。就这样,bus、device 和driver,这三者之间或者说他们中的两两之间,就给联系上了。知道其中之一,就能找到另外两个。

但现在情况变了,出现了一种新的名词,叫热插拔。设备可以在计算机启动以后在插入或者拔出计算机了。设备可以在任何时刻出现,而驱动也可以在任何时刻被加载,所以,出现的情况就是,每当一个structdevice 诞生,它就会去bus 的drivers链表中寻找自己的另一半,反之,每当一个struct device_driver 诞生,它就去bus的devices 链表中寻找它的那些设备。如果找到了合适的,那么OK,和之前那种情况一下,调device_bind_driver 绑定好。如果找不到,没有关系,等待吧!

(二)、 驱动注册的代码游走

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

其中 ptr是指向正被使用的某类型变量指针;type是包含ptr指向的变量类型的结构类型;member是type结构体中的成员,类型与ptr指向的变量类型一样。功能是计算返回包含ptr指向的变量所在的type类型结构变量的指针。(比较拗口)该宏的实现思路:计算type结构体成员member在结构体中的偏移量,然后ptr的地址减去这个偏移量,就得出type结构变量的首地址。该宏的实现方法:1、通过typeof关键字定义一个与type结构体的member成员相同的类型的变量__mptr且将ptr值赋给它。            

2、用宏offsetof(type,member),获取member成员在type结构中的偏移量(原型:offsetof(TYPE,MEMBER)((size_t)&(TYPE *)0)->MEMBER). 定义在stddef.h.)            

3、最后将__mptr值减去这个偏移量,就得到这个结构变量的地址了(亦指针)。

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

(三)、设备注册代码

以USB检测为例

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

中间省略了一部分代码:

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

中间省略N行

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

(四)、探测函数probe的寻根

很多驱动都会有probe函数,probe函数不像read和write函数那样是经过调用才执行,probe函数会在驱动安装或设备被发现的时候执行,这就会设计到两方面的内容,probe函数到底是怎样实现的呢?

经过之前的代码游走之后,可以发现,在驱动安装过程中会调用driver_attach函数,通过该函数去检测对应总线上是否有该驱动所对应的dev设备,如果有就执行驱动中的probe函数。

对于设备,当设备被发现之后最终也会执行一个叫device_attach函数,通过该函数去寻找对应总线中的设备驱动,当找到对应的设备驱动之后就去执行驱动中的probe函数。

4.1驱动driver端

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

4.2设备device端

Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系
Linux设备、总线和驱动之间的关系

继续阅读