💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
uboot引入了驱动模型(driver model),这种驱动模型为驱动的定义和访问接口提供了统一的方法;提高了驱动之间的兼容性以及访问的标准型。 ### uboot的DM主要有四个组成部分: * udevice - 简单就是指设备对象,可以理解为kernel中的device。 * driver - udevice的驱动,可以理解为kernel中的device\_driver。和底层硬件设备通信,并且为设备提供面向上层的接口。 * uclass - 使用相同方式的操作集的device的组。相当于是一种抽象。uclass为那些使用相同接口的设备提供了统一的接口。 * uclass\_driver - 对应uclass的驱动程序。主要提供uclass操作时,如绑定udevice时的一些操作。 调用关系如下: ![](https://img.kancloud.cn/8d/a3/8da3663a8befe2293d622eea0ab0957b_832x726.png =600x) ### DM的模型支持源码在:include/dm ![](https://img.kancloud.cn/a6/6d/a66d7378b49867d77933d6a639c4b6e7_832x184.png =600x) ### 几个关键数据结构的说明: ### **1.uclass id** 在uclass-id.h中定义了相关的id,部分列举如下: ![](https://img.kancloud.cn/fa/18/fa182783cffbeb23c60fa0607cc2aefb_832x612.png =600x) ### 比如我们串口用到uclass的ID就是UCLASS\_SERIAL。 ### **2.uclass** 同一类设备属于同一个uclass,拥有相同的uclass ID。比如说RTC芯片, 市面上RTC芯片很多,由不同的厂家生产,其内存寄存器定义甚至访问接口都不一样,所以RTC的driver肯定是不一样的,但是从功能的角度来说,他们都是用来记录时间的,所他们都属于rtc-class。 uclass从层级结构来讲,起到非常好的承上启下的作用,它既能屏蔽具体设备个体间的差异性,向用户提供统一的接口,又能为同一类的设备定义统一的处理函数,具体的设备驱动只需要实现这些处理函数即可,从而简化的设备驱动的开发。 ### 我们可以在uclass.h中找到uclass的定义如下: 从设备的角度来看,同一类的设备(比如RTC)拥有相同的uclass ID,并全部挂在该uclass下;从驱动的角度来看,uclass driver实现通用的处理逻辑。 ### **3.uclass\_driver** 同样我们可以在uclass.h中找到struct uclass\_driver的定义,这个结构体定义了一组我们访问uclass的接口: ![](https://img.kancloud.cn/bd/d7/bdd7919e06349a1c1df56d11618aed3f_734x554.png =600x) ``` post_bind // 在udevice被绑定到该uclass之后调用 pre_unbind // 在udevice被解绑出该uclass之前调用 pre_probe // 在该uclass的一个udevice进行probe之前调用 post_probe // 在该uclass的一个udevice进行probe之后调用 pre_remove // 在该uclass的一个udevice进行remove之前调用 child_post_bind // 在该uclass一个udevice的一个子设备被绑定到该udevice之后调用 child_pre_probe // 在该uclass的一个udevice的一个子设备进行probe之前调用 init // 安装该uclass的时候调用 destroy // 销毁该uclass的时候调用 ``` ### ### **4.udevice** 我们可以在device.h中找到定义: ![](https://img.kancloud.cn/77/47/77471080a1df814d3e3dda3334c000f3_660x770.png =600x) ### ``` const struct driver *driver; // 该udevice对应的driver const char *name; // 设备名 void *platdata; // 该udevice的平台数据 void *parent_platdata; // 提供给父设备使用的平台数据 void *uclass_platdata; // 提供给所属uclass使用的平台数据 int of_offset; // 该udevice的dtb节点偏移,代表了dtb里面的这个节点node ulong driver_data; // 驱动数据 struct udevice *parent; // 父设备 void *priv; // 私有数据的指针 struct uclass *uclass; // 所属uclass void *uclass_priv; // 提供给所属uclass使用的私有数据指针 void *parent_priv; // 提供给其父设备使用的私有数据指针 struct list_head uclass_node; // 用于连接到其所属uclass的链表上 struct list_head child_head; // 链表头,连接其子设备 struct list_head sibling_node; // 用于连接到其父设备的链表上 uint32_t flags; // 标识 ``` ### **5.driver** 同样我们可以在device.h中找到定义: ![](https://img.kancloud.cn/5f/3e/5f3ec797ba64b628307251d41cafdc2a_760x472.png =600x) ``` char *name; // 驱动名 enum uclass_id id; // 对应的uclass id const struct udevice_id *of_match; //用于和device tree里面的设备节点匹配 (*bind) // 用于绑定目标设备到该driver中 (*probe) // 用于probe目标设备,激活 (*remove) // 用于remove目标设备。禁用 (*unbind) // 用于解绑目标设备到该driver中 (*ofdata_to_platdata) // probe之前,解udevice的dts节点,转化成udevice的数据 (*child_post_bind) // 如果目标设备的一个子设备被绑定之后,调用 (*child_pre_probe) // 在目标设备的一个子设备被probe之前,调用 (*child_post_remove) // 在目标设备的一个子设备被remove之后,调用 int priv_auto_alloc_size; //需要分配多少空间作为其udevice的私有数据 int platdata_auto_alloc_size; //需要分配多少空间作为其udevice的平台数据 int per_child_auto_alloc_size; //每个子设备需要多少私有数据 int per_child_platdata_auto_alloc_size; //每个子设备需要多少平台数据 const void *ops; // 操作集,提供给uclass用,格式具体由uclass决定 uint32_t flags; // 一些标志位 ```