外设驱动框架
AC79NN SDK 的外设驱动框架为芯片上所有外设(UART、IIC、GPIO、SD 卡、Flash、按键等)提供统一的抽象层:应用层通过 dev_open / dev_read / dev_write / dev_ioctl / dev_close 这一组标准接口访问任意设备,驱动层通过 struct device_operations(字符设备)或 struct dev_io_t(存储类设备)挂接具体实现,实现"设备无关"的应用代码与"即插即用"的驱动注册机制。
Purpose and Scope
本页面向 SDK 使用者和驱动开发者,完整讲解 AC79NN 外设驱动框架的两套核心抽象:
- 字符设备框架(
device.h):基于dev_node+device_operations的统一字符设备模型,覆盖dev_open/read/write/ioctl/close/seek全部标准操作,是 UART、IIC、GPIO、ADC、按键、SDIO 等设备驱动的基础。 - 存储类设备框架(
device_drive.h):面向块存储设备的dev_io_t接口,包含设备类型枚举、在线状态、电源状态和错误码定义,是 NOR/NAND Flash、SD 卡、U 盘等存储介质驱动的基础。
配套说明:各具体外设驱动的命令字定义见 ioctl_cmds.h;各外设的独立页面(如 UART、IIC、按键驱动等)由目录中对应的叶子页面另行覆盖,本页只说明它们共同依赖的框架机制。USB 设备栈(apps/common/usb/device/)与网络驱动(include_lib/net/)虽使用本框架,但其协议细节不属于本页范围。
Overview
设计目标
嵌入式系统中外设种类繁多、寄存器操作各异。如果应用层直接操作寄存器,代码将与具体芯片和具体外设强耦合,无法移植、无法复用。AC79NN 外设驱动框架借鉴 Linux 字符设备模型,将"设备"抽象为可枚举、可注册、可统一调用的对象:
- 设备即节点:每个驱动通过
REGISTER_DEVICE宏把一个dev_node放入链接脚本指定的.device段,系统启动时由devices_init()统一遍历初始化,无需手动维护设备列表。 - 操作即函数表:驱动只需实现
struct device_operations中的函数指针(open/read/write/ioctl/close…),框架负责调度与分发。 - 应用即句柄:应用层只通过设备名字符串(如
"uart1"、"iic0")打开设备,拿到不透明的void *句柄后即可读写,完全不知道底层实现细节。
关键概念
| 概念 | 说明 |
|---|---|
dev_node | 设备节点,描述"存在哪些设备":名字 + 操作函数表 + 私有数据 |
device | 设备实例,描述"设备被打开后的状态":引用计数 + 私有数据 + 操作函数表 |
device_operations | 字符设备操作函数表,驱动实现的核心契约 |
dev_io_t | 存储类设备接口,面向 mount/read/write 的块设备契约 |
dev_type | 设备类型枚举,用于区分 SD 卡、Flash、U 盘等介质 |
| ioctl 命令 | 通过 dev_ioctl 传递的控制命令,命令字在 ioctl_cmds.h 中定义 |
适用场景
- 应用需要读写串口、IIC 从机、ADC、GPIO、按键等字符外设时;
- 需要挂载/卸载 SD 卡、NOR/NAND Flash、U 盘等存储介质时;
- 需要新增一个自定义外设驱动并接入系统统一管理时。
Architecture
flowchart TD
subgraph sg_App["应用层 (Application)"]
App["业务代码<br/>fopen 风格调用"]
end
subgraph sg_API["框架 API 层"]
API["dev_open / dev_read / dev_write<br/>dev_ioctl / dev_close / dev_seek"]
API2["dev_bulk_read / dev_bulk_write"]
end
subgraph sg_Core["框架核心 (include_lib/driver/device)"]
Node["dev_node 注册表<br/>REGISTER_DEVICE 宏 (.device 段)"]
Ops["struct device_operations<br/>online/init/open/read/write/seek/ioctl/close"]
DevInst["struct device 实例<br/>atomic ref + private_data"]
Init["devices_init() 启动扫描"]
IO["dev_io_t 存储类接口<br/>mount/read/write/ioctrl/power/detect"]
end
subgraph sg_Drv["具体驱动层 (Drivers)"]
D1["uart / iic / gpio / adc"]
D2["key 按键 (adkey/iokey/irkey...)"]
D3["sdio (sd/mmc/card)"]
D4["flash (nor/nand) / 存储设备"]
end
subgraph sg_Hw["硬件层"]
HW["芯片外设寄存器"]
end
App --> API
API --> Ops
API --> DevInst
API2 --> Ops
Node --> Init
Ops --> Node
Ops --> D1
Ops --> D2
Ops --> D3
IO --> D4
D1 --> HW
D2 --> HW
D3 --> HW
D4 --> HW
架构说明:应用层只与框架 API 交互,不感知具体驱动。框架 API 通过 dev_node 中保存的 device_operations 函数表分发调用到具体驱动;驱动直接操作硬件寄存器。devices_init() 在启动阶段扫描 .device 段中由 REGISTER_DEVICE 宏注册的全部节点并调用其 init。存储类设备则通过独立的 dev_io_t 接口由文件系统/存储管理层使用。
字符设备框架详解(device.h)
字符设备框架是 AC79NN 外设驱动模型的基础,全部定义位于 include_lib/driver/device/device.h。它包含三个核心数据结构、两个注册宏和一组统一操作 API。
核心数据结构
struct device_operations — 驱动契约
struct device_operations {
bool (*online)(const struct dev_node *node);
int (*init)(const struct dev_node *node, void *);
int (*open)(const char *name, struct device **device, void *arg);
int (*read)(struct device *device, void *buf, u32 len, u32);
int (*write)(struct device *device, void *buf, u32 len, u32);
int (*seek)(struct device *device, u32 offset, int orig);
int (*ioctl)(struct device *device, u32 cmd, u32 arg);
int (*close)(struct device *device);
};
Source: device.h
每个驱动必须实现该函数表中的全部或部分函数。设计意图:online 用于热插拔检测(如 SD 卡/U 盘是否在位);init 在系统启动扫描时被 devices_init() 调用,完成硬件初始化;open 负责创建并返回 struct device 实例;read/write/ioctl/close 对应应用层的标准调用。函数指针带 struct device * 参数,使同一驱动可同时服务多个打开实例。
struct dev_node — 设备注册表项
struct dev_node {
const char *name;
const struct device_operations *ops;
void *priv_data;
};
Source: device.h
dev_node 是"静态"的设备描述:name 是应用层 dev_open 时使用的字符串标识;ops 指向驱动实现的操作函数表;priv_data 携带驱动私有数据(如寄存器基址、配置参数)。
struct device — 打开后的设备实例
struct device {
atomic_t ref;
void *private_data;
const struct device_operations *ops;
};
Source: device.h
device 是"动态"的打开实例:ref 为原子引用计数,支持多任务同时持有同一设备;private_data 保存驱动运行时状态;ops 复用节点上的函数表。框架 API 层把应用传入的 void * 句柄强转为 struct device * 后分发调用。
设备注册宏
#define REGISTER_DEVICE(node) \
const struct dev_node node SEC_USED(.device)
#define REGISTER_DEVICES(node) \
const struct dev_node node[] SEC_USED(.device)
Source: device.h
两个宏把 dev_node(或 dev_node 数组)放入 .device 链接段。设计意图:驱动文件各自定义自己的节点,无需维护全局注册表;链接器自动收集所有 .device 段符号,devices_init() 在启动时按段扫描即可枚举全部设备——新增一个驱动只需新增一个宏调用,零侵入。REGISTER_DEVICES 用于同类型多实例设备(如多路 UART、多路 IIC)。
框架统一 API
int devices_init(); // 启动时扫描 .device 段并逐个调用 init
bool dev_online(const char *name); // 查询设备是否在线
void *dev_open(const char *name, void *arg); // 按名字打开设备,返回句柄
int dev_read(void *device, void *buf, u32 len); // 读数据
int dev_write(void *device, void *buf, u32 len); // 写数据
int dev_seek(void *device, u32 offset, int orig); // 定位
int dev_ioctl(void *device, int cmd, u32 arg); // 控制命令
int dev_close(void *device); // 关闭设备
int dev_bulk_read(void *_device, void *buf, u32 offset, u32 len); // 批量读
int dev_bulk_write(void *_device, void *buf, u32 offset, u32 len); // 批量写
Source: device.h
设计要点:
dev_open返回void *:应用层拿到的是不透明句柄,后续dev_read/dev_write/dev_ioctl/dev_close都只操作这个句柄,保证设备实现的封装性。dev_ioctl是控制面唯一入口:所有非读写操作(波特率配置、GPIO 方向、IIC 速率、采样通道选择等)统一通过cmd命令字 +arg参数完成,命令字在ioctl_cmds.h中集中定义,避免 API 无限膨胀。- 批量读写:
dev_bulk_read/write面向需要"偏移 + 长度"的连续访问场景(典型如 Flash 分区读写),是对read/write的补充。
存储类设备框架详解(device_drive.h)
面向存储介质的驱动(SD 卡、NOR/NAND Flash、U 盘)使用另一套接口 dev_io_t,定义于 include_lib/driver/device/device_drive.h。它与字符设备框架的区别:字符框架面向"流式"外设(打开后顺序读写),存储框架面向"块/地址"介质(按地址 mount、read、write)。
设备类型枚举 dev_type
typedef enum _dev_type {
DEV_SDCRAD_0 = 0X10,
DEV_SDCRAD_1,
DEV_SDCRAD_2,
DEV_UDISK_H0,
DEV_UDISK_H1,
DEV_UDISK_F0,
DEV_NOR_FLASH,
DEV_NAND_FLASH,
DEV_STORAGE = 0x100,
DEV_LOGIC_DISK = 0x101,
DEV_USB_SLAVE,
DEV_USB_HOST,
DEV_HID = 0x200,
DEV_NET,
DEV_AUDIO,
DEV_ISP,
} dev_type;
Source: device_drive.h
类型值按用途分段编码:0x10 段为物理存储介质(SD/UDISK/Flash),0x100 段为逻辑设备(存储、逻辑盘、USB 主机/从机),0x200 段为功能设备(HID、网络、音频、ISP)。设计意图:数值段位本身就携带了设备类别信息,便于存储管理层按类型分发处理策略。
dev_io_t — 存储设备驱动接口
typedef struct DEV_IO {
const char name[8];
s32(*mount)(void *volatile parm);
s32(*unmount)();
s32(*read)(u8 *volatile buf, u32 addr, u32 len);
s32(*write)(u8 *volatile buf, u32 addr, u32 len);
s32(*ioctrl)(void *volatile parm, u32 cmd);
s32(*power)(u32 mod);
s32(*detect)(); //设备状态检测
struct dev_mutex *mutex;
dev_type device_type;
void *private_data; //设备私有属性,用来提供额外接口或者存储一些设备的特性
} dev_io_t;
Source: device_drive.h
每个字段的设计意图:
mount/unmount:介质挂载与卸载生命周期管理,mount参数携带挂载配置(如分区表);read/write:按addr + len的绝对地址读写,这是块设备区别于字符设备的本质;ioctrl:介质级控制(擦除、坏块管理、容量查询等);power:电源状态控制,配合DEV_POWER_ON/OFF/STANDBY/WAKEUP状态机实现低功耗;detect:轮询介质在位状态,驱动热插拔;mutex:读写互斥锁(struct dev_mutex内含独立的write_mutex与read_mutex,见 device_drive.h 第 47-50 行),保证并发访问安全;device_type:介质类型标识,供上层分发;private_data:驱动私有扩展接口或设备特性存储。
设备状态与错误码
typedef enum dev_sta {
DEV_OFFLINE = 0, // 设备从在线切换到离线
DEV_ONLINE = 1, // 设备从离线切换到在线
DEV_HOLD = 2, // 其他值表示设备状态未改变
DEV_POWER_ON = 0x10, // 开机
DEV_POWER_OFF, // 关机
DEV_POWER_STANDBY, // 待机
DEV_POWER_WAKEUP, // 唤醒
} DEV_STA;
typedef enum dev_err {
DEV_ERR_NONE = 0,
DEV_ERR_NOT_MOUNT,
DEV_ERR_OVER_CAPACITY,
DEV_ERR_UNKNOW_CLASS,
DEV_ERR_NOT_READY, // 设备已经在线,但没初始化完成
DEV_ERR_LUN,
DEV_ERR_TIMEOUT,
DEV_ERR_CMD_TIMEOUT,
...
} dev_err;
Source: device_drive.h
状态与错误码采用独立枚举:状态机(DEV_STA)描述"介质连接状态 + 电源状态"两个维度,错误码(dev_err)描述操作失败原因。DEV_ERR_NOT_READY 专门表达"设备已在线但初始化未完成"的中间态,这是热插拔场景的关键语义——detect 回报 DEV_ONLINE 后,存储管理需要等待设备进入 ready 才能读写。
Core Flow — 设备生命周期
启动初始化与设备打开流程
sequenceDiagram
participant Boot as 系统启动
participant Init as devices_init()
participant Node as dev_node (.device 段)
participant Drv as 驱动 open 实现
participant App as 应用任务
participant Dev as struct device 实例
Boot->>Init: 启动阶段调用
Init->>Node: 扫描 .device 段注册表
Node-->>Init: 枚举全部 dev_node
Init->>Drv: 逐个调用 ops->init(node)
Drv-->>Init: 硬件初始化完成
Init-->>Boot: 框架就绪
App->>Init: dev_open("uart1", arg)
Init->>Node: 按名字查找节点
Node-->>Init: 命中 node->ops
Init->>Drv: 调用 ops->open(name, &device, arg)
Drv-->>Init: 填充 struct device (ref=1)
Init-->>App: 返回 void* 句柄
App->>Drv: dev_read(handle, buf, len)
App->>Drv: dev_write(handle, buf, len)
App->>Drv: dev_ioctl(handle, cmd, arg)
App->>Init: dev_close(handle)
Init->>Drv: 调用 ops->close(device) 并释放引用
流程要点:
- 注册期(编译期):各驱动文件通过
REGISTER_DEVICE宏把dev_node放入.device链接段,编译链接时自动完成设备枚举表的构建。 - 初始化期(启动期):
devices_init()遍历.device段,对每个节点调用ops->init,完成寄存器配置、中断注册等硬件初始化。 - 使用期(运行期):应用调用
dev_open(name),框架按名字匹配dev_node,调用ops->open创建struct device实例(ref原子计数置 1),返回句柄;此后所有读写/控制调用通过句柄 →device->ops直接分发。 - 释放期:
dev_close(handle)调用ops->close并递减引用计数,计数归零后释放实例资源。
存储设备挂载与热插拔流程
flowchart TD
Start([detect 轮询]) --> Check{"介质在位?"}
Check -->|"否"| Offline["上报 DEV_OFFLINE<br/>卸载文件系统"]
Check -->|"是"| Online["上报 DEV_ONLINE"]
Online --> Ready{"初始化完成?"}
Ready -->|"否"| NotReady["DEV_ERR_NOT_READY<br/>等待就绪"]
Ready -->|"是"| Mount["dev_io_t->mount(分区参数)"]
Mount --> FS["文件系统挂载<br/>read/write 按 addr+len 访问"]
FS --> Power{"低功耗请求?"}
Power -->|"是"| Standby["DEV_POWER_STANDBY<br/>power() 切换电源状态"]
Standby --> Wake["DEV_POWER_WAKEUP 恢复"]
Wake --> FS
Offline --> Start
NotReady --> Start
Usage Examples
打开并读写一个字符设备
以串口为例,应用层通过设备名打开设备,然后进行读写与控制:
void *dev_open(const char *name, void *arg); // 打开设备
int dev_read(void *device, void *buf, u32 len); // 读入 buffer
int dev_write(void *device, void *buf, u32 len); // 写入 buffer
int dev_ioctl(void *device, int cmd, u32 arg); // 控制/修改参数
int dev_close(void *device); // 关闭设备
Source: device.h
典型调用序列(示意):
void *hdl = dev_open("uart1", NULL); // 按名字打开设备,arg 通常为 NULL
u8 buf[64];
dev_read(hdl, buf, sizeof(buf)); // 接收数据
dev_write(hdl, buf, 32); // 发送数据
dev_ioctl(hdl, IOCTL_SET_BAUD, 115200); // 修改参数
dev_close(hdl); // 关闭
说明:
dev_open返回void *句柄,后续所有操作只依赖该句柄与ioctl_cmds.h中定义的命令字,应用代码无需包含任何驱动实现头文件——这正是框架解耦的目的。
注册一个自定义设备驱动
驱动侧需要定义 struct device_operations 函数表,并通过 REGISTER_DEVICE 宏注册节点:
#define REGISTER_DEVICE(node) \
const struct dev_node node SEC_USED(.device)
#define REGISTER_DEVICES(node) \
const struct dev_node node[] SEC_USED(.device)
Source: device.h
使用 REGISTER_DEVICES 数组形式可注册同类型多实例设备(如多路 UART),数组中的每个元素对应一个可被 dev_open 按名字命中的设备节点。
存储类设备接口实现骨架
存储驱动实现 dev_io_t 结构,提供按地址的读写与电源管理:
typedef struct DEV_IO {
const char name[8];
s32(*mount)(void *volatile parm);
s32(*unmount)();
s32(*read)(u8 *volatile buf, u32 addr, u32 len);
s32(*write)(u8 *volatile buf, u32 addr, u32 len);
s32(*ioctrl)(void *volatile parm, u32 cmd);
s32(*power)(u32 mod);
s32(*detect)(); //设备状态检测
struct dev_mutex *mutex;
dev_type device_type;
void *private_data;
} dev_io_t;
Source: device_drive.h
驱动需同时实现 detect()(回报 DEV_ONLINE/DEV_OFFLINE)与 mount()(挂载介质),并借助 struct dev_mutex(含独立读写互斥锁)保护并发访问。
API Reference
以下为框架对外提供的统一设备 API(定义于 device.h),所有 API 均被 DO_NOT_DOCUMENT 之外的公开注释标记,供应用层直接调用。
int devices_init()
系统启动阶段扫描 .device 链接段中的全部 dev_node,逐个调用 ops->init 完成硬件初始化。由系统启动流程调用,应用一般无需手动调用。
bool dev_online(const char *name)
- 参数:
name— 设备名字符串。 - 返回:设备当前是否在线。常用于热插拔检测,如查询 SD 卡是否插入。
void *dev_open(const char *name, void *arg)
- 参数:
name(const char *):设备名称,如"uart1"、"iic0";arg(void *):控制参数,一般为 NULL。
- 返回:设备句柄(
struct device *的不透明封装);失败返回 NULL。 - 说明:框架按
name在注册表中查找dev_node,调用ops->open创建实例并初始化原子引用计数。
int dev_read(void *device, void *buf, u32 len)
- 参数:
device设备句柄;buf接收缓冲区;len期望读取长度。 - 返回:实际读取字节数;失败返回负错误码。
- 说明:从设备接收数据,分发到
ops->read。
int dev_write(void *device, void *buf, u32 len)
- 参数:
device设备句柄;buf待发送缓冲区;len数据长度。 - 返回:实际写入字节数;失败返回负错误码。
- 说明:向设备发送数据,分发到
ops->write。
int dev_seek(void *device, u32 offset, int orig)
- 参数:
device设备句柄;offset偏移量;orig基准位置(SEEK_SET/SEEK_CUR/SEEK_END)。 - 返回:0 成功;负值失败。
- 说明:支持定位的设备(如逻辑盘)用于调整读写位置。
int dev_ioctl(void *device, int cmd, u32 arg)
- 参数:
device设备句柄;cmd(int):设备控制命令,命令字集中定义于ioctl_cmds.h;arg(u32):控制参数,可为配置值或指针转换。
- 返回:0 成功;负值失败(如
DEV_ERR_NOT_READY)。 - 说明:设备控制面的唯一入口,覆盖波特率、方向、速率、通道等全部参数修改。
int dev_close(void *device)
- 参数:
device设备句柄。 - 返回:0 成功;负值失败。
- 说明:调用
ops->close,递减引用计数;计数归零后释放设备实例。
int dev_bulk_read(void *_device, void *buf, u32 offset, u32 len) / int dev_bulk_write(void *_device, void *buf, u32 offset, u32 len)
- 参数:
_device设备句柄;buf数据缓冲区;offset起始偏移;len长度。 - 返回:操作字节数或负错误码。
- 说明:面向连续地址访问的批量接口(典型用于 Flash 分区读写),内部可能拆分为多次对齐操作。
struct dev_mutex(device_drive.h)
struct dev_mutex {
OS_MUTEX *write_mutex;
OS_MUTEX *read_mutex;
};
Source: device_drive.h
存储驱动并发保护锁,读写锁分离可允许"多读单写"交错执行;在非 RTOS 环境(_WIN_DEBUG_ 模拟)下映射为 pthread 互斥锁,保证 PC 端调试行为与目标机一致。
Configuration Options
外设驱动框架本身不提供运行时配置文件;设备的"配置"通过三种机制完成:
| 机制 | 载体 | 说明 |
|---|---|---|
| 编译期注册 | REGISTER_DEVICE / REGISTER_DEVICES 宏 + .device 链接段 | 决定系统枚举到哪些设备、设备名是什么 |
| 打开参数 | dev_open(name, arg) 的 arg | 打开时传入初始化参数(如默认波特率、IIC 地址) |
| 运行期控制 | dev_ioctl(device, cmd, arg) | 运行中修改设备参数,命令字见 ioctl_cmds.h |
各具体外设的参数项(如 UART 波特率、IIC 速率、GPIO 方向)由对应驱动页面与 ioctl_cmds.h 中的命令字定义,本页不展开。
Failure Modes、边界与并发
设备不可用 / 未注册
dev_open 在注册表中找不到匹配的 name 时返回 NULL。应用侧应在打开后立即判空,避免对空句柄调用 dev_read/dev_write 导致解引用崩溃。框架对未注册设备没有隐式兜底,这是"名字即契约"设计的直接代价——设备名拼写错误在运行期才暴露。
热插拔中间态(DEV_ERR_NOT_READY)
存储设备在线(DEV_ONLINE)但初始化未完成时,读写会返回 DEV_ERR_NOT_READY(device_drive.h 第 116 行明确注释:"设备已经在线,但是没初始化完成")。上层存储管理必须轮询等待设备进入 ready 状态,而不是把该错误当作永久故障;同时 detect() 的轮询结果 DEV_OFFLINE 意味着介质被拔出,文件系统层需要触发卸载流程,防止对已拔出介质继续读写。
并发访问
- 字符设备:
struct device.ref使用原子类型(atomic_t),支持多任务同时持有同一设备句柄;dev_close递减引用计数,归零才释放,避免"最后一个持有者关闭时其他任务仍在使用"的悬垂指针问题。 - 存储设备:
dev_io_t.mutex提供读写分离的双互斥锁(write_mutex/read_mutex),写操作独占、读操作可并发,兼顾吞吐与一致性。驱动实现若绕过该锁直接操作寄存器,会造成读写交错、数据损坏——这是存储驱动实现时的强制约束。
错误码语义
dev_err 枚举(device_drive.h 第 109 行起)覆盖:未挂载(DEV_ERR_NOT_MOUNT)、容量超限(DEV_ERR_OVER_CAPACITY)、未知类别(DEV_ERR_UNKNOW_CLASS)、LUN 错误(DEV_ERR_LUN)、超时(DEV_ERR_TIMEOUT/DEV_ERR_CMD_TIMEOUT)等。上层应区分"可重试错误"(超时、未就绪)与"不可恢复错误"(未知类别、容量超限)采取不同策略,避免死循环重试拖垮系统。
电源状态机
DEV_POWER_ON/OFF/STANDBY/WAKEUP(0x10–0x13)定义了设备电源生命周期。低功耗切换必须由 power(mod) 统一执行;若外设在 standby 时被直接访问而未先唤醒,驱动应返回错误或自动唤醒,具体行为由各驱动实现决定。
Extension Points — 如何扩展框架
- 新增字符外设驱动:实现
struct device_operations(至少open/read/write/ioctl/close),定义dev_node并通过REGISTER_DEVICE注册,节点名即对外设备名。系统启动后即可被dev_open枚举使用,无需修改框架代码。 - 新增存储介质驱动:实现
dev_io_t(mount/unmount/read/write/ioctrl/power/detect),填充device_type与mutex,即可接入存储管理/文件系统层。 - 扩展控制命令:在
ioctl_cmds.h中新增命令字枚举,保持命令字全局唯一;驱动在ops->ioctl中按cmd分发处理。 - 多实例设备:使用
REGISTER_DEVICES数组注册同类型多路设备,每路有独立名字与priv_data,实现一对多复用。 - 调试环境适配:
device_drive.h通过_MANGO_OS_/_WIN_DEBUG_宏在 RTOS 与 PC 模拟环境之间切换互斥实现,驱动开发可在 PC 上先行验证逻辑。
测试与验证
仓库中 include_lib/driver/device/ 下所有驱动头文件(如 uart.h、iic.h、gpio.h、key/、sdio/)均为框架 API 的消费方,其声明的 dev_ioctl 命令选择宏(如 uart.h 中的 "UART dev_ioctl function select")即各驱动对框架 ioctl 分发机制的实现验证。框架层本身通过 devices_init() 启动自检与各驱动的 online/detect 状态机被应用间接测试;热插拔路径(SD 卡/U 盘)建议在目标板上做插拔与读写压力测试,重点覆盖 DEV_ERR_NOT_READY 重试逻辑与拔出瞬间的并发读写。
Related Links
- ioctl_cmds.h — 设备控制命令字定义
- device.h — 字符设备框架核心
- device_drive.h — 存储类设备接口
- includes.h — 设备驱动头文件汇总
- 具体外设驱动(框架的消费方):
uart.h、iic.h、gpio.h、gpcnt.h、key/(adkey/iokey/irkey/touch_key 等)、sdio/(sd/mmc/card)、chargebox.h - 相关目录页:USB 设备栈见
apps/common/usb/device/;网络驱动见include_lib/net/