zoukankan      html  css  js  c++  java
  • 【u-boot】u-boot对设备树的节点解析(转)

    1,设备树的引入
    2,uboot本身对设备树的支持
    3,对uboot中设备树节点解析代码的分析

    (1)上一篇文章中提到函数 dm_init_and_scan(bool pre_reloc_only) 中有对设备树节点解析的函数dm_extended_scan_fdt()该函数的主要作用就是扫描设备树中的节点,并创立对应的设备驱动等结构的绑定工作。
    先看对应的代码

    int dm_extended_scan_fdt(const void *blob, bool pre_reloc_only)
    {
        ret = dm_scan_fdt(gd->fdt_blob, pre_reloc_only);
        //顾名思义,该函数就是扫描设备树并与设备驱动建立联系
        ret = dm_scan_fdt_ofnode_path("/clocks", pre_reloc_only);
        ret = dm_scan_fdt_ofnode_path("/firmware", pre_reloc_only);
        //上面这两个该函数扫描clocks节点和firmware节点
    }

    重点看第一个函数的具体实现过程

    int dm_scan_fdt(const void *blob, bool pre_reloc_only)
    {
    #if CONFIG_IS_ENABLED(OF_LIVE)
        if (of_live_active())
            return dm_scan_fdt_live(gd->dm_root, gd->of_root,
                        pre_reloc_only);
        else
    #endif
        return dm_scan_fdt_node(gd->dm_root, blob, 0, pre_reloc_only);
    }

    由于没有定义OF_LIVE宏,所以该函数最终调用的是dm_scan_fdt_node函数,那么接下来看该函数的实现过程

    tatic int dm_scan_fdt_node(struct udevice *parent, const void *blob,
                    int offset, bool pre_reloc_only)
    {
        int ret = 0, err;
        //从偏移offset处开始一个个的扫描节点(node)
        for (offset = fdt_first_subnode(blob, offset); offset > 0; offset = fdt_next_subnode(blob, offset))
            {
            const char *node_name = fdt_get_name(blob, offset, NULL);
             /*chosen或者firmware节点本身不是一个设备,但是有可能包含其他设备节点,
             扫描其子节点*/
            if (!strcmp(node_name, "chosen") ||
                !strcmp(node_name, "firmware")) {
                pr_debug("parsing subnodes of "%s" ", node_name);

                err = dm_scan_fdt_node(parent, blob, offset,
                               pre_reloc_only);
                if (err && !ret)
                    ret = err;
                continue;//没有子节点的话则继续扫描下一个节点
            }

            if (!fdtdec_get_is_enabled(blob, offset)) {//忽略失能设备
                pr_debug("   - ignoring disabled device ");
                continue;
            }
            err = lists_bind_fdt(parent, offset_to_ofnode(offset), NULL,
                         pre_reloc_only);
            if (err && !ret) {
                ret = err;
                debug("%s: ret=%d ", node_name, ret);
            }
        }

        if (ret)
            dm_warn("Some drivers failed to bind ");

        return ret;
    }

    int lists_bind_fdt(struct udevice *parent, ofnode node, struct udevice **devp,
               bool pre_reloc_only)
    {
        struct driver *driver = ll_entry_start(struct driver, driver);
        const int n_ents = ll_entry_count(struct driver, driver);
        const struct udevice_id *id;
        struct driver *entry;
        struct udevice *dev;
        bool found = false;
        const char *name, *compat_list, *compat;
        int compat_length, i;
        int result = 0;
        int ret = 0;

        if (devp)
            *devp = NULL;
        name = ofnode_get_name(node);
        pr_debug("bind node %s ", name);

        compat_list = ofnode_get_property(node, "compatible", &compat_length);
        if (!compat_list) {
            if (compat_length == -FDT_ERR_NOTFOUND) {
                pr_debug("Device '%s' has no compatible string ",
                     name);
                return 0;//这里直接返回,设备能bind的话,需要设备节点有 compatible 属性
            }

            dm_warn("Device tree error at node '%s' ", name);
            return compat_length;
        }
         //遍历compatible 字符串列表
        for (i = 0; i < compat_length; i += strlen(compat) + 1) {
            compat = compat_list + i;
            pr_debug("   - attempt to match compatible string '%s' ",
                 compat);

            for (entry = driver; entry != driver + n_ents; entry++) {
                ret = driver_check_compatible(entry->of_match, &id,
                                  compat);
                if (!ret)//遍历driver段表,找到相对应的driver
                    break;
            }
            if (entry == driver + n_ents)
                continue;

            if (pre_reloc_only) {
                if (!dm_ofnode_pre_reloc(node) &&
                    !(entry->flags & DM_FLAG_PRE_RELOC))
                    return 0;
            }

            pr_debug("   - found match at '%s' ", entry->name);
            ret = device_bind_with_driver_data(parent, entry, name,
                               id->data, node, &dev);
            if (ret == -ENODEV) {
                pr_debug("Driver '%s' refuses to bind ", entry->name);
                continue;
            }
            if (ret) {
                dm_warn("Error binding driver '%s': %d ", entry->name,
                    ret);
                return ret;
            } else {
                found = true;
                if (devp)
                    *devp = dev;
            }
            break;
        }

        if (!found && !result && ret != -ENODEV)
            pr_debug("No match for node '%s' ", name);

        return result;
    }


    函数device_bind_with_driver_data()最终调用的是device_bind_common()函数。
    ————————————————
    版权声明:本文为CSDN博主「liuduanfei」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
    原文链接:https://blog.csdn.net/A_orz_/article/details/100657963

  • 相关阅读:
    tcpdump抓包
    openldap quick start guide
    深入理解PHP内核(六)函数的定义、传参及返回值
    深入理解PHP内核(五)函数的内部结构
    mongodb 关系、引用、覆盖索引查询
    mongodb php
    mongodb-$type、limit、skip、sort方法、索引、聚合
    mongodb简介与增删该查
    深入理解PHP内核(四)概览-PHP脚本的执行
    深入理解PHP内核(三)概览-SAPI概述
  • 原文地址:https://www.cnblogs.com/idyllcheung/p/12055988.html
Copyright © 2011-2022 走看看