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; // 一些标志位
```
- 《嵌入式Linux开发指南——面向IoT领域》
- 源代码与开发软件
- 配套开发套件
- 前言
- 起始部分:准备篇
- 硬件开发平台简介
- 安装 Xshell 7 调试工具
- 安装必要的驱动
- 配置安装ADB
- 配置安装cmder
- 第一部分:基础篇
- 第1章 开发环境及交叉编译链的搭建
- 本章学习目标
- 1.1 开发服务器的搭建
- 1.1.1 VMware导入开发服务器
- 1.1.2 Samba网络服务
- 1.1.3 SSH网络服务
- 1.1.4 交叉编译链
- 1.2 硬件资源介绍
- 第2章 Linux基本命令
- 2.1 常用命令
- 2.1.1 ls
- 2.1.2 cd
- 2.1.3 pwd
- 2.1.4 mkdir
- 2.1.5 touch
- 2.1.6 mv
- 2.1.7 cp
- 2.1.8 rm
- 2.1.9 file
- 2.1.10 cat
- 2.1.11 tree
- 2.1.12 find
- 2.1.13 clear
- 2.1.14 chmod
- 2.1.15 sudo
- 2.1.16 su
- 2.1.17 ping
- 2.2 补充命令
- 2.2.1 ln
- 2.2.2 grep
- 2.2.3 diff
- 2.2.4 patch
- 第3章 嵌入式C基础
- 3.1 数据类型
- 3.1.1 类型定义
- 3.1.2 类型格式化
- 3.2 变量
- 3.2.1 可执行程序存储区
- 3.2.2 动态类型
- 3.2.3 类型转换
- 3.3 指针
- 3.3.1 指针与堆
- 3.3.2 多阶指针
- 3.3.3 通用类型指针
- 3.4 主函数(main)参数列表
- 3.5 可变参数
- 3.5.1 基本用法
- 3.5.2 扩展用法之日志输出
- 3.6 头文件
- 3.6.1 兼容C++
- 3.6.2 日志功能实例
- 3.6.3 C++源文件测试
- 第4章 嵌入式Shell基础
- 4.1 基本语法
- 4.1.1 第一个程序
- 4.1.2 日志输出
- 4.1.3 变量
- 4.1.4 分支控制ifelse
- 4.1.5 for循环
- 4.1.6 while循环
- 4.1.7 case分支语句
- 4.1.8 循环控制
- 4.1.9 变量运算符
- 4.2 函数
- 4.2.1 基本格式及调用
- 4.2.2 函数参数
- 4.2.3 脚本传参
- 第5章 嵌入式系统基础
- 5.1 固件基本组成
- 5.1.1 硬件系统结构
- 5.1.2 分区
- 5.1.2 软件结构
- 5.2 内核设备树
- 5.2.1 结构
- 5.2.2 节点语法
- 5.2.3 属性语法
- 第6章 嵌入式C++基础
- 第二部分:系统篇
- 第1章 固件分区和烧录
- 1.1 准备工作
- 1.1.1 硬件连接说明
- 1.1.2 配置烧录工具
- 1.2 固件烧录
- 1.2.1 固件说明
- 1.2.2 进行烧录
- 1.3 简化固件
- 第2章 系统交叉编译
- 2.1 Uboot
- 2.2 Kernel
- 2.3 Rootfs
- 2.4 APPs
- 第3章 Uboot串口交互终端
- 3.1 硬件连接
- 3.2 波特率配置
- 3.3 调试
- 3.4 Driver Model(DM)模型
- 3.5 串口驱动程序及DTS
- 3.5.1 驱动程序
- 3.5.2 设备树
- 第4章 Kernel串口2做交互终端
- 4.1 驱动源码
- 4.2 内核设备树
- 4.3 补丁更新
- 第5章 内核Config
- 5.1 menuconfig
- 5.2 选项类型
- 5.3 部分General setup实例
- 5.4 生效配置
- 第6章 U盘挂载
- 6.1 配置选项说明
- 6.2 应用
- 第7章 SD卡挂载
- 7.1 内核设备树
- 7.2 应用
- 第8章 WiFi-STA工作模式
- 8.1 内核配置
- 8.2 内核设备树
- 8.3 wpa_supplicant
- 8.3.1 基础
- 8.3.2 应用测试
- 8.3.3 配置文件连接
- 第9章 WiFi-AP工作模式
- 9.1 hostapd
- 9.1.1 基础
- 9.1.2 应用测试
- 第10章 RGB调色灯三路PWM驱动
- 10.1 硬件基础
- 10.2 内核设备树
- 10.3 应用
- 第11章 ADC按键驱动
- 11.1 硬件基础
- 11.2 设备树节点
- 11.3 应用
- 11.3.1 了解IIO子系统
- 11.3.2 按键测试
- 第12章 串口1与ZigBee主控链路
- 12.1 设备树节点
- 12.2 应用测试
- 第13章 可读写根文件系统
- 13.1 简述
- 13.2 内核配置树修改
- 第14章 用户数据区
- 14.1 根文件系统区和用户区的区别
- 14.2 用户数据区
- 14.2.1 分区说明
- 14.2.2增加分区
- 14.2.3 分区内容制作
- 14.2.4 分区挂载
- 第三部分:应用篇
- 第1章 http网络服务及文件传输
- 1.1 搭建服务
- 1.2 下载文件
- 第2章 TCP链路
- 2.1 IP通信
- 2.2 TCP特点和应用
- 2.2.1 特点
- 2.2.2 服务器建立
- 2.2.3 客户端建立
- 2.3 实例
- 第3章 epoll机制
- 3.1 什么是epoll
- 3.2 实例
- 第4章 JSON格式及开源库cJSON的移植
- 4.1 什么是JSON格式
- 4.2 cJSON库
- 4.3 cJSON库裁剪
- 4.4 创建JSON实例
- 4.5 解析JSON实例
- 第5章 jsoncpp的移植
- 5.1 创建JSON实例
- 5.2 解析JSON实例
- 第6章 TCP数据转发服务器
- 6.1 link
- 6.2 linker
- 6.3 基本应用
- 6.2.1 服务器
- 6.2.2 客户端
- 6.4 代理服务器
- 6.5 补充说明
- 第四部分:项目篇
- 项目篇的说明
- 第1章 串口通信协议设计
- 1.1 设计基础
- 1.2 协议格式
- 第2章 zb_msg
- 2.1 串口通信类serial
- 2.2 协议处理zb_msg
- 2.3 交叉编译测试
- 第3章 开源库常见许可证
- 第4章 libevent异步事件库的移植
- 4.1 什么是libevent
- 4.2 交叉编译libevent
- 第5章 ev_base及ev_proxy
- 5.1 ev_base
- 5.2 ev_proxy
- 5.3 应用实例
- 第6章 openssl库移植
- 6.1 什么是openssl
- 6.2 openssl的交叉编译
- 第7章 基于libevent&openssl的https服务
- 7.1 重新交叉编译libevent
- 7.2 httpd
- 7.3 应用实例
- 第8章 libmosquitto移植
- 8.1 什么是mosquitto
- 8.1.1 什么是MQTT
- 8.1.2 mosquitto
- 8.2 mosquitto的交叉编译
- 第9章 AES加解密
- 9.1 简介
- 9.2 应用实例
- 第10章 mqtter(支持AES加解密)
- 10.1 接口说明
- 10.2 源码说明
- 10.3 应用实例
- 版权与免责声明
- 版权声明与免责声明