杰理 SDK 文档中心
首页
首页
  • 项目概览

    • AD16N 系列芯片与 SDK 能力总览
  • 快速开始

    • 环境搭建与编译工具链
    • 编译构建指南
    • 烧录与固件升级
  • SDK 工程架构

    • SDK 目录结构与模块分层
    • 构建系统与批处理工具
    • BSP 板级支持包
  • mbox_flash 小音箱应用

    • 应用初始化与启动流程
    • 应用配置系统
    • 按键、UI 与用户交互
  • 音频子系统

    • 音频解码框架与调度
    • 音频格式解码器实现
    • MIDI 合成与播放
    • 音频编码与录音
    • EQ/DRC 与音效处理
    • DAC/ADC 音频接口与采样
  • 存储与文件系统

    • 媒体 IO 抽象层 MIO
    • 存储设备驱动
    • 文件系统支持
  • 平台系统库

    • 系统基础服务
    • CPU 平台与运行库
    • 固件升级与更新机制
    • 蓝牙与扩展连接接口
  • 电源与低功耗管理

    • 电源管理与低功耗设计
    • 锂电池充电管理
  • 硬件与文档参考

    • SDK 文档中心与版本发布记录
    • 芯片数据手册与硬件设计参考

存储设备驱动

AD16N SDK 中的存储设备驱动层为 NOR Flash、SD 卡(含 CD-ROM 模拟与加密分区)、U 盘(USB 大容量存储)等存储介质提供统一抽象,通过 dev_node/device 注册表与 struct device_operations 操作集向上层文件系统与业务逻辑暴露标准化的打开、读写、控制接口。

Purpose and Scope

本页面向存储设备驱动子系统,覆盖以下内容:

  • 设备抽象层:dev_node、device、device_operations 的定义与注册机制(.device 段)。
  • 设备管理 API:dev_open、dev_ioctl、dev_close、dev_byte_read/write、dev_bulk_read/write 等。
  • 设备类型、状态与错误码枚举(dev_type、dev_sta、dev_err)。
  • NOR Flash 驱动(sfc / ext_flsh):命令集、互斥锁与擦除类型。
  • SD 卡驱动(sd0 / sd_cdrom / sd_enc):sdx_dev_* 系列接口。

以下相关主题属于兄弟页面,不在本页展开:上层文件系统与分区表(见文件系统相关页面)、USB 协议栈与 OTG 控制器(见 USB 相关页面)、设备管理中间件(dev_mg)的调度细节。

Overview

存储设备驱动是连接物理存储介质与上层文件系统/业务应用的桥梁。AD16N 是一颗 MCU SoC,其存储形态包括:

  • 片内/片外 SPI NOR Flash(设备名 sfc、ext_flsh),承载固件、配置与用户数据;
  • SD/TF 卡(sd0),支持普通文件系统、CD-ROM 模拟(sd_cdrom)与加密分区(sd_enc);
  • USB U 盘(udisk0),通过 USB Host 栈挂载的大容量存储。

驱动的设计目标:

  1. 统一抽象:所有存储介质都注册为 struct dev_node,实现同一套 struct device_operations 函数指针,上层代码无需关心介质差异。
  2. 引用计数管理:struct device 内含 atomic_t ref,支持多任务共享打开的设备句柄。
  3. 扇区级批量接口:dev_bulk_read/write 以扇区为单位,面向文件系统;dev_byte_read/write 以字节为单位,面向配置读写等小数据场景。

Architecture

flowchart TD
    subgraph sg_App["应用/文件系统层"]
        FS["文件系统 / 业务逻辑"]
    end

    subgraph sg_DevMg["设备管理层 dev_mg"]
        REG["dev_node 注册表<br/>(.device 段)"]
        OPS["struct device_operations<br/>online/init/open/read/write<br/>bulk_read/bulk_write/ioctl/close"]
        DEV["struct device<br/>(atomic ref + ops)"]
    end

    subgraph sg_Drivers["存储设备驱动"]
        SFC["sfc / ext_flsh 驱动<br/>NOR Flash (SPI)"]
        SD0["sd0 驱动<br/>SD/TF 卡"]
        SDCD["sd_cdrom 驱动<br/>CD-ROM 模拟"]
        SDENC["sd_enc 驱动<br/>加密分区"]
        UDISK["udisk0 驱动<br/>USB 大容量存储"]
    end

    subgraph sg_Media["物理介质"]
        FLASH[(SPI NOR Flash)]
        SDCARD[(SD/TF Card)]
        USBDEV[(USB U-Disk)]
    end

    FS -->|"dev_open / dev_ioctl / dev_bulk_read"| DEV
    DEV --> OPS
    OPS --> REG
    REG --> SFC
    REG --> SD0
    REG --> SDCD
    REG --> SDENC
    REG --> UDISK
    SFC --> FLASH
    SD0 --> SDCARD
    SDCD --> SDCARD
    SDENC --> SDCARD
    UDISK --> USBDEV

