设备树节点概述

设备树的概述
2.1、参考资料
内核源码目录Documentation\devicetree设备树说明文档
内核源码drivers/of/源码分析
2.2、基本概念
设备树是描述软/硬件信息的,包含节点和属性的一个树形结构。节点用以归类描述了一个硬件信息或是软件信息(好比文件系统的目录)。节点内描述了一个或多个属性,属性是键值对,描述具体的软/硬信息。简单形式如下:
/{
node{
property=value;
...
child_node{
child_property=value;
...
};
...
};
...
};
说明如下:
/:根节点,节点使用“{};”的语法描述作用范围
node:根节点下的一个子节点
child_node:node节点下的一个子节点
property:node节点内描述的属性,value就是属性的值(任意字节数据,可以是整型、字符串、数组、等等)。描述行以“;”结束
2.3、存储形式
在《ARM Linux社区为什么要引入设备树》中,已经讨论过设备树的使用方式。简而言之:内核初始化时,以配置的文件形式读取设备树文件的内容,并解析后生成相应的软/硬件信息,以供相应的内核代码使用。
编写设备树文件是以.dts的文本文件存储的,主要是为了修改、添加编辑方便。
那么问题来了,如果纯文本解析的话,显然比较慢且麻烦。譬如如果属性值是一个I/O地址:0x80000000,如果是字符串的形式存储,那么“0x80000000”就是一个字符串,内核代码解析这个信息的时候还得转换成整型数,不仅仅是慢,无形设备树文件大小还会增加不少,还得增加更多的初始化代码。
所以.dts的设备树文件,在内核使用前需要转换一次,主要是把繁复的语法形式及属性值转换成字节数据(特殊的数据结构),而非符号。.dts文件转换后是.dtb的二进制文件。
3、节点
3.1、命名
节点的命名以字母、数字、_、等等符号构成。常见的命令方式如下:
A、以“设备名”为节点名,范例:
DM9000命名如下:
/{
...
dm9000{
...
};
...
};
B、以“设备@I/O地址”为“节点名@I/O地址”,范例:
DM9000在主机端的I/O地址为0x8000 0000,可以命名如下:
/{
...
dm9000@80000000{
...
};
...
};
C、以“设备类型@I/O地址”为“节点名@I/O地址”,范例:
DM9000在主机端的I/O地址为0x8000 0000,可以命名如下:
/{
...
ethernet@80000000{
...
};
...
};
3.2、节点路径
A、
/{
...
dm9000{
...
};
...
};
节点名:dm9000
节点路径:/dm9000
B、
/{
...
dm9000@80000000{
...
};
...
};
节点名:dm9000
节点路径:/dm9000@80000000
C、
/{
...
ethernet@80000000{
...
};
...
};
节点名:ethernet
节点路径:/ethernet@80000000
3.3、节点引用
/{
aliases {
demo = &demo;
};
...
demo:demo@80000000{
...
};
...
};
节点名:demo
节点路径:/demo@80000000
引用路径:demo(等价/demo@80000000,解决路径名过程的问题)
设备树中引用节点“/demo@80000000”的范例:
&demo{
...
};
3.4、节点查找
有时候,分享内核代码或是编写内核代码的时候,可能会涉及使用查找节点函数。内核提供很多内核函数来查找(解析设备树)一个指定节点:
A、路径查找
/*
* 功能:通过路径查找指定节点
* 参数:
* const char *path - 节点路径,可以是路径,也可以是路径引用
* 返回值:
* 成功:得到节点对象的首地址;失败:NULL
*/
struct device_node *of_find_node_by_path(const char *path);
B、节点名查找
/*
* 功能:通过节点名查找指定节点
* 参数:
* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始
* const char *name- 节点名
* 返回值:
* 成功:得到节点对象的首地址;失败:NULL
*/
struct device_node *of_find_node_by_name(struct device_node *from, const char *name);
C、通过compatible属性查找
/*
* 功能:通过compatible属性查找指定节点
* 参数:
* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始
* const char *type - 节点类型,可以为NULL
* const char *compat - 指向节点的compatible属性的值(字符串)的首地址
* 返回值:
* 成功:得到节点对象的首地址;失败:NULL
*/
struct device_node *of_find_compatible_node(struct device_node *from,
const char *type, const char *compat);
设备ID表结构
struct of_device_id {
char name[32]; /*设备名*/
char type[32]; /*设备类型*/
char compatible[128]; /*用于与设备树compatible属性值匹配的字符串*/
const void *data; /*私有数据*/
};
/*
* 功能:通过compatible属性查找指定节点
* 参数:
* struct device_node *from - 指向开始路径的节点,如果为NULL,则从根节点开始
* const struct of_device_id *matches - 指向设备ID表
* 注意ID表必须以NULL结束
* 范例: const struct of_device_id mydemo_of_match[] = {
{ .compatible = "fs4412,mydemo", },
{}
};
* 返回值:
* 成功:得到节点对象的首地址;失败:NULL
*/
struct device_node *of_find_matching_node(struct device_node *from,
const struct of_device_id *matches);
D、查找子节点
/*
* 功能:查找指定节点的子节点
* 参数:
* const struct device_node *node - 指向要查找子节点的父节点
* const char *name - 子节点名
* 返回值:
* 成功:得到子节点对象的首地址;失败:NULL
*/
struct device_node *of_get_child_by_name(const struct device_node *node,
const char *name);
3.5、节点内容合并
有时候,一个硬件设备的部分信息不会变化,但是部分信息是可能会变化的,就出现了节点内容合并。即:先编写好节点,仅仅描述部分属性值;使用者后加一部分属性值。
在同级路径下,节点名相同的“两个”节点实际是一个节点。
/*参考板的已经编写好的node节点*/
/{
node{
item1=value;
};
};
/*移植者添加的node节点*/
/{
node{
item2=value;
};
};
等价于:
/{
node{
item1=value;
item2=value;
};
};
3.6、节点内容替换
有时候,一个硬件设备的部分属性信息可能会变化,但是设备树里面已经描述了所有的属性值,使用者可以添加已有的属性值,以替换原有的属性值,就出现了节点内容替换。
另外,节点的内容即使不会变化,但是可能不会使用。
在同级路径下,节点名相同的“两个”节点实际是一个节点。
内容替换的常见形式之一:
/*参考板的已经编写好的node节点*/
/{
node{
item=value1;
};
};
/*移植者添加的node节点*/
/{
node{
item=value2;
};
};
等价于:
/{
node{
item=value2;
};
};
内容替换的常见形式之二:
/*参考板的已经编写好的node节点*/
/{
node{
item=value;
status = "disabled";
};
};
/*移植者添加的node节点*/
/{
node{
status = "okay";
};
};
等价于:
/{
node{
item=value;
status = "okay";
};
};
3.7、节点内容引用
有时候,一个节点需要使用到别的节点的属性值,就需要引用的概念。有时候在设备树编写时,要替换节点属性值,或是合并节点的属性值,也会使用引用。
A、引用节点完成属性值的替换及合并:
/*参考板的已经编写好的node节点*/
/{
node:node@80000000{
item1=value;
status = "disabled";
};
};
/*移植者添加的node节点*/
&node{
item2=value;
status = "okay";
};
等价于:
/{
node : node@80000000{
item1=value;
item2=value;
status = "okay";
};
};
B、节点引用另一个节点:
/*参考板的已经编写好的node节点*/
/{
node:node@80000000{
item=value;
};
};
/*移植者添加的demo节点*/
/{
demo{
item=<&node>;
};
};
说明:
demo节点的属性item引用了节点的node的属性值,具体怎么使用node节点的属性值,在属性章节进行讨论。

 

你可能感兴趣的:(linux,驱动)