深入解析 Linux 内核如何解析和获取设备树属性
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 内核如何解析设备树属性!