【Linux 源码阅读记录】设备树解析 of 相关代码

前言

  • 最近移植接触 Linux 的设备树解析相关的代码,对 Linux of (open firmware)设备树解析代码比较感兴趣。

  • 可以通过阅读Linux 大量的优秀代码,增强一些编程与编码的技巧与经验

切入点

  • of_device_is_available :设备树节点是否可用,源码位置 drivers\of\base.c

  • 代码如下:

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 属性,依旧认为 此设备树节点使能。

示例

c 复制代码
&watchdog0 {
    status = "disable";
};
&watchdog1 {
    status = "okay";
};
&pcie_vnet0 {
    status = "ok";
    extend-op = <16>;
    memory-region = <&pcie_ctrl_reserved>;
};
&i2s0 {
    status = "disable";
};

&i2s1 {
    status = "disable";
};
  • 此时 watchdog0watchdog1 pcie_vnet0 均使能,而 i2s0 i2s1 节点由于 status = "disable";,不使能。

__of_device_is_available 的实现代码

c 复制代码
/**
 *  __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 属性,一个设备树节点,可以有多个属性
c 复制代码
&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,代码如下

c 复制代码
/*
 * 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 的实现:最底层的匹配

c 复制代码
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

小结

  • 通过属性设备树节点的基本操作,了解到 设备树节点 属性的解析与搜索流程,整个实现非常的巧妙,编码也非常的精简,阅读这样的代码,有一种美的享受,并且日积月累,可以提高代码分析与增强编码能力。

  • 当前的调用关系,通过层层封装,让每个实现函数看起来都比较的干练与精致。

c 复制代码
of_device_is_available  
	->  __of_device_is_available  
		->  __of_get_property  
			->  __of_find_property  
				->  of_prop_cmp
					-> strcmp
相关推荐
无泪无花月隐星沉12 小时前
uos server 1070e lvm格式磁盘扩容分区
linux·运维·uos
食咗未12 小时前
Linux USB HOST EXTERNAL STORAGE
linux·驱动开发
食咗未12 小时前
Linux USB HOST HID
linux·驱动开发·人机交互
Xの哲學12 小时前
Linux SLAB分配器深度解剖
linux·服务器·网络·算法·边缘计算
齐鲁大虾13 小时前
UOS(统信操作系统)如何更新CUPS(通用Unix打印系统)
linux·服务器·chrome·unix
虾..14 小时前
Linux 简单日志程序
linux·运维·算法
huoxingwen15 小时前
Ubuntu 22.04 上 VMware Workstation 点击虚拟机窗口就消失的解决历程
linux·运维·ubuntu
姚青&16 小时前
Linux 常用命令之基本命令
linux·运维·服务器
一路往蓝-Anbo16 小时前
【第05期】数据的微观世界 (五) —— 浮点数 vs 定点数:MCU的数学课
linux·stm32·单片机·嵌入式硬件·物联网
G_H_S_3_16 小时前
【网络运维】企业级监控平台Zabbix:部署与实践指南
linux·运维·网络·zabbix