【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
相关推荐
Johny_Zhao3 小时前
网络安全等级保护测评实施方案
linux·网络·人工智能·网络安全·信息安全·云计算·等保测评·系统运维·itsm
落羽的落羽4 小时前
【AI】快速理解AI应用的相关名词概念
linux·c++·人工智能·python·计算机网络·算法
刚入门的大一新生4 小时前
Linux-进程控制
linux·运维·服务器·c++
上火的金鱼妹4 小时前
K8S基础组件作用和关系整理
linux·运维·服务器·kubernetes
Vcaker5 小时前
Linux学习25-harbor私有仓库部署
linux·运维·学习
刃神太酷啦5 小时前
Redis 进阶核心:持久化 (RDB/AOF)、事务与主从复制全解析----《Hello Redis!》(5)
linux·c语言·数据库·c++·redis·缓存·bootstrap
编程的一拳超人5 小时前
DeepSeek Harness Linux/macOS/Windows 本地下载、启动与模型配置指南
linux·windows·macos·deepseek
时凌云.5 小时前
【2026最新】JDK 下载安装与环境配置全教程(Windows/Mac/Linux 三平台,零基础友好)
java·linux·macos
不懂的浪漫6 小时前
ToDesk 连接 Linux 后分辨率过低的解决方法
linux·运维·数据库
广州灵眸科技有限公司6 小时前
从手动三步到上电即连:4G模组systemd开机自连方案
linux·运维·服务器·开发语言·网络·人工智能·php