前言
-
不得不说,当前新版本的 Linux 内核 设备驱动框架,与设备树(Device Tree)结合密切,整体 设备树的设备驱动框架,比较的庞大,但又非常的经典。
-
一个个的 设备树解析函数,都是前人【智慧】的结晶,了解 设备树的实现,了解设备树的解析,对Linux 设备驱动开发非常有利,并且可以大大提高开发编码能力
-
虽然Linux 内核庞大、开源,但是Linux 内核各个模块的实现都是经典,非常适合学习深造
设备树展开
-
设备树源文件(dts)与 设备树头文件(dtsi),通过 dtc 工具生成了 设备树二进制文件 (dtb)
-
设备树二进制文件(dtb)经过展开(反扁平化)成设备树结构在内存中。
-
可以通过 设备树 root 根节点,通过 设备节点的属性(property)、设备树节点的名称(name)或者路径(full_name)找到相应的设备树节点。
-
设备树节点类似树的【树枝或者树叶】,【树枝】下面还可以有多个子节点,或者只有叶子节点。
-
设备树整体像个 【家族族谱】,内核实现使用多级的链表,把各个设备树节点连接起来。
设备树节点
-
对于每个设备树节点,数据结构
struct device_node
表示如下 -
include\linux\of.h
中
struct device_node {
const char *name;
phandle phandle;
const char *full_name;
struct fwnode_handle fwnode;
struct property *properties;
struct property *deadprops; /* removed properties */
struct device_node *parent;
struct device_node *child;
struct device_node *sibling;
#if defined(CONFIG_OF_KOBJ)
struct kobject kobj;
#endif
unsigned long _flags;
void *data;
#if defined(CONFIG_SPARC)
unsigned int unique_id;
struct of_irq_controller *irq_trans;
#endif
};
- 看起来很复杂,其实多看几次(熟悉),发现并没有想象中的复杂,了解过 JSON 的大概看设备树节点也不会太吃力。
- 本篇重点关注
dma-coherent;
这样的设备树节点的 属性(property)如何用于解析,也就是判断这个属性是否存在,通过of_property_read_bool
函数
设备树节点与设备树节点属性 property 的组织方式
-
单链表的结构组织,如果有了设备树节点的指针,就可以遍历这个设备树节点下的所有属性 property
-
注意这个设备树与设备树节点属性的组织关系,实在设备树 dtb 载入后,反扁平化
unflatten_device_tree
后形成的,也就是现成的,用于解析与判断匹配,比如 属性的查找,就是一直单链表遍历查找即可 -
drivers\of\base.c
–__of_find_property
的属性查找
- 设备树节点 与 设备树 自身的各个属性,采用 单链表 的结构串起来
of_property_read_bool 的实现原理
-
对于一个设备树节点,属性可以有很多,大部分都是 键值对结构,也有的属性只有 属性名,没有 value
-
设备树节点的属性(这里使用类似单链表结构),挂在对应的设备树节点上,
-
struct device_node
的成员struct property *properties;
-
struct property
有个成员struct property *next;
struct property {
char *name;
int length;
void *value;
struct property *next;
#if defined(CONFIG_OF_DYNAMIC) || defined(CONFIG_SPARC)
unsigned long _flags;
#endif
#if defined(CONFIG_OF_PROMTREE)
unsigned int unique_id;
#endif
#if defined(CONFIG_OF_KOBJ)
struct bin_attribute attr;
#endif
};
-
设备树节点 有个 属性的 头结点,这个设备树节点下的属性,以单链表的结构链上去。就像是【糖葫芦】,访问设备树节点时,需要依次【遍历】与匹配(比对)
-
了解了 设备树节点与属性,
of_property_read_bool
的工作原理也就清楚了,只需要判断设备树是否有这个属性即可 -
of_property_read_bool
入参:const struct device_node *np
是一个设备树节点指针 -
const char *propname
如此:设备树是否存在的属性 property 的 name,字符串 -
of_find_property
之前了解过,就是单链表的方式遍历,查找是否存在 property
/**
* of_property_read_bool - Find a property
* @np: device node from which the property value is to be read.
* @propname: name of the property to be searched.
*
* Search for a property in a device node.
* Returns true if the property exists false otherwise.
*/
static inline bool of_property_read_bool(const struct device_node *np,
const char *propname)
{
struct property *prop = of_find_property(np, propname, NULL);
return prop ? true : false;
}
of_property_read_bool 的用法
- 比如
drivers\of\address.c
中 的:
bool of_dma_is_coherent(struct device_node *np)
{
struct device_node *node;
if (IS_ENABLED(CONFIG_OF_DMA_DEFAULT_COHERENT))
return true;
node = of_node_get(np);
while (node) {
if (of_property_read_bool(node, "dma-coherent")) {
of_node_put(node);
return true;
}
node = of_get_next_dma_parent(node);
}
of_node_put(node);
return false;
}
-
这里判断是否存在
dma-coherent
属性 -
这里还说明了设备树节点有父子兄弟这样的关系,比如父节点或者祖父节点有这个属性,依旧可以认为这个属性存在。
-
有些设备树节点属性【继承】了上级或者上上级的属性。
-
真实的设备树节点,父子兄弟关系并没有想象中的那样复杂,大多就三到四级。
疑问
-
设备树节点 property 为何可以直接遍历查找
-
【答】这得多亏了 设备树 dtc 工具与 设备树 【反扁平化】操作,这个设备树 dtb 不是直接像普通文件读取到内存的,需要通过
unflatten_device_tree
,梳理并把各个设备树节点,组织成设备树结构。类似于 dtb 是一箱水果,需要分门别类,比如按价钱等摆到各自的摊位上,方便大家挑选与购买。
小结
- 设备树解析部分,其实就是解析【现成】的应经 设备树化后的 各个有组织次序的 设备树。所以操作起来类似于链表的节点查找,字符串比较,没有那么的难