最近移植接触 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
通过注释发现,判断一个设备树节点是否【使能】,条件为:
status
属性,属性值是 “ok” 或 “okay”,则表示节点使能status
属性,依旧认为 此设备树节点使能。&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