设备树基础语法:节点、属性、值的表示方法

设备树(Device Tree)这东西,说白了就是一块描述硬件的数据结构。我刚开始接触Linux内核时,总觉得它很神秘——为什么不用C代码直接操作寄存器,非要搞个树形结构出来?后来在项目中踩过几次坑才明白,设备树的存在,是为了让同一份内核能适配不同的硬件板卡。

嗯,咱们今天就从最基础的语法讲起。你只要掌握了节点、属性、值这三要素,设备树就算入门了。

1. 节点(Node)—— 设备树的骨架

设备树里的每个硬件设备,都对应一个节点。节点用花括号 { } 表示,节点名通常写成 设备名@地址 的形式。

节点命名规则:

  • 设备名 必须唯一,比如 uarti2c
  • @地址 是可选的,但建议加上,用于区分同类型设备
  • 节点名不能包含空格和特殊字符

举个例子,一个串口节点可以这样写:

uart0: serial@101f0000 {
    compatible = "ns16550";
    reg = <0x101f0000 0x1000>;
    interrupts = <10>;
};

这里的 uart0 是标签(label),方便其他地方引用。serial@101f0000 才是真正的节点名。我在项目中习惯给每个重要节点都加上标签,这样在 &uart0 引用时一目了然。

2. 属性(Property)—— 描述硬件特征

属性就是节点的“身份证信息”。每个属性都有一个名字和一个值。常见的属性有:

属性名 含义 示例
compatible 设备兼容性字符串,驱动匹配的关键 "ti,am335x-uart"
reg 寄存器地址和长度 <0x48020000 0x1000>
interrupts 中断号 <29>
status 设备状态(okay/disabled) "okay"

避坑指南: 我曾经在项目中把 compatible 写成了 compatiable,结果驱动死活不匹配。内核不会报错,只会默默忽略这个节点。排查了整整一天才发现是拼写错误。所以,compatible 这个单词一定要记牢。

3. 值(Value)—— 数据的表示方式

设备树的值有四种基本类型,我整理成了一张表:

类型 表示方式 示例 说明
字符串 双引号 "ns16550" 用于 compatible、status 等
32位整数 尖括号 <0x1000> 地址、中断号等
64位整数 两个32位组合 <0x00000000 0x10000000> 大地址空间用
字节数组 方括号 [0x00 0x01 0x02] MAC地址、UUID等

你想想看,为什么地址要用尖括号?因为设备树编译器(DTC)会把尖括号里的内容解析成32位整数数组。而方括号是逐字节解析的,两者完全不同。

4. 节点嵌套与引用

设备树是树形结构,节点可以嵌套。比如一个I2C控制器下面挂多个设备:

&i2c0 {
    status = "okay";
    clock-frequency = <100000>;

    eeprom@50 {
        compatible = "atmel,24c02";
        reg = <0x50>;
    };

    rtc@68 {
        compatible = "ds1307";
        reg = <0x68>;
    };
};

这里 eeprom@50rtc@68 是子节点,它们继承了父节点 i2c0 的某些属性。我个人习惯把子节点的 reg 属性写成设备地址,而不是内存地址,这样更直观。

注意: 子节点的 reg 含义取决于父节点的 #address-cells#size-cells 属性。如果父节点声明了 #address-cells = <1>,那么子节点的 reg 第一个值就是地址,第二个值是长度。这个规则很容易搞混,我建议你在写每个节点前,先确认父节点的这两个属性。

5. 核心逻辑结构图

下面这张图展示了设备树从节点到硬件寄存器的映射流程,我画成了SVG:

设备树到硬件寄存器映射流程 设备树节点 解析 compatible 属性 驱动匹配 读取 reg 属性 地址解析 ioremap 映射 硬件寄存器 关键点 1. compatible 决定驱动 2. reg 提供物理地址 3. #address-cells 控制 地址解析方式 4. ioremap 完成映射 5. 最终操作寄存器

这张图把整个流程串起来了。你从设备树节点出发,经过驱动匹配、地址解析,最后通过 ioremap 映射到硬件寄存器。每一步都离不开我们刚才讲的节点、属性、值这三个基础概念。

6. 实战小技巧

最后分享几个我在项目中积累的经验:

  • 多用标签: 每个节点都加上标签,方便在 &节点名 时引用。我见过有人直接用节点路径引用,代码又长又容易错。
  • 属性顺序不重要: 设备树编译器不关心属性顺序,但建议把 compatible 放在第一个,方便阅读。
  • 注释用 /* */ 设备树支持C风格的注释,但别用 //,有些旧版本编译器不支持。
  • 检查语法: 写完设备树后,用 dtc -I dts -O dtb -o test.dtb test.dts 编译一下,能发现大部分语法错误。

核心总结: 节点是骨架,属性是血肉,值是数据。三者组合起来,就能描述任何硬件设备。你只要记住 compatible 用于驱动匹配,reg 用于地址映射,设备树的基本语法就算掌握了。


专注资料整理