架构说明:上层只与 struct device 交互,通过 dev_open(name) 按名字查找 dev_node,获得绑定驱动操作集的 device 句柄。每个驱动(如 sfc_dev_ops)在链接期通过 REGISTER_DEVICE 宏放入 .device 段,devices_init() 在启动时遍历该段完成初始化。这样新增一种存储介质只需实现一套 device_operations 并注册,无需改动上层代码——这是典型的驱动-设备分离设计。

设备抽象层与注册机制

核心数据结构

存储驱动的三大核心结构定义在 sdk/apps/include_lib/dev_mg/device.h:

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 (*bulk_read)(struct device *device, void *buf, u32 len, u32);
    int (*bulk_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);
};

struct dev_node {
    const char *name;
    const struct device_operations *ops;
    void *priv_data;
};

struct device {
    atomic_t ref;
    void *private_data;
    const struct device_operations *ops;
    void *platform_data;
    void *driver_data;
};

Source: device.h

设计要点:

  • struct device_operations 是纯函数指针集合,一个驱动(如 sfc_dev_ops)就是一张该结构的静态表。read/write 与 bulk_read/bulk_write 并存:前者用于字节寻址(如配置区),后者用于扇区寻址(如文件系统簇读写)。
  • struct dev_node 是注册条目:名字 + 操作集 + 私有数据,作为驱动实例存在于 .device 链接段。
  • struct device 是打开后的句柄:atomic_t ref 做引用计数,private_data/driver_data 供驱动保存介质上下文(如 SPI 句柄、卡状态)。

注册宏与链接段

驱动通过宏将节点放入 .device 段,链接脚本负责把段内所有节点排布在 device_node_begin 与 device_node_end 之间:

#define REGISTER_DEVICE(node) \
    const struct dev_node node sec_used(.device)

#define REGISTER_DEVICES(node) \
    const struct dev_node node[] sec_used(.device)

extern const struct dev_node device_node_begin[];
extern const struct dev_node device_node_end[];

Source: device.h

REGISTER_DEVICES 支持一次注册数组形式的多个节点(例如同一驱动管理多个 SD 卡槽)。devices_init() 遍历 [device_node_begin, device_node_end) 区间,对每个节点调用其 ops->init;该函数注释明确说明它只能由 devices_init_api() 调用,不可单独使用,避免重复初始化。

设备命名约定

系统预定义了以下存储设备名(device.h 顶部宏):

宏设备名介质
__SFC_NANE"sfc"片内 SPI NOR Flash
__SD0_NANE"sd0"SD/TF 卡 0
__SD_CDROM"sd_cdrom"SD 卡 CD-ROM 模拟
__SD_ENC"sd_enc"SD 卡加密分区
__EXT_FLASH_NANE"ext_flsh"外部扩展 NOR Flash
__UDISK"udisk0"USB U 盘
__OTG"otg"USB OTG 控制器

Source: device.h

设备类型、状态与错误码

device_drive.h 定义了驱动层的设备类型枚举 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

SD 卡与 U 盘占用 0x10~0x15,NOR/NAND Flash 紧随其后;0x100 起为逻辑层类型(存储设备、逻辑盘、USB 主从),0x200 起为其他外设(HID、网络、音频、ISP)。该枚举与 dev_io_t 结构配套,dev_io_t 是驱动提供给文件系统层的另一套接口(mount/unmount/read/write/ioctrl/power/detect),与 device_operations 互补:前者面向块设备挂载,后者面向句柄式读写。

状态枚举 dev_sta 定义了设备热插拔与电源状态:

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;

Source: device_drive.h

错误码枚举 dev_err 从 DEV_ERR_NONE 起按类别排列:挂载/容量类(NOT_MOUNT、OVER_CAPACITY)、就绪类(NOT_READY)、超时类(TIMEOUT、CMD_TIMEOUT、READ_TIMEOUT、WRITE_TIMEOUT)、离线类(OFFLINE)、CRC 类(CRC、CMD_CRC、READ_CRC、WRITE_CRC)、USB 控制传输类(CONTROL_STALL、RXSTALL、TXSTALL)以及存储路径类(NOT_STORAGE、INVALID_PATH 等)。这些错误码为上层文件系统与用户层提供了统一的错误语义,避免各驱动各自为政。

