设备树:描述设备信息的一种树状方式。在linux内核的3.10版本前并没有使用
设备树这种方式描述设备信息,而是通过文件的方式描述设备信息。在3.10内核版本
出现前利纳斯托瓦斯要求ARM社区整改设备信息的表述方式。ARM社区参考POWER PC设备
信息表述方式,引入了设备树。所以在3.10的内核版本之后所有ARM的内核表示设备信息
的方式都使用设备树。
dts -------------*.c
dtsi -------------*.h
|
DTC
|
--------------*.dtb
设备树(Device Tree)是一种描述硬件的数据结构,在操作系统(OS)引导阶段进行设
备初始化(DTB文件在linux内核启动的时候内核解析),解析之后设备树就被放到内存在上
(逻辑结构:树状结构)。如果某个驱动需要使用设备信息,直接从设备树上获取对应的
设备信息即可。
参考:https://elinux.org/Device_Tree_Usage
设备树是节点和属性的简单树结构。属性是键值对,节点可能同时包含属性和子节点。
[@ ]
| |
节点名(设备类,最多31个字符) 设备的地址
eg1:
serial@101f1000{};
设备树中同名的节点会被合并(相同的键值会覆盖前面的值,不同的键合并到一个节点中)
节点可以取别名,node2就是mynode2的别名
方式1:
node2:mynode2@aabbccdd{
key1=“val1”;
};
方式2:
aliases {
node2= &mynode2@aabbccdd;
};
节点的引用(引用的节点需要放在根节点外)
&node2{
};
•
文本字符串(以空结尾)用双引号表示:
•
string-property = “a string”;
•
‘Cells’ 是由尖括号分隔的 32 位无符号整数:
•
cell-property = <0xbeef 123 0xabcd1234>;
•
二进制数据用方括号分隔(单字节的16进制表示形式):
•
binary-property = [01 23 45 67];
•
不同表示的数据可以使用逗号连接在一起:
•
mixed-property = “a string”, [0x01 0x23 0x45 0x67], <0x12345678>;
mynode@0x12345678{
string = “DC22041 everyone!!”;
uint = <0x11223344 0xaabbccdd>;
macaddr=[00 0c 29 7b f9 be];
mixed = “hello”,<0x112233>,[aa cc 00 12];
};
将上述的设备节点放在arch/arm/boot/dts/stm32mp157a-fsmp1a.dts
cp arch/arm/boot/dts/stm32mp157a-fsmp1a.dtb ~/tftpboot/
设备节点结构体:
struct device_node { //每个节点都会对应一个device_node结构体,它在内核中是树状结构
const char *name; // 节点的名称
const char *full_name; //节点全名
struct property *properties; // 属性健值对
...
};
属性结构体:
struct property {
char *name; // 键的名称
int length; //值的长度
void *value; // 键的值
struct property *next; // 单链表
};
查找节点API
struct device_node *of_find_node_by_path(const char *path)
功能:通过节点的路径,查找到节点
参数:
@path -节点的路径 "/mynode@0x12345678"
返回值: 成功:设备节点的地址
失败:NULL
struct device_node *of_find_node_by_name(struct device_node *from,
const char *name)
功能:通过节点名查找指定节点
参数:
@from - 开始查找节点,如果为NULL,则从根节点开始
@name - 节点名
返回值:成功:得到节点的首地址
失败:NULL
获取属性
struct property *of_find_property(const struct device_node *np,
const char *name,int *lenp)
功能:已知设备节点的地址,根据键的名称,查找出键值
参数:
@np -设备节点的地址
@name -键的名称
@lenp -获取到的值的字符串长度
返回值:成功 属性健值对的指针
出错 NULL
static inline int of_property_read_u8_array(const struct device_node *np,
const char *propname, u8 *out_values, size_t sz)
功能: 得到属性值中指定标号的8位数组的值
参数:
@np - 设备节点指针
@propname - 属性名称
@out_values- 输出数据的首地址
@sz - 成员个数
返回值: 成功返回0,出错错误码
int of_property_read_u32_array(const struct device_node *np,
const char *propname,
u32 *out_values, size_t sz)
功能: 得到属性值中指定标号的32位数组的值
参数:
@np - 设备节点指针
@propname - 属性名称
@out_values- 输出数据的首地址
@sz - 成员个数
返回值: 成功返回0,出错错误码
int of_property_read_string(struct device_node *np, const char *propname,
const char **out_string)
功能:已知字符串属性健值对的名称,得到字符串的值
参数:
np -设备节点的地址
propname -属性健值对的名称
out_string -填充字符串的值
返回值:成功0,出错错误码
#include
#include
#include
/*
mynode@0x12345678{
string = "DC22041 everyone!!";
uint = <0x11223344 0xaabbccdd>;
macaddr=[00 0c 29 7b f9 be];
mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
static int __init mynode_init(void)
{
//通过路径获取节点
node = of_find_node_by_path("/mynode@0x12345678");
if (node == NULL) {
printk("get node error\n");
return -ENODATA;
}
printk("name=%s,value = %s\n", node->properties->name,
(char*)node->properties->value);
printk("name=%s,value1 = %#x,value2=%#x\n", node->properties->next->name,
__be32_to_cpup(node->properties->next->value),
__be32_to_cpup(node->properties->next->value+4));
//__be32_to_cpup:将大端转化为小端(32bit)
return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
#include
#include
#include
/*
mynode@0x12345678{
string = "DC22041 everyone!!";
uint = <0x11223344 0xaabbccdd>;
macaddr=[00 0c 29 7b f9 be];
mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
struct property *p;
static int __init mynode_init(void)
{
int len,i;
//通过路径获取节点
node = of_find_node_by_path("/mynode@0x12345678");
if (node == NULL) {
printk("get node error\n");
return -ENODATA;
}
p = of_find_property(node,"mixed",&len);
if(p == NULL){
printk("get property error\n");
return -ENODATA;
}
printk("%s\n",(char *)p->value);
printk("%#x\n",__be32_to_cpup(p->value+6));
for(i=0;i<4;i++){
printk("%#x\n",*(unsigned char *)(p->value+10+i));
}
return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
#include
#include
#include
/*
mynode@0x12345678{
string = "DC22041 everyone!!";
uint = <0x11223344 0xaabbccdd>;
macaddr=[00 0c 29 7b f9 be];
mixed = "hello",<0x112233>,[aa cc 00 12];
};
*/
struct device_node* node;
struct property* p;
static int __init mynode_init(void)
{
int i;
const char* out_string;
u32 d32[2];
u8 d8[6];
//通过路径获取节点
node = of_find_node_by_path("/mynode@0x12345678");
if (node == NULL) {
printk("get node error\n");
return -ENODATA;
}
of_property_read_string(node, "string", &out_string);
printk("string = %s\n", out_string);
of_property_read_u32_array(node, "uint", d32, 2);
for (i = 0; i < 2; i++) {
printk("uint[%d] = %#x\n", i, d32[i]);
}
of_property_read_u8_array(node, "macaddr", d8, 6);
for (i = 0; i < 6; i++) {
printk("macaddr[%d] = %#x\n", i, d8[i]);
}
return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");
for (i = 0; i < 2; i++) {
printk("uint[%d] = %#x\n", i, d32[i]);
}
of_property_read_u8_array(node, "macaddr", d8, 6);
for (i = 0; i < 6; i++) {
printk("macaddr[%d] = %#x\n", i, d8[i]);
}
return 0;
}
static void __exit mynode_exit(void)
{
}
module_init(mynode_init);
module_exit(mynode_exit);
MODULE_LICENSE("GPL");