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的函数调用分析

posted on 2021-11-24 09:42  tycoon3  阅读(151)  评论(0编辑  收藏  举报

导航