【Linux 源码阅读记录】设备树解析 of 相关代码
前言
-
最近移植接触 Linux 的设备树解析相关的代码,对 Linux of (open firmware)设备树解析代码比较感兴趣。
-
可以通过阅读Linux 大量的优秀代码,增强一些编程与编码的技巧与经验
切入点
-
of_device_is_available
:设备树节点是否可用,源码位置drivers\of\base.c
-
代码如下:
/**
* of_device_is_available - check if a device is available for use
*
* @device: Node to check for availability
*
* Returns true if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
bool of_device_is_available(const struct device_node *device)
{
unsigned long flags;
bool res;
raw_spin_lock_irqsave(&devtree_lock, flags);
res = __of_device_is_available(device);
raw_spin_unlock_irqrestore(&devtree_lock, flags);
return res;
}
-
代码调用流程:
of_device_is_available
调用了__of_device_is_available
-
通过注释发现,判断一个设备树节点是否【使能】,条件为:
- (1)如果有
status
属性,属性值是 “ok” 或 “okay”,则表示节点使能 - (2)如果没有
status
属性,依旧认为 此设备树节点使能。
- (1)如果有
示例
&watchdog0 {
status = "disable";
};
&watchdog1 {
status = "okay";
};
&pcie_vnet0 {
status = "ok";
extend-op = <16>;
memory-region = <&pcie_ctrl_reserved>;
};
&i2s0 {
status = "disable";
};
&i2s1 {
status = "disable";
};
- 此时
watchdog0
与watchdog1
pcie_vnet0
均使能,而i2s0
与i2s1
节点由于status = "disable";
,不使能。
__of_device_is_available
的实现代码
/**
* __of_device_is_available - check if a device is available for use
*
* @device: Node to check for availability, with locks already held
*
* Returns true if the status property is absent or set to "okay" or "ok",
* false otherwise
*/
static bool __of_device_is_available(const struct device_node *device)
{
const char *status;
int statlen;
if (!device)
return false;
status = __of_get_property(device, "status", &statlen);
if (status == NULL)
return true;
if (statlen > 0) {
if (!strcmp(status, "okay") || !strcmp(status, "ok"))
return true;
}
return false;
}
- 调用了
__of_get_property
去获取【查找】是否存在status
属性,一个设备树节点,可以有多个属性
&i2c1 {
status = "okay";
clock-frequency = <1000000>;
};
-
以上 设备树节点
i2c1
有两个属性, 一个属性是status
,另一个属性是clock-frequency
,属性就是一个key = value
键值对 -
代码其实很精简,如果没有
status
属性,就返回 TRUE,也就是认为【节点使能】 -
如果 有
status
属性,并且属性值 为okay
或者ok
,节点使能 -
两种情况之外,就是 【节点不使能】,一般是
status = "disable";
__of_get_property
的实现
-
设备树匹配,本质上大部分是字符串的比较。比如
strcmp
函数的大量使用 -
确认是否存在
status
属性的设备树节点,使用__of_get_property
,代码如下
/*
* Find a property with a given name for a given node
* and return the value.
*/
const void *__of_get_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp = __of_find_property(np, name, lenp);
return pp ? pp->value : NULL;
}
-
发现又套了一层,实现函数为
__of_find_property
,这里 get 改为了find
,也就是搜索与查找 -
功能函数的封装,让代码看起来更紧凑,代码功能模块化
__of_find_property
的实现:最底层的匹配
static struct property *__of_find_property(const struct device_node *np,
const char *name, int *lenp)
{
struct property *pp;
if (!np)
return NULL;
for (pp = np->properties; pp; pp = pp->next) {
if (of_prop_cmp(pp->name, name) == 0) {
if (lenp)
*lenp = pp->length;
break;
}
}
return pp;
}
-
查看代码,这里有两个操作, 一个设备树节点,有多个属性对,而每个属性对就是
key=value
这样的,一般设备树编写时,不需要增加【双引号】或者【单引号】,毕竟是文本格式处理。 -
变量设备树的各个属性,是个【单链表】,然后通过
of_prop_cmp
进行匹配,匹配成功,就返回【设备树】节点属性的指针,匹配失败,会返回空指针
of_prop_cmp
的实现
-
源码位置
include\linux\of.h
-
#define of_prop_cmp(s1, s2) strcmp((s1), (s2))
,这里就是 字符串比较函数strcmp
,比对成功,就是返回 0,比对失败,就返回非0
小结
-
通过属性设备树节点的基本操作,了解到 设备树节点 属性的解析与搜索流程,整个实现非常的巧妙,编码也非常的精简,阅读这样的代码,有一种美的享受,并且日积月累,可以提高代码分析与增强编码能力。
-
当前的调用关系,通过层层封装,让每个实现函数看起来都比较的干练与精致。
of_device_is_available
-> __of_device_is_available
-> __of_get_property
-> __of_find_property
-> of_prop_cmp
-> strcmp