NOR Flash 驱动(sfc / ext_flsh)

驱动开关与无 OS 模式

NOR Flash 驱动由 TFG_EXT_FLASH_EN 编译开关控制:启用后定义 TCFG_NORFLASH_DEV_ENABLE 以启动 NOR Flash 驱动。

#if defined(TFG_EXT_FLASH_EN) && TFG_EXT_FLASH_EN
#define TCFG_NORFLASH_DEV_ENABLE //启动 nor flash
#endif

#define NORFLASH_NO_SYS 1     //0:使用操作系统,1:不使用操作系统

Source: norflash.h

NORFLASH_NO_SYS 决定互斥实现方式。MCU 裸机场景(NORFLASH_NO_SYS=1)下,驱动使用自旋式的 flash_mutex(本质是一个 volatile u8 信号量)保证对 SPI Flash 的独占访问;flash_mutex_pend 支持超时(timeout=0 表示死等),并在等待期间调用 wdt_clear() 喂狗,防止长时间占用 Flash 时看门狗复位:

static inline s8 flash_mutex_pend(flash_mutex *sem, u32 timeout)// 当为timeout=0时,死等
{
    u32 _jiffies = maskrom_get_jiffies();
    u32 _timeout = timeout + _jiffies;
    extern void wdt_clear();
    while (1) {
        if (*sem) {
            (*sem) = 0;
            break;
        }
        if ((timeout != 0) && (_timeout < _jiffies)) {
            return -1;
        }
        wdt_clear();
    }
    return 0;
}

Source: norflash.h

设计意图:Flash 擦写属于长耗时操作(扇区擦除可达数十毫秒),若多任务/中断同时访问 SPI 总线会产生竞态;而裸机下没有 RTOS 互斥量可用,故用轻量自旋锁 + 超时 + 喂狗组合,既保证互斥又防止系统因长时间关中断或忙等而复位。同时提供 query_flash_mutex_pend 非阻塞查询变体,供中断上下文探测锁状态。

Flash 命令集

驱动内置 WinBond W25X 系列命令集,覆盖完整的读写擦生命周期:

#define WINBOND_WRITE_ENABLE		0x06
#define WINBOND_READ_SR1			0x05
#define WINBOND_READ_SR2			0x35
#define WINBOND_WRITE_SR1			0x01
#define WINBOND_WRITE_SR2			0x31
#define WINBOND_READ_DATA			0x03
#define WINBOND_FAST_READ_DATA		0x0b
#define WINBOND_FAST_READ_DUAL_OUTPUT 0x3b
#define WINBOND_PAGE_PROGRAM			0x02
#define WINBOND_PAGE_ERASE              0x81
#define WINBOND_SECTOR_ERASE		0x20
#define WINBOND_BLOCK_ERASE			0xD8
#define WINBOND_CHIP_ERASE			0xC7
#define WINBOND_JEDEC_ID                0x9F
#define WINBOND_POWER_DOWN              0xB9
#define WINBOND_RELEASE_POWER_DOWN      0xAB

Source: norflash.h

命令设计遵循 NOR Flash 规范:写操作前必须先 WRITE_ENABLE (0x06);状态寄存器读取(READ_SR1)用于轮询写/擦完成位(WIP);提供四级擦除粒度——页擦除(0x81)、扇区擦除(0x20,4KB)、块擦除(0xD8,64KB)、整片擦除(0xC7),上层根据数据量选择最小合适的擦除粒度以平衡速度与磨损。JEDEC_ID (0x9F) 用于上电识别 Flash 厂商与型号,POWER_DOWN/RELEASE_POWER_DOWN 用于低功耗管理。

擦除类型枚举

enum {
    FLASH_PAGE_ERASER,
    FLASH_SECTOR_ERASER,
    ...
};

Source: norflash.h

该枚举供 ioctl 命令(如 IOCTL_FLASH_ERASE_SECTOR 等,定义于 ioctl_cmds.h)选择擦除粒度,驱动据此分发到对应的擦除命令。

SD 卡驱动(sd0 / sd_cdrom / sd_enc)

SD 卡接口族

SD 卡驱动以 sdx_dev_* 为前缀,在 sdk/apps/include_lib/device/sdmmc/sd.h 中声明,覆盖从初始化到关闭的完整生命周期:

