1. 引言
设备树(Device Tree, DT)是 Linux 内核用于描述硬件的平台抽象方式。设备树中的 属性(Properties) 存储了设备的配置信息,Linux 内核通过特定的 API 解析和读取这些属性,以正确初始化设备驱动。
本篇文章将详细讲解 Linux 内核如何解析设备树属性,并提供一个 标准内核模块代码 以及 对应的设备树配置,帮助你理解关键技术点。
2. 内核解析设备树的基本机制
Linux 内核解析设备树时,主要依赖 Flattened Device Tree (FDT) 解析框架,其核心组件包括:
- drivers/of/ 文件夹:存放设备树解析代码。
- of.h 头文件:定义了设备树 API。
- of_device.h 头文件:定义了
struct device_node
结构体。
2.1 设备树解析核心数据结构
(1)设备节点 struct device_node
struct device_node {const char *name; // 设备节点名称struct property *properties; // 指向该节点的属性列表struct device_node *parent; // 父节点struct device_node *child; // 子节点struct device_node *sibling; // 兄弟节点
};
(2)设备树属性 struct property
struct property {char *name; // 属性名int length; // 属性值长度void *value; // 指向属性值的指针
};
3. 如何在 Linux 设备驱动中解析设备树属性
Linux 提供了一系列 API 来解析设备树中的属性信息。常用 API 如下:
API 函数 | 作用 |
---|---|
of_find_node_by_path() | 通过路径查找设备树节点 |
of_find_node_by_name() | 通过名称查找设备树节点 |
of_property_read_u32() | 读取 32-bit 数值类型属性 |
of_property_read_string() | 读取字符串属性 |
of_property_read_bool() | 读取布尔值属性(存在即为 true) |
示例 1:解析 compatible
属性
struct device_node *np;
const char *compat;
np = of_find_node_by_path("/soc/i2c@40066000");
if (np) {if (of_property_read_string(np, "compatible", &compat) == 0) {pr_info("Compatible: %s\n", compat);}
}
说明:
- 通过路径
/soc/i2c@40066000
查找 I2C 设备节点。- 读取
compatible
属性并打印。
4. 完整示例:解析设备树信息并注册字符设备驱动
4.1 设备树节点 (example.dts
)
/example {compatible = "mydevice,example";example_device: example@0 {compatible = "myvendor,mydevice";reg = <0x1000 0x100>;example-property = <42>;example-string = "Hello, Device Tree";};
};
解析:
compatible = "myvendor,mydevice";
:用于驱动匹配。reg = <0x1000 0x100>;
:设备寄存器信息。example-property = <42>;
:自定义数值属性。example-string = "Hello, Device Tree";
:自定义字符串属性。
4.2 内核驱动 (example_driver.c
)
#include <linux/module.h>
#include <linux/platform_device.h>
#include <linux/of.h>static int example_probe(struct platform_device *pdev) {struct device_node *np = pdev->dev.of_node;u32 example_value;const char *example_str;if (!np)return -EINVAL;if (of_property_read_u32(np, "example-property", &example_value) == 0)pr_info("example-property: %d\n", example_value);if (of_property_read_string(np, "example-string", &example_str) == 0)pr_info("example-string: %s\n", example_str);return 0;
}static const struct of_device_id example_of_match[] = {{ .compatible = "myvendor,mydevice" },{},
};
MODULE_DEVICE_TABLE(of, example_of_match);static struct platform_driver example_driver = {.probe = example_probe,.driver = {.name = "example_driver",.of_match_table = example_of_match,},
};
module_platform_driver(example_driver);MODULE_LICENSE("GPL");
MODULE_AUTHOR("Embedded Dev");
MODULE_DESCRIPTION("Example Device Tree Driver");
解析:
example_probe()
:驱动探测函数,解析设备树属性。of_property_read_u32()
和of_property_read_string()
:分别解析example-property
和example-string
。example_of_match
:设备树compatible
匹配表。
4.3 设备树加载与测试
- 编译设备树
dtc -I dts -O dtb -o example.dtb example.dts
- 加载设备树
sudo cp example.dtb /boot/
- 编译并加载驱动
make -C /lib/modules/$(uname -r)/build M=$(pwd) modules sudo insmod example_driver.ko dmesg | grep example
5. 总结
- Linux 通过
struct device_node
解析设备树结构。 - 常用 API 如
of_property_read_u32()
读取设备树属性。 - 设备树
compatible
用于匹配驱动,驱动必须注册of_match_table
。 - 完整示例展示了如何编写标准内核模块并解析设备树信息。
这篇文章提供了一套完整、准确的 Linux 设备树解析方案,希望能帮助你深入理解 Linux 内核如何解析设备树属性!