第二讲:设备树语法入门——节点、属性、标签、别名、包含文件
好,咱们正式开始啃设备树的语法。说实话,很多刚接触Linux驱动的朋友,一看到.dts文件里那些花括号、分号、@符号就头大。我当年第一次看的时候也懵——这玩意儿到底是C语言还是JSON?其实都不是,它就是一种树形结构的描述语言,专门用来告诉内核:你的硬件长什么样。
这一讲,咱们把最核心的五个概念讲透:节点、属性、标签、别名、还有.dtsi包含文件。搞懂这些,你就能看懂90%的设备树文件了。
1. 节点(Node)——设备树的骨架
节点就是设备树里的“树枝”。每个节点代表一个硬件设备或总线。比如CPU、内存、I2C控制器、GPIO控制器,都是节点。
语法很简单:
/ {
cpu {
compatible = "arm,cortex-a7";
reg = <0x10000000 0x1000>;
};
memory {
device_type = "memory";
reg = <0x80000000 0x40000000>;
};
};
看到没?根节点是/,下面挂两个子节点:cpu和memory。每个节点用花括号包起来,最后加分号。节点里可以再嵌套子节点,形成树状结构。
2. 属性(Property)——节点的“身份证”
属性就是描述节点特征的东西。每个属性都有一个名字和一个值。常见的属性类型有:
| 属性类型 | 写法示例 | 说明 |
|---|---|---|
| 字符串 | compatible = "arm,cortex-a7"; |
用于驱动匹配,最重要 |
| 32位整数 | reg = <0x10000000 0x1000>; |
地址和长度,尖括号包着 |
| 64位整数 | reg = <0x0 0x80000000 0x0 0x40000000>; |
高32位在前,低32位在后 |
| 布尔值 | status = "okay"; |
或者"disabled",没有true/false |
| 字节数组 | local-mac-address = [00 11 22 33 44 55]; |
方括号,十六进制 |
这里我要特别强调compatible属性。它就像设备的“身份证号”,驱动通过它来匹配设备。格式一般是"厂商,型号",比如"ti,am335x-uart"、"fsl,imx6q-uart"。我踩过坑:有一次把逗号写成了点,结果驱动死活不认,查了两天才发现。
3. 标签(Label)——给节点起个“外号”
标签就是节点的别名,方便在其他地方引用。语法是在节点名前加个名字和冒号:
uart0: serial@10000000 {
compatible = "ns16550";
reg = <0x10000000 0x100>;
};
这里的uart0就是标签。有了标签,你就可以在别处用&uart0来引用这个节点。比如在板级文件里覆盖它的属性:
&uart0 {
status = "okay";
clock-frequency = <115200>;
};
4. 别名(Alias)——给节点编号
别名跟标签有点像,但用途不同。别名是在根节点的aliases子节点里定义的:
/ {
aliases {
serial0 = &uart0;
serial1 = &uart1;
ethernet0 = &mac0;
};
};
别名的主要作用是给设备分配固定的编号。比如系统里有两个串口,你想让UART0永远是/dev/ttyS0,UART1永远是/dev/ttyS1,那就用别名固定下来。
我记得有一次调试,发现串口设备号每次启动都不一样。查了半天,原来是aliases没写对,内核按dtb里的顺序乱排的。加上别名后,世界清净了。
5. 包含文件(.dtsi)——代码复用利器
.dtsi文件就是设备树的头文件。SoC厂商会把芯片内部的所有外设定义放在.dtsi里,板卡厂商只需要包含它,然后添加板级特有的设备(比如网口、LED、按键)。
语法跟C语言的#include一样:
// imx6q.dtsi (SoC厂商提供)
#include "imx6q-pinfunc.h"
/ {
soc {
uart1: serial@02020000 {
compatible = "fsl,imx6q-uart";
reg = <0x02020000 0x4000>;
status = "disabled";
};
};
};
// my-board.dts (板卡厂商编写)
#include "imx6q.dtsi"
&uart1 {
status = "okay";
pinctrl-0 = <&pinctrl_uart1>;
};
6. 实战小技巧——如何快速验证语法
写设备树最怕什么?语法错误。编译时dtc报错,一行行查很费劲。我分享几个经验:
- 分号别漏:每个属性结束要加分号,每个节点结束也要加分号。漏一个,编译就报错。
- 花括号配对:用带缩进的编辑器,一眼就能看出括号是否匹配。
- @符号别乱用:节点名里的@后面跟的是地址,比如
serial@10000000。如果节点没有地址,就别加@。 - 先编译再烧录:我习惯每次改完.dts都执行
make dtbs,确认没报错再烧到板子上。省得启动时内核panic。
嗯,这一讲的内容就这些。说白了,设备树语法就是一套描述硬件的规则。节点是骨架,属性是血肉,标签和别名是引用方式,.dtsi是复用手段。把这五个概念搞明白,你就能自己写一个简单的设备树文件了。
下一讲,咱们聊聊设备树编译和反编译,看看.dts怎么变成.dtb,以及怎么从.dtb反推回.dts。这可是调试利器,别错过。