• U-Boot Driver Model领域模型设计


    需求分析

    在2014年以前,uboot没有一种类似于linux kernel的设备驱动模型,随着uboot支持的设备越来越多,其一直受到如下问题困扰:

    • 设备初始化流程都独立实现,而且为了集成到系统,需要修改核心公共代码(如init_sequence)
    • 很多子系统只允许一个驱动,比如无法同时支持USB2.0和USB3.0
    • 子系统间的交互实现各异,开发难度大
    • 没有个统一的设备视图(如linux的/sys)

    uboot driver model(U-Boot驱动模型,以下简写dm)的提出就是为了解决这些问题,它的设计目标包括:

    • 提供统一设备驱动框架,降低设备驱动的开发复杂度
    • 提供设备树视图
    • 支持设备组
    • 支持设备lazy init
    • 支持设备驱动沙盒测试
    • 较小的系统开销(内存和CPU)

    对象设计

    对象的设计之所以区分静态形式和运行态形式,考量的出发点是设计模块化。
    静态表达形式的对象是离散的,和系统和其他对象隔离开,减小对象的复杂度,利于模块化设计,遵循人类表达习惯。
    运行态形式的对象是把所有对象组合成层次视图,有着清晰的数据关联视图。方便系统运行时数据的流动。

    静态表达形式

    device: FDT(设备树文本描述) 或者 静态数据结构U_BOOT_DEVICE(以数据段形式组织)
    driver: 静态数据结构U_BOOT_DRIVER(以数据段形式组织)

    运行态形式

    udevice: 设备对象(以链表形式组织)
    driver: 驱动对象。作为udevice的一个属性
    uclass:设备组公共属性对象(以链表形式组织),外部顶层对象,作为udevice的一个属性
    uclass_driver: 设备组公共行为对象,作为uclass的一个属性

    领域建模

    uboot设备模型中udevice为核心对象,以树型模型组织(如下),其为dm的顶层结构。

    单个udevice建模如下,详细对象定义参见《附:核心数据结构》小节。

    所有对象可以按udevice或者uclass进行遍历。

    DM初始化流程

    DM初始化流程包括:

    • 模型初始化
    • 静态对象初始化
    • 运行态对象初始化
    • 设备组公共初始化
    • 设备初始化

    DM初始化的总入口接口:dm_init_and_scan(),其主要由以下三块组成:

    dm_init():创建udevice和uclass空链表,创建根设备(root device)

    dm_scan_platdata():扫描U_BOOT_DEVICE定义的设备,创建对应的udevice和uclass对象,查找并绑定相应driver,并调用probe流程。

    dm_scan_fdt():扫描由FDT设备树文件定义的设备,创建对应的udevice和uclass对象,查找并绑定相应driver,并调用probe流程。

    附:核心数据结构

    U_BOOT_DRIVER(demo_shape_drv) = {
        .name    = "demo_shape_drv",
        .of_match = demo_shape_id,
        .id    = UCLASS_DEMO,
        .ofdata_to_platdata = shape_ofdata_to_platdata,
        .ops    = &shape_ops,
        .probe = dm_shape_probe,
        .remove = dm_shape_remove,
        .priv_auto_alloc_size = sizeof(struct shape_data),
        .platdata_auto_alloc_size = sizeof(struct dm_demo_pdata),
    };
    
    #define U_BOOT_DRIVER(__name)                        
        ll_entry_declare(struct driver, __name, driver)
        
    #define ll_entry_declare(_type, _name, _list)                
        _type _u_boot_list_2_##_list##_2_##_name __aligned(4)        
                __attribute__((unused,                
                section(".u_boot_list_2_"#_list"_2_"#_name)))
    
    struct driver {
        char *name;
        enum uclass_id id;
        const struct udevice_id *of_match;
        int (*bind)(struct udevice *dev);
        int (*probe)(struct udevice *dev);
        int (*remove)(struct udevice *dev);
        int (*unbind)(struct udevice *dev);
        int (*ofdata_to_platdata)(struct udevice *dev);
        int (*child_post_bind)(struct udevice *dev);
        int (*child_pre_probe)(struct udevice *dev);
        int (*child_post_remove)(struct udevice *dev);
        int priv_auto_alloc_size;
        int platdata_auto_alloc_size;
        int per_child_auto_alloc_size;
        int per_child_platdata_auto_alloc_size;
        const void *ops;    /* driver-specific operations */
        uint32_t flags;
    };
    
    U_BOOT_DEVICE(demo0) = {
        .name = "demo_shape_drv",
        .platdata = &red_square,
    };
    #define U_BOOT_DEVICE(__name) ll_entry_declare(struct driver_info, __name, driver_info)
    struct driver_info { const char *name; const void *platdata; #if CONFIG_IS_ENABLED(OF_PLATDATA) uint platdata_size; #endif }; struct uclass { void *priv; struct uclass_driver *uc_drv; struct list_head dev_head; struct list_head sibling_node; }; UCLASS_DRIVER(demo) = { .name = "demo", .id = UCLASS_DEMO, };
    #define UCLASS_DRIVER(__name) ll_entry_declare(struct uclass_driver, __name, uclass)
    struct uclass_driver { const char *name; enum uclass_id id; int (*post_bind)(struct udevice *dev); int (*pre_unbind)(struct udevice *dev); int (*pre_probe)(struct udevice *dev); int (*post_probe)(struct udevice *dev); int (*pre_remove)(struct udevice *dev); int (*child_post_bind)(struct udevice *dev); int (*child_pre_probe)(struct udevice *dev); int (*init)(struct uclass *class); int (*destroy)(struct uclass *class); int priv_auto_alloc_size; int per_device_auto_alloc_size; int per_device_platdata_auto_alloc_size; int per_child_auto_alloc_size; int per_child_platdata_auto_alloc_size; const void *ops; uint32_t flags; }; struct udevice { const struct driver *driver; const char *name; void *platdata; void *parent_platdata; void *uclass_platdata; int of_offset; ulong driver_data; struct udevice *parent; void *priv; struct uclass *uclass; void *uclass_priv; void *parent_priv; struct list_head uclass_node; struct list_head child_head; struct list_head sibling_node; uint32_t flags; int req_seq; int seq; #ifdef CONFIG_DEVRES struct list_head devres_head; #endif };

    --EOF--

  • 相关阅读:
    lua学习项目笔记
    Jenkins 安装、配置与项目新建及构建
    Gitlab的安装及项目新建
    PHP常见排序算法
    抽象类和接口的区别
    分布式版本控制系统Git的安装及使用
    深入解析OpenCart的代理类proxy
    PHP模式设计之单例模式、工厂模式、注册树模式、适配器模式、观察者模式
    linux命令行传递参数定期执行PHP文件
    php类中的$this,static,const,self这几个关键字使用方法
  • 原文地址:https://www.cnblogs.com/wahaha02/p/5987350.html
Copyright © 2020-2023  润新知