extern int sdx_dev_init(const struct dev_node *node, void *arg);
extern bool sdx_dev_online(const struct dev_node *node);
extern int sdx_dev_open(const char *name, struct device **device, void *arg);
extern int sdx_dev_byte_read(struct device *device, void *buf, u32 len, u32 offset);
extern int sdx_dev_byte_write(struct device *device, void *buf, u32 len, u32 offset);
extern int sdx_dev_read(struct device *device, void *buf, u32 len, u32 offset);
extern int sdx_dev_write(struct device *device, void *buf, u32 len, u32 offset);
extern int sdx_dev_ioctl(struct device *device, u32 cmd, u32 arg);
extern int sdx_dev_close(struct device *device);

Source: sd.h

接口与 struct device_operations 一一对应,说明 sdx_* 函数族就是 sd0 设备节点的 ops 实现体。sdx_dev_online 用于热插拔检测(轮询卡检测引脚或命令响应),sdx_dev_ioctl 透传容量查询、只读状态、写保护等命令。

SD 卡功能变体

SD 卡驱动还派生出两个功能变体,同一物理介质、不同逻辑角色:

  • sd_cdrom(CD-ROM 模拟):sd_cdrom_dev_init/open/read/ioctl/close,将 SD 卡内容以只读光驱形式暴露,通常用于车机/音箱等场景的固件升级盘或媒体盘模拟。
  • sd_enc(加密分区):sd_enc_dev_init/open/read/write/ioctl,在标准读写之外增加加密变换,用于保护版权内容或私有数据。
//*****************sd_cdrom区
int sd_cdrom_dev_init(const struct dev_node *node, void *arg);
bool sd_cdrom_dev_online(const struct dev_node *node);
int sd_cdrom_dev_open(const char *name, struct device **device, void *arg);
int sd_cdrom_dev_read(struct device *device, void *buf, u32 len, u32 offset);
int sd_cdrom_dev_ioctl(struct device *device, u32 cmd, u32 arg);
int sd_cdrom_dev_close(struct device *device);

//*****************sd_enc区
int sd_enc_dev_init(const struct dev_node *node, void *arg);
bool sd_enc_dev_online(const struct dev_node *node);
int sd_enc_dev_open(const char *name, struct device **device, void *arg);
int sd_enc_dev_read(struct device *device, void *buf, u32 len, u32 offset);
int sd_enc_dev_write(struct device *device, void *buf, u32 len, u32 offset);
int sd_enc_dev_ioctl(struct device *device, u32 cmd, u32 arg);

Sources: sd.h、sd.h

注意 sd_cdrom 没有 write 接口(只读光驱语义),而 sd_enc 提供完整的 read/write。三者可分别注册为独立 dev_node,由应用按需 dev_open,互不干扰。

Core Flow:设备打开与读写时序

一次典型的存储读写请求(如文件系统读一个扇区)按以下顺序穿过抽象层:

sequenceDiagram
    participant FS as 文件系统/应用
    participant MG as 设备管理 (dev_mg)
    participant OP as device_operations 表
    participant DRV as 驱动实现 (sdx_dev_*/sfc)
    participant MED as 物理介质 (SD/Flash)

    FS->>MG: dev_open("sd0", arg)
    MG->>MG: 遍历 .device 段查找 dev_node
    MG->>OP: ops->open(name, &device, arg)
    OP->>DRV: sdx_dev_open(...)
    DRV->>MED: 卡初始化/命令准备
    DRV-->>OP: 返回 device 句柄
    OP-->>MG: 填充 struct device (ref=1)
    MG-->>FS: void* device

    FS->>MG: dev_bulk_read(device, buf, sector, num)
    MG->>OP: ops->bulk_read(device, buf, len, offset)
    OP->>DRV: sdx_dev_read(...)
    DRV->>MED: CMD17/CMD18 读块
    MED-->>DRV: 数据块
    DRV-->>FS: 拷贝到 buf

    FS->>MG: dev_ioctl(device, cmd, arg)
    MG->>OP: ops->ioctl(...)
    OP-->>DRV: 容量/状态查询

    FS->>MG: dev_close(device)
    MG->>OP: ops->close(device)
    OP->>DRV: sdx_dev_close(...) / ref--

