2020.12.4
分析总线驱动模型是为了搞清楚总线是如何将driver和device匹配的,即当我们插入我们的设备时,总线是如何找到这个设备对应的驱动,并且调用驱动的probe函数的。不管是先有驱动后有设备、还是先有设备后有驱动。都会调用驱动driver中的probe,而不是设备device。
总线的引入:
首先,驱动设计从直接操作寄存器,每一次修改都要很费劲;到实现驱动程序的第一次
分层,分为了两层,实现了更换单板或芯片时修改更加方便;再到所谓的“分离”,做到
了修改引脚也可以更加的方便。可以说是把分层后的第二层给再细分一下。
在前面,我们为了给硬件分配所谓的“资源”,定义了一个 led_resouce 结构体。很显然,给每个设备都定义一个结构体,太麻烦了,很有重复造轮子的感觉。所以,出现了“平台”这个概念,也就是platform_device结构体,它里面允许我们来定义各种硬件的资源。
到目前为止,都是对硬件的指定的框架在变化,而对硬件的操作,也就是要利用这些硬件达到什么效果,这些并没有什么变化:
-
分配\设置\注册 fileoperation结构体
-
使用ioremap映射寄存器
-
再对寄存器进行操作
因此右侧的driver结构体并没有本质的变化,那么问题来了,这两个平台如何一一对应?这就要交给总线结构了,先放一放,我们先看看platform_device结构体长什么样:
static struct platform_device board_A_led_dev = {
.name = "100ask_led",
.num_resources = ARRAY_SIZE(resources),
.resource = resources,
};
原来如此,老朋友“资源”被定义在了platform_device结构体的resources里,不过值得注意的是,在结构体的私有数据里也可以定义“资源”。不过在resources里定义时,要遵守一定的规则。
当device和driver配对成功时,driver的probe函数就会被调用,然后依然只是对硬件操作的老三步。
而总线驱动模型的另一个需要注意的地方就是,这个总线的两端连着一堆platform_device和platform_driver,他们是怎么互相找到对方的呢?
所以进入到下一个环节:
总线的配对:
① 最先比较:是否强制选择某个 driver
比较 platform_device. driver_override 和 platform_driver.driver.name
可以设置 platform_device 的 driver_override,强制选择某个 platform_driver。
② 然后比较:设备树信息
比较:platform_device. dev.of_node 和 platform_driver.driver.of_match_table。
由设备树节点转换得来的 platform_device 中,含有一个结构体:of_node。
如果一个 platform_driver 支持设备树,它的 platform_driver.driver.of_match_table 是一个数组。
使用设备树信息来判断 dev 和 drv 是否配对时,
首先,如果 of_match_table 中含有 compatible 值,就跟 dev 的 compatile 属性比较,若
一致则成功,否则返回失败;
其次,如果 of_match_table 中含有 type 值,就跟 dev 的 device_type 属性比较,若一致
则成功,否则返回失败;
最后,如果 of_match_table 中含有 name 值,就跟 dev 的 name 属性比较,若一致则成
功,否则返回失败。
而设备树中建议不再使用 devcie_type 和 name 属性,所以基本上只使用设备节点的
compatible 属性来寻找匹配的 platform_driver。
③ 接下来比较:platform_device_id
比较platform_device. name和platform_driver.id_table[i].name,
id_table中可能有多项。
platform_driver.id_table 是“platform_device_id”指针,表示该 drv 支持若干个 device,它
里面列出了各个 device 的{.name, .driver_data},其中的“name”表示该 drv 支持的设备的名
字,driver_data 是些提供给该 device 的私有数据。
④ 最后比较:platform_device.name 和 platform_driver.driver.name
platform_driver.id_table 可能为空,
这时可以根据 platform_driver.driver.name 来寻找同名的 platform_device。