1.概要
2.内容
设备树(Device Tree,简称DT)是一种易于阅读的硬件描述文件,用于描述硬件设备的信息,如硬件配置、设备连接关系等。在Linux内核中,设备树被广泛应用,特别是在嵌入式系统中。设备树节点是设备树的基本组成单元,每个节点代表一个硬件设备或设备的一部分。访问设备树节点通常涉及以下几种方式:
一、节点标识和引用
-
节点标识:在C/C++中访问设备树节点需要引用节点标识,节点标识本身不是一个值,不能够使用变量进行保存。
-
节点标识的获取方式:
- DT_PATH(path, node_name):通过节点的完整路径进行引用。
- DT_ALIAS(alias):通过查找/aliases下的同名节点进行引用。
- DT_NODELABEL(label):通过节点标签进行引用。
- DT_INST(x, vnd_soc_i2c):通过实例号和节点中的compatible进行引用。x代表实例编号,vnd_soc_i2c为compatible对应值(属性中的非字母和数字字符会被替换成下划线,大写字母也会全部替换成小写)。实例号以0为开始,为当设备树中有多个节点存在相同属性时候,设备树会对这些节点进行编号,包括未使能的节点,但是具体哪一个设备会分配哪一个实例号,这是不确定的,能确定的是未使能的节点排在使能节点之后。
- DT_CHOSEN(node_name):通过查找/chosen下的同名节点进行引用。
- DT_PARENT(node)/DT_CHILD(node):通过当前节点索引父节点和子节点。
二、设备树API
在Linux内核中,提供了一套标准的API来访问和操作设备树节点及其属性。这些API通常定义在<linux/of.h>
和<linux/of_device.h>
头文件中。以下是一些常用的设备树访问API:
-
查找节点:
- of_find_node_by_path(const char *path):根据节点路径查找节点。
- of_find_node_by_name(struct device_node *from, const char *name):从指定节点开始,查找具有指定名称的子节点。
- of_find_node_by_type(struct device_node *from, const char *type):从指定节点开始,查找具有指定类型的子节点。
-
获取节点属性:
- of_find_property(const struct device_node *np, const char *name, int *lenp):查找节点中的属性。
- of_property_read_u32(const struct device_node *np, const char *propname, u32 *out_value):读取一个32位无符号整数属性。
- of_property_read_u32_array(const struct device_node *np, const char *propname, u32 *out_values, size_t sz):读取一个32位无符号整数数组属性。
- **of_property_read_string(struct device_node *np, const char *propname, const char out_string):读取一个字符串属性。
-
内存映射:
- of_iomap(struct device_node *node, int index):将节点reg属性中的内存地址直接映射到虚拟地址。
三、设备树节点路径和别名
- 节点路径:在设备树中,每个节点都有一个唯一的路径,从根节点开始,通过节点名逐级访问到目标节点。
- 别名(Aliases):为了方便访问节点,设备树中可以使用别名节点来定义节点的别名。别名节点通常位于设备树的顶层或者与chosen节点并列。通过别名,可以简化设备节点之间的连接关系描述,提高可读性和可维护性。
四、示例
假设有一个I2C设备节点,其名称为eeprom@50
,位于I2C总线节点/soc/i2c@021a0000
下。要访问这个设备节点,可以使用以下方法:
-
通过完整路径访问:
struct device_node *node = of_find_node_by_path("/soc/i2c@021a0000/eeprom@50");
-
通过别名访问(如果定义了别名):
struct device_node *node = of_find_node_by_alias("eeprom");
-
获取节点属性:
const char *compatible; if (of_property_read_string(node, "compatible", &compatible) == 0) { printk(KERN_INFO "Compatible: %s\n", compatible); }
通过以上方法,可以方便地在Linux内核中访问和操作设备树节点及其属性。