流程要点:

  1. 打开阶段:dev_open 按名字在 .device 段注册表中定位 dev_node,调用 ops->open 创建 struct device,atomic_t ref 初始化为 1,之后所有读写都通过该句柄进行。
  2. 读写阶段:上层调用 dev_bulk_read/write(扇区语义,offset 为扇区号)或 dev_byte_read/write(字节语义,offset 为字节地址);设备管理函数将参数转发给对应 ops 函数指针,由具体驱动翻译成介质命令(SD 的 CMD17/CMD18、Flash 的 READ_DATA/PAGE_PROGRAM)。
  3. 控制阶段:dev_ioctl 是通用控制通道,承载容量查询、擦除命令、写保护等非读写操作。
  4. 关闭阶段:dev_close 递减引用计数并释放资源。
flowchart LR
    A["dev_open(name)"] --> B{"节点存在?"}
    B -->|"否"| E["返回 NULL"]
    B -->|"是"| C{"ops->online?"}
    C -->|"离线"| F["返回 NULL / 状态通知"]
    C -->|"在线"| D["ops->open → struct device"]
    D --> G["dev_bulk_read/write<br/>dev_ioctl<br/>dev_close"]

数据模型与关系

classDiagram
    class dev_node {
        +const char* name
        +const device_operations* ops
        +void* priv_data
    }
    class device {
        +atomic_t ref
        +void* private_data
        +const device_operations* ops
        +void* platform_data
        +void* driver_data
    }
    class device_operations {
        <<interface>>
        +online(node) bool
        +init(node, arg) int
        +open(name, device**, arg) int
        +read(device, buf, len, offset) int
        +write(device, buf, len, offset) int
        +bulk_read(device, buf, len, offset) int
        +bulk_write(device, buf, len, offset) int
        +seek(device, offset, orig) int
        +ioctl(device, cmd, arg) int
        +close(device) int
    }
    class dev_io_t {
        +char name[8]
        +mount(parm) s32
        +unmount() s32
        +read(buf, addr, len) s32
        +write(buf, addr, len) s32
        +ioctrl(parm, cmd) s32
        +power(mod) s32
        +detect() s32
        +dev_type device_type
    }
    dev_node --> device_operations : 绑定 ops
    device --> device_operations : 调用 ops
    dev_node ..> dev_io_t : 驱动另提供块设备接口

两类接口的协作关系:device_operations 是"句柄式"接口(先 open 拿句柄,再按句柄读写),服务于设备管理中间件与文件系统;dev_io_t 是"注册式"块设备接口(mount/unmount/read/write/ioctrl/power/detect 直接按地址操作),服务于上层存储管理框架。两者通过 dev_node 的 priv_data 或 device->driver_data 关联到同一驱动实例,实现"同一介质、两套视图"。

API Reference

设备管理 API(device.h)

函数签名说明
devices_initint devices_init(void)遍历 .device 段初始化所有驱动,仅由 devices_init_api() 调用
devices_init_apiint devices_init_api(void)对外提供的设备初始化入口
dev_onlinebool dev_online(const char *name)查询设备是否在线(热插拔检测)
dev_openvoid *dev_open(const char *name, void *arg)打开设备,返回 struct device* 句柄(失败返回 NULL)
dev_ioctlint dev_ioctl(void *device, int cmd, u32 arg)向设备发送控制命令
dev_closeint dev_close(void *device)关闭设备句柄,递减引用计数
dev_byte_readint dev_byte_read(void *device, void *buf, u32 offset, u32 len)字节寻址读
dev_byte_writeint dev_byte_write(void *device, void *buf, u32 offset, u32 len)字节寻址写
dev_bulk_readint dev_bulk_read(void *device, void *buf, u32 sector, u32 sector_num)扇区批量读
dev_bulk_writeint dev_bulk_write(void *device, void *buf, u32 sector, u32 sector_num)扇区批量写
set_device_nodestruct dev_node_mg *set_device_node(struct dev_node *start, struct dev_node *end)自定义设备节点区间(动态注册)
device_status_emitint device_status_emit(const char *device_name, const u8 status)上报设备在线/离线/电源状态事件

Source: device.h

参数约定:

  • dev_byte_read/write 与 dev_bulk_read/write 的参数顺序不同:字节接口为 (buf, offset, len),批量接口为 (buf, sector, sector_num)。前者 offset 是字节地址,后者 sector 是扇区号——调用时务必区分,避免混淆。
  • dev_open 返回 void*,实际类型为 struct device*,上层通常直接透传给读写函数,无需解引用内部字段。

NOR Flash 驱动接口(norflash.h)

