4、设备树绑定与规范:设备树绑定文档、Schema验证、YAML绑定格式、检查绑定正确性

设备树绑定,说白了就是一份「说明书」。

它告诉内核:某个硬件设备该怎么描述,哪些属性是必须的,哪些是可选的。我在早期做嵌入式开发时,就吃过没写绑定的亏——自己写的设备树节点,过了一个月再看,完全忘了那些自定义属性是干嘛用的。嗯,从那以后,我养成了写绑定文档的习惯。

4.1 设备树绑定文档

绑定文档通常放在内核源码的 Documentation/devicetree/bindings/ 目录下。每个子系统都有自己的子目录,比如 gpio/、i2c/、pinctrl/ 等。

文档里要写清楚:

  • 兼容性字符串:比如 compatible = "vendor,device"
  • 必需属性:比如 reg、interrupts、clocks 等
  • 可选属性:比如 gpio-hog、power-supply 等
  • 子节点要求:比如某些总线控制器要求子节点有特定的 reg 格式
  • 示例节点:一个完整的设备树节点示例

我个人习惯:写绑定文档时,先列一个表格,把属性名、类型、是否必需、描述都写清楚。这样后续维护时一目了然。

4.2 Schema验证

光有文档还不够。你想想看,如果设备树写错了,内核启动时可能直接 panic。所以我们需要一种自动化的验证方式。

Linux 内核现在使用 DT Schema 来做这件事。它基于 JSON Schema 标准,用 YAML 格式编写。每个绑定文件对应一个 schema 文件,扩展名是 .yaml。

验证工具是 dt-validate,它会检查:

  • 属性名是否拼写正确
  • 属性值类型是否匹配(比如字符串写成了数字)
  • 必需属性是否缺失
  • 子节点数量是否符合要求

避坑指南:我曾经遇到过一个问题——设备树里把 interrupts 写成了 interrupt,少了个 s。内核编译没报错,但中断就是不起作用。后来用 dt-validate 一跑,秒出错误。所以我现在每次提交代码前,都会跑一遍 schema 验证。

4.3 YAML绑定格式

YAML 绑定文件长什么样?我给你看一个典型的例子:

# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/gpio/gpio-leds.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#

title: GPIO LEDs

maintainers:
  - Jacek Anaszewski <jacek.anaszewski@gmail.com>
  - Pavel Machek <pavel@ucw.cz>

properties:
  compatible:
    const: gpio-leds

  led:
    type: object
    additionalProperties: false
    properties:
      gpios:
        maxItems: 1
      label:
        $ref: /schemas/types.yaml#/definitions/string
      linux,default-trigger:
        $ref: /schemas/types.yaml#/definitions/string
      default-state:
        enum: [on, off, keep]
    required:
      - gpios

required:
  - compatible

additionalProperties: false

examples:
  - |
    leds {
        compatible = "gpio-leds";
        led-0 {
            gpios = <&gpio0 0 GPIO_ACTIVE_HIGH>;
            label = "power";
            linux,default-trigger = "heartbeat";
        };
    };

这个文件里,properties 定义了节点可以有哪些属性,required 定义了哪些是必须的,examples 给出了一个完整示例。

有几个关键点要注意:

  • $ref 用来引用其他 schema 文件,比如类型定义
  • additionalProperties: false 表示不允许出现未定义的属性
  • enum 限制属性值只能从枚举列表中选
  • maxItems 限制数组的最大长度

注意:YAML 对缩进非常敏感。我见过有人用 tab 缩进,结果 schema 解析失败。请务必使用空格,推荐 2 个空格缩进。

4.4 检查绑定正确性

写完绑定文件后,怎么检查它对不对?

内核提供了一个测试框架,叫 dt_binding_check。你可以在内核源码根目录下运行:

make dt_binding_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/gpio/gpio-leds.yaml

这个命令会:

  1. 解析你的 YAML 文件,检查语法是否正确
  2. 验证 schema 本身是否符合 meta-schema 的规范
  3. 如果有示例,还会检查示例是否合法

另外,还有 dtbs_check 命令,它会用所有绑定文件去验证实际的设备树文件:

make dtbs_check DT_SCHEMA_FILES=Documentation/devicetree/bindings/gpio/gpio-leds.yaml

这个命令会扫描所有 .dts 文件,找出那些不符合你绑定规范的节点。

我的经验:在 Yocto 项目中,我会在 local.conf 里加上 INHERIT += "devicetree",这样每次编译时都会自动验证设备树。如果验证失败,构建过程会直接报错,不会生成有问题的镜像。

4.5 知识体系结构图

下面这张图展示了设备树绑定的完整工作流:

设备树绑定工作流 编写绑定文档 .yaml 格式 Schema验证 dt_binding_check 检查绑定正确性 dtbs_check 生成设备树 .dtb 文件 Yocto集成 INHERIT += "devicetree" 关键检查点 • 必需属性是否齐全(compatible、reg、interrupts 等) • 属性值类型是否正确(字符串、数字、枚举、phandle 等) • 子节点结构是否符合预期(数量、命名、属性约束)

这张图展示了从编写绑定文档到最终生成设备树的完整流程。我个人建议,在 Yocto 项目中一定要把 dt_binding_check 和 dtbs_check 集成到构建流程里。这样能提前发现很多问题,避免在硬件上调试时抓狂。

小技巧:如果你不确定某个属性该怎么写,可以去内核源码里搜一下同类型设备的绑定文件。比如你想写一个 I2C 设备的绑定,就看看 Documentation/devicetree/bindings/i2c/ 目录下的例子。模仿是最快的学习方式。

好了,关于设备树绑定与规范,核心就是这些。记住:绑定文档不是摆设,它是你和内核之间的一份「契约」。写清楚、验证好,能省下大把调试时间。

可可精品资料库