内核对设备树的处理
从源代码文件 dts 文件开始,设备树的处理过程为:
- dts 在 PC 机上被编译为 dtb 文件;
- u-boot 把 dtb 文件传给内核;
- 内核解析 dtb 文件,把每一个节点都转换为 device_node 结构体;
- 对于某些 device_node 结构体,会被转换为 platform_device 结构体。
dtb 中的每一个节点都被转换为 device_node 结构体
根节点被保存在全局变量 of_root 中,从 of_root 开始时可以访问到任意节点。
哪些设备树节点会被转换为 platform_device
- 根节点下含有 compatible 属性的子节点;
- 含有特定 compatible 属性的子节点
如果一个节点的 compatible 属性,它的值是这 4 者之一:“simple-bus”、“simple-mfd”、“isa”、“arm,amba-bus”,那么它的子节点(需含 compatible 属性)也可以转换为 platform_device; - 总线 I2C、SPI 节点下的子节点:不转换为 platform_device
某个总线下到子节点,应该交给对应的总线驱动程序来处理,它们不应该被转换为 platform_device。
比如以下的节点中:
- /mytest 会被转换为 platform_device,因为它兼容“simple-bus”;
它的子节点/mytest/ mytest@0 也会被转换为 platform_device - /i2c 节点一般表示 ic2 控制器,它会被转换为 platform_device,在内核中对应的 platform_driver;
- /i2c/at24c02 节点不会被转化为 platform_device,它被如何处理完全由父节点的 platform_driver 决定,一般是被创建为一共 i2c_client。
- 类似的还有/spi 节点,它一般也是用来表示 spi 控制器,它会被转换为 platform_device,在内核中有对应的 platform_device;
- /spi/ flash@0 节点不会被转换为 platform_device, 它被如何处理完全由父节点的 platform_driver 决定 , 一般是被创建为一个 spi_device。
{
mytest {
compatible = "mytest","simple-bus";
mytest@0 {
compatible = "mytest_0";
};
};
i2c {
compatile = "samsung,i2c";
at24c02 {
compatile = "at24c02";
};
};
spi {
compatile = "samsung,spi";
flash@0 {
compatible = "winbond,w25q32dw";
spi max frequency = <25000000>;
reg = <0>;
};
};
};
怎么转换为 platform_device
内核处理设备树的函数调用过程,这里不去分析;只需要得到下列结论:
- platform_device 中含有 resource 数组,它来自 device_node 的 reg,interrupts 属性;
- platform_device. dev. of_node 指向 device_node,可以通过它获得其他属性。
platform_device 如何与 platform_driver 配对
从设备树转换得来的 platform_device 会被注册会被注册进内核里,以后当我们每注册一个 platform_driver 时,它们就会两两确定能否配对,如果能配对成功就调用 platform_driver 的 probe 函数。
套路是一样的。我们需要将前面讲过的“匹配规则”再完善一下,先贴源码:
(1)最先比较:是否强制选择某个 driver
- 比较:
platform_device.driver_override
和platform_driver.driver.name
可以设置platform_device
的driver_override
,强制选择某个platform_driver
。
(2)然后比较:设备树信息
- 比较:
platform_device.dev.of_node
和platform_driver.driver.of_match_table
。
由设备树节点转换得来的platform_device
中,含有一个结构体:of_node。它的类型如下:
如果一个 platform_driver
支持设备树,它的 platform_driver.driver.of_match_table
是一个数组,类型如下:
- 首先,如果
of_match_table
中含有 compatible 值,就跟 dev 的 compatible 属性比较,若一致则成功,否则返回失败; - 其次,如果
of_match_table
中含有 type 的值,就跟 dev 的 device_type 属性比较,若一致则成功,否则返回失败; - 最后,如果
of_match_table
中含有 name 的值,就跟 dev 的 name 属性比较,若一致则成功,否则返回失败。
而设备树中不建议使用 device_type 和 name 属性,所以基本上只使用设备节点的 compatible 属性来寻找匹配的 platform_driver。
(3)接下来比较: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 的私有数据。
(4)最后比较
- platform_device. name 和 platform_driver. driver. name
可以用一张图概括这个配对过程:
没有转换为 platform_device 的节点,如何使用?
任意驱动程序里,都可以直接访问设备树。
可以使用内核里操作设备树的常用函数中介绍的函数找到节点,读出里面的值。