杰理 SDK 文档中心
首页
首页
  • SDK 概述与快速开始

    • SDK 概览与 AC791N 芯片平台
    • 环境搭建与编译指南
    • 烧录与固件升级
    • 工程结构导览
  • 产品方案应用

    • WiFi 摄像头方案
    • WiFi IPC 可视对讲方案
    • WiFi 故事机方案
    • 扫码枪 HID 方案
    • 开发板示例工程
  • 公共应用组件

    • 语音识别 ASR 引擎
    • LLM 与 AI 语音助手接入
    • 摄像头传感器驱动
    • UI 显示框架与驱动
    • USB 主机与设备栈
    • 文件系统与存储管理
    • 系统服务与外设管理
    • 生产测试与射频工具
  • 蓝牙协议栈

    • 经典蓝牙 BR/EDR
    • BLE 低功耗蓝牙
    • 蓝牙 Mesh 网络
    • 蓝牙扩展协议(RCSP/广播/无线麦克风)
  • WiFi 与网络协议栈

    • WiFi 驱动与网络模式
    • lwIP TCP/IP 协议栈
    • 网络安全与加密库
    • 应用层网络协议
    • 流媒体与音视频传输
    • 云平台接入 SDK
    • P2P 远程访问与设备互联
  • 芯片平台与驱动

    • wl82 平台与硬件加速
    • 外设驱动框架
    • 平台配置与固件打包工具
  • 媒体与音频引擎

    • 音频编解码与音源
    • 音效处理引擎
    • 视频与图像处理
  • 操作系统与运行时

    • 实时操作系统与 POSIX 层
    • C/C++ 运行时库
  • 开发资源与文档

    • 文档与规格书
    • 公共示例工程
    • UI 资源工程与打包
    • SDK 辅助工具与脚本

外设驱动框架

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 字符设备模型,将"设备"抽象为可枚举、可注册、可统一调用的对象:

  1. 设备即节点:每个驱动通过 REGISTER_DEVICE 宏把一个 dev_node 放入链接脚本指定的 .device 段,系统启动时由 devices_init() 统一遍历初始化,无需手动维护设备列表。
  2. 操作即函数表:驱动只需实现 struct device_operations 中的函数指针(open/read/write/ioctl/close…),框架负责调度与分发。
  3. 应用即句柄:应用层只通过设备名字符串(如 "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) 并释放引用

流程要点:

  1. 注册期(编译期):各驱动文件通过 REGISTER_DEVICE 宏把 dev_node 放入 .device 链接段,编译链接时自动完成设备枚举表的构建。
  2. 初始化期(启动期):devices_init() 遍历 .device 段,对每个节点调用 ops->init,完成寄存器配置、中断注册等硬件初始化。
  3. 使用期(运行期):应用调用 dev_open(name),框架按名字匹配 dev_node,调用 ops->open 创建 struct device 实例(ref 原子计数置 1),返回句柄;此后所有读写/控制调用通过句柄 → device->ops 直接分发。
  4. 释放期: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 — 如何扩展框架

  1. 新增字符外设驱动:实现 struct device_operations(至少 open/read/write/ioctl/close),定义 dev_node 并通过 REGISTER_DEVICE 注册,节点名即对外设备名。系统启动后即可被 dev_open 枚举使用,无需修改框架代码。
  2. 新增存储介质驱动:实现 dev_io_t(mount/unmount/read/write/ioctrl/power/detect),填充 device_type 与 mutex,即可接入存储管理/文件系统层。
  3. 扩展控制命令:在 ioctl_cmds.h 中新增命令字枚举,保持命令字全局唯一;驱动在 ops->ioctl 中按 cmd 分发处理。
  4. 多实例设备:使用 REGISTER_DEVICES 数组注册同类型多路设备,每路有独立名字与 priv_data,实现一对多复用。
  5. 调试环境适配: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/
Prev
wl82 平台与硬件加速
Next
平台配置与固件打包工具