符号类型说明
flash_mutex_create(sem, count)inline初始化 Flash 互斥信号量
flash_mutex_pend(sem, timeout)inline s8获取锁,timeout=0 死等,超时返回 -1
flash_mutex_post(sem)inline释放锁
query_flash_mutex_pend(sem, timeout)inline s8非阻塞探测锁状态
flash_mutex_set(sem, count)inline强制设置锁值
TCFG_NORFLASH_DEV_ENABLE宏使能 NOR Flash 驱动(由 TFG_EXT_FLASH_EN 触发)

SD 卡驱动接口(sd.h)

sd0 设备:sdx_dev_init/online/open/byte_read/byte_write/read/write/ioctl/close(见上文代码),直接实现 device_operations 全部条目。

Configuration Options

配置项类型默认值说明
TFG_EXT_FLASH_EN编译宏0使能外部扩展 Flash,开启后自动定义 TCFG_NORFLASH_DEV_ENABLE
NORFLASH_NO_SYS编译宏11=不使用 OS,采用自旋锁式 flash_mutex;0=使用 OS 互斥量
flash_mutex_pend 的 timeout函数参数0(死等)锁获取超时(jiffies),非 0 时超时返回 -1
设备名宏(__SFC_NANE 等)宏"sfc"/"sd0" 等设备注册名,上层 dev_open 按此查找

Failure Modes、边界情况与并发

设备离线与热插拔

  • dev_online(name) 与驱动 ops->online 构成热插拔检测链:上层轮询在线状态,离线时 dev_open 返回 NULL。dev_err 中的 DEV_ERR_OFFLINE、DEV_ERR_NOT_READY(在线但未初始化完成)区分了两种失败时机。
  • SD 卡在读写中途拔出时,驱动层返回超时/CRC 类错误(DEV_ERR_READ_TIMEOUT、DEV_ERR_READ_CRC 等),上层应据此触发卸载流程而非重试风暴。

并发与互斥

  • 句柄引用计数:struct device.ref 为 atomic_t,多任务可共享同一句柄;dev_close 递减,最后一个关闭者释放资源。
  • Flash 独占:裸机模式下 flash_mutex 自旋锁保证 SPI Flash 访问串行化;等待期间 wdt_clear() 喂狗,避免长擦除导致看门狗复位。若 flash_mutex_pend 超时(返回 -1),调用方必须放弃操作,不可重入写。
  • 中断上下文:query_flash_mutex_pend 为非阻塞变体,供中断/高优先级上下文探测锁状态,避免死等。

容量与寻址边界

  • DEV_ERR_OVER_CAPACITY 表示读写越过介质容量;dev_bulk_* 的 sector 语义下,len 为扇区数,驱动需换算为字节偏移并做边界检查。
  • Flash 擦写粒度差异(页/扇区/块/整片)要求上层按对齐边界下发擦除命令,否则可能破坏相邻数据。

字节接口与批量接口的混用

同一设备上字节接口(配置区)与批量接口(文件系统)并存。若二者没有共享互斥(device_drive.h 的 dev_io_t.mutex 即为此设计),并发混用可能导致 Flash 写状态机冲突;SD 驱动内部应保证命令串行。

Extension Points

  1. 新增存储介质驱动:实现 struct device_operations(至少 init/open/read/write/ioctl/close),用 REGISTER_DEVICE(node) 注册到 .device 段,系统启动时自动初始化。参考 sfc_dev_ops(device.h 末尾导出)与 sdx_dev_* 函数族。
  2. 动态注册:set_device_node(start, end) 可在运行时注册额外节点区间,适用于需要动态枚举设备(如多 U 盘)的场景。
  3. 设备事件上报:device_status_emit(name, status) 将 dev_sta 状态(在线/离线/电源切换)广播给上层,供 UI 或电源管理订阅。
  4. 功能变体:参照 sd_cdrom(只读)与 sd_enc(加密)模式,可基于同一底层驱动派生新的逻辑设备,仅重写 device_operations 中差异化的函数指针。

Related Links

  • 设备管理中间件(dev_mg) — 本页所述 dev_open/dev_ioctl 等 API 的调度与注册表实现。
  • 文件系统与分区 — 基于本页批量读写接口的挂载与分区表管理(若目录存在)。
  • USB 协议栈与 OTG — udisk0 设备背后的 USB Host/SCSI 实现(若目录存在)。
  • 源码入口:device.h、device_drive.h、norflash.h、sd.h
Prev
媒体 IO 抽象层 MIO
Next
文件系统支持