• 【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;
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 代码调用流程: of_device_is_available 调用了 __of_device_is_available

    • 通过注释发现,判断一个设备树节点是否【使能】,条件为:

      • (1)如果有 status 属性,属性值是 “ok” 或 “okay”,则表示节点使能
      • (2)如果没有 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";
    };
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 此时 watchdog0watchdog1 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 调用了 __of_get_property 去获取【查找】是否存在 status 属性,一个设备树节点,可以有多个属性
    &i2c1 {
        status = "okay";
        clock-frequency = <1000000>;
    };
    
    • 1
    • 2
    • 3
    • 4
    • 以上 设备树节点 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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 发现又套了一层,实现函数为 __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;
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 查看代码,这里有两个操作, 一个设备树节点,有多个属性对,而每个属性对就是 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
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
  • 相关阅读:
    外包干了2个月,技术退步明显。。。。。
    React Native验证码图片设计(验证码图片使用的是同一个链接)
    从数据库设计到性能调优,全面掌握openGemini应用开发最佳实践
    驱动day8
    散列表查找技术(数据结构)
    Flink之状态管理
    计算机毕业设计ssm二手房纪经人房屋管理系统85bvk系统+程序+源码+lw+远程部署
    【博学谷学习记录】超强总结,用心分享丨大数据超神之路(五):Hadooop进阶版
    【MySQL系列】Java的JDBC编程
    npm i 报错或者卡顿 range manifest for 解决
  • 原文地址:https://blog.csdn.net/tcjy1000/article/details/134519358