深入解析 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-propertyexample-string
  • example_of_match:设备树 compatible 匹配表。

4.3 设备树加载与测试

  1. 编译设备树
    dtc -I dts -O dtb -o example.dtb example.dts
    
  2. 加载设备树
    sudo cp example.dtb /boot/
    
  3. 编译并加载驱动
    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 内核如何解析设备树属性!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值