zoukankan      html  css  js  c++  java
  • Linux设备树

    linux kernel的设备驱动模型在linux kernel引入统一设备模型之后,bus、driver和device形成了设备模型中的铁三角。在驱动初始化的时候会将代表该driver的一个数据结构挂入bus上的driver链表,device的数据结构挂入bus上的devie链表,那么如何让device遇到“对”的那个driver呢?那么就要靠缘分了,也就是bus的match函数来完成。在传统的方式中,代码中会定义一个static struct platform_device *xxx_devices的静态数组,在初始化的时候调用platform_add_devices。这些静态定义的platform_device往往又需要静态定义各种resource,那么对于设备树,也就是需要根据device_node的树状结构(root是of_allnodes)将一个个的device node挂入到相应的总线device链表中即可。
     

    static int __init customize_machine(void)
    {
        /*
         * customizes platform devices, or adds new ones
         * On DT based machines, we fall back to populating the
         * machine from the device tree, if no callback is provided,
         * otherwise we would always need an init_machine callback.
         */
        if (machine_desc->init_machine)
            machine_desc->init_machine();
    #ifdef CONFIG_OF
        else
            of_platform_populate(NULL, of_default_bus_match_table,
                        NULL, NULL);
    #endif
        return 0;
    }
     

    新内核中device_node展开为platform_device将device_node展开为platform_device是of_platform_default_populate_init()函数实现的。

    arch_initcall_sync(of_platform_default_populate_init);


    其具体调用为

    static int __init of_platform_default_populate_init(void)
        int of_platform_default_populate(struct device_node *root, const struct of_dev_auxdata *lookup,struct device *parent)
                    int of_platform_populate(struct device_node *root, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent)
                                static int of_platform_bus_create(struct device_node *bus, const struct of_device_id *matches, const struct of_dev_auxdata *lookup, struct device *parent, bool strict)
                                           static struct platform_device *of_platform_device_create_pdata(struct device_node *np, const char *bus_id, void *platform_data, struct device *parent)
     

    of_platform_default_populate_init函数生成platform_device的过程

    static int __init of_platform_default_populate_init(void)
    {
        struct device_node *node;
    
        if (!of_have_populated_dt())
            return -ENODEV;
    
        /*
         * Handle certain compatibles explicitly, since we don't want to create
         * platform_devices for every node in /reserved-memory with a
         * "compatible",
         */
         // 处理一些保留的节点
        for_each_matching_node(node, reserved_mem_matches) 
            of_platform_device_create(node, NULL, NULL);
        // 处理一些特殊节点下面的子节点
        node = of_find_node_by_path("/firmware");
        if (node) {
            of_platform_populate(node, NULL, NULL, NULL);
            of_node_put(node);
        }
        //这个才是我们关心的
        /* Populate everything else. */
        of_platform_default_populate(NULL, NULL, NULL);
        return 0;
    }
    arch_initcall_sync(of_platform_default_populate_init);
    #endif

    of_platform_default_populate()

    int of_platform_default_populate(struct device_node *root,
                     const struct of_dev_auxdata *lookup,
                     struct device *parent)
    {
        return of_platform_populate(root, of_default_bus_match_table, lookup,
                        parent);
    }
    EXPORT_SYMBOL_GPL(of_platform_default_populate);
     

    传入一个特殊的参数:of_default_bus_match_table

    const struct of_device_id of_default_bus_match_table[] = {
        { .compatible = "simple-bus", },
        { .compatible = "simple-mfd", },
        { .compatible = "isa", },
    #ifdef CONFIG_ARM_AMBA
        { .compatible = "arm,amba-bus", },
    #endif /* CONFIG_ARM_AMBA */
        {} /* Empty terminated list */
    };
     

    根据我们之前的分析,只要是子节点中的属性含有"simple-bus",“simple-mfd”,“isa”,“arm,amba-bus”,这些子节点就可以转化为platform_device

     传递进来的lookup参数为NULL,所以of_dev_lookup这部分也就不去看了

      auxdata = of_dev_lookup(lookup, bus);
            if (auxdata) {
                    bus_id = auxdata->name;
                    platform_data = auxdata->platform_data;
            }

    dev = of_platform_device_create_pdata(bus, bus_id, platform_data, parent);

    static struct platform_device *of_platform_device_create_pdata(
                                            struct device_node *np,
                                            const char *bus_id,
                                            void *platform_data,
                                            struct device *parent)
    {
            struct platform_device *dev;
    
            if (!of_device_is_available(np) ||
                of_node_test_and_set_flag(np, OF_POPULATED))
                    return NULL;
    
            dev = of_device_alloc(np, bus_id, parent);
            if (!dev)
                    goto err_clear_flag;
    
            dev->dev.coherent_dma_mask = DMA_BIT_MASK(32);
            if (!dev->dev.dma_mask)
                    dev->dev.dma_mask = &dev->dev.coherent_dma_mask;
            dev->dev.bus = &platform_bus_type;
            dev->dev.platform_data = platform_data;

    【跟着韦东山学习linux设备树】内核中device_node转换为platform_device的函数调用分析

  • 相关阅读:
    CentOS 7 配置 ISCSI 服务器
    CentOS 7 配置 http 服务器
    CentOS 7 配置 samba服务器
    ssh的两种连接方法(包括无密码访问)
    CentOS 7 破解mariadb密码
    Selenium2+python自动化53-unittest批量执行(discover)【转载】
    Selenium2+python自动化52-unittest执行顺序【转载】
    Selenium2+python自动化51-unittest简介【转载】
    selenium3+python自动化50-环境搭建(firefox)【转载】
    Selenium2+python自动化49-判断文本(text_to_be_present_in_element)【转载】
  • 原文地址:https://www.cnblogs.com/dream397/p/15596756.html
Copyright © 2011-2022 走看看