5.1 设备驱动框架
title: "5.1 设备驱动框架"
shortTitle: "设备驱动框架"
description: "OneOS 设备驱动框架核心架构详解,包括 os_device_t 数据结构、设备操作接口、通知机制与完整驱动注册流程"
icon: "fa6-solid:microchip"
author: 学习阁
date: 2026-07-18
category: 设备驱动
tag:
- 驱动
- 设备
- os_device_t
order: 2
5.1 设备驱动框架
📚 本节导读
学习时长: 约 60 分钟
难度级别: ⭐⭐⭐⭐☆
前置知识: C 语言结构体、函数指针、链表、信号量、第4章内核组件
🎯 学习目标
- 理解 OneOS 设备驱动框架的分层架构与统一抽象模型
- 掌握
os_device_t核心数据结构及其成员含义 - 掌握
os_device_ops操作函数表 - 了解设备类型枚举与 IOCTL 命令体系
- 掌握设备注册、查找、打开、读写、关闭的完整流程
- 了解设备通知机制
一、概述
OneOS 设备驱动框架采用分层架构,所有设备统一抽象为 os_device_t 结构体,通过统一的 ops 操作接口访问。设备框架提供设备注册/注销、打开/关闭、读写、控制等统一接口,遵循"一切皆设备"的设计理念。
框架的核心优势在于:
- 统一抽象:字符设备、块设备、网络设备、总线设备等均以
os_device_t表示 - 统一接口:所有设备通过
init/deinit/read/write/control五个标准操作函数访问 - 引用计数:自动管理设备打开/关闭,防止设备在使用中被卸载
- 同步机制:内置信号量支持阻塞/非阻塞读写
- 通知机制:支持设备事件通知,方便上层监听设备状态变化
二、核心数据结构
2.1 设备类型枚举 enum os_device_type
OneOS 定义了 27 种设备类型,涵盖了嵌入式系统中常见的所有外设类型:
enum os_device_type
{
OS_DEVICE_TYPE_CHAR = 0, /* 字符设备 */
OS_DEVICE_TYPE_BLOCK, /* 块设备 */
OS_DEVICE_TYPE_NETIF, /* 网络接口 */
OS_DEVICE_TYPE_MTD, /* 存储设备 */
OS_DEVICE_TYPE_CAN, /* CAN 设备 */
OS_DEVICE_TYPE_RTC, /* RTC 设备 */
OS_DEVICE_TYPE_SOUND, /* 音频设备 */
OS_DEVICE_TYPE_GRAPHIC, /* 图形设备 */
OS_DEVICE_TYPE_I2CBUS, /* I2C 总线设备 */
OS_DEVICE_TYPE_USBDEVICE, /* USB 从设备 */
OS_DEVICE_TYPE_USBHOST, /* USB 主机总线 */
OS_DEVICE_TYPE_SPIBUS, /* SPI 总线设备 */
OS_DEVICE_TYPE_SPIDEVICE, /* SPI 设备 */
OS_DEVICE_TYPE_SDIO, /* SDIO 总线设备 */
OS_DEVICE_TYPE_PM, /* 电源管理伪设备 */
OS_DEVICE_TYPE_PIPE, /* 管道设备 */
OS_DEVICE_TYPE_PORTAL, /* 门户设备 */
OS_DEVICE_TYPE_CLOCKSOURCE, /* 时钟源设备 */
OS_DEVICE_TYPE_CLOCKEVENT, /* 时钟事件设备 */
OS_DEVICE_TYPE_MISCELLANEOUS, /* 杂项设备 */
OS_DEVICE_TYPE_SENSOR, /* 传感器设备 */
OS_DEVICE_TYPE_TOUCH, /* 触摸设备 */
OS_DEVICE_TYPE_INFRARED, /* 红外设备 */
OS_DEVICE_TYPE_WLAN, /* 无线网络设备 */
OS_DEVICE_TYPE_PWM, /* PWM 设备 */
OS_DEVICE_TYPE_ENCODER, /* 编码器设备 */
OS_DEVICE_TYPE_GENERIC /* 通用设备 */
};2.2 设备操作函数表 struct os_device_ops
每个设备驱动必须实现 os_device_ops 中的五个标准操作函数指针:
struct os_device_ops
{
os_err_t (*init)(os_device_t *dev);
os_err_t (*deinit)(os_device_t *dev);
os_ssize_t (*read)(os_device_t *dev, os_off_t pos, void *buffer, os_size_t size);
os_ssize_t (*write)(os_device_t *dev, os_off_t pos, const void *buffer, os_size_t size);
os_err_t (*control)(os_device_t *dev, int cmd, void *args);
};| 函数指针 | 说明 |
|---|---|
init | 设备初始化,在设备首次打开时调用 |
deinit | 设备反初始化,释放设备资源 |
read | 读取设备数据,返回实际读取字节数 |
write | 写入设备数据,返回实际写入字节数 |
control | 通用设备控制,通过 cmd 区分不同命令 |
2.3 设备结构体 struct os_device
struct os_device
{
char name[OS_NAME_MAX + 1]; /* 设备名称 */
enum os_device_type type; /* 设备类型 */
enum os_device_status status; /* 设备状态 */
int32_t ref_count; /* 引用计数 */
const struct os_device_ops *ops; /* 操作函数表 */
os_list_node_t list; /* 设备链表节点 */
os_list_node_t cb_heads[OS_DEVICE_CB_TYPE_NUM]; /* 回调链表(RX/TX) */
os_semaphore_dummy_t sem_dummy; /* 通用信号量占位 */
os_semaphore_dummy_t tx_sem_dummy; /* 发送信号量占位 */
os_semaphore_dummy_t rx_sem_dummy; /* 接收信号量占位 */
os_semaphore_id sem; /* 通用信号量 */
os_semaphore_id tx_sem; /* 发送信号量 */
os_semaphore_id rx_sem; /* 接收信号量 */
int32_t tx_count; /* 发送计数 */
int32_t rx_count; /* 接收计数 */
int32_t tx_size; /* 发送大小 */
int32_t rx_size; /* 接收大小 */
os_tick_t tx_timeout; /* 发送超时(tick) */
os_tick_t rx_timeout; /* 接收超时(tick) */
void *user_data; /* 用户私有数据 */
#ifdef OS_USING_IO_MULTIPLEXING
os_list_node_t poll_list; /* IO 多路复用链表 */
#endif
#ifdef OS_USING_DEVICE_NOTIFY
os_list_node_t notify_list; /* 设备通知链表 */
#endif
#ifdef OS_DEVICE_SUPPORT_PLUG
os_plug_t plug; /* 设备插件 */
#endif
};关键成员说明:
| 成员 | 说明 |
|---|---|
name | 设备名称,最大长度 OS_NAME_MAX(默认15),用于设备查找 |
type | 设备类型,决定设备所属的 IOCTL 命令空间 |
status | 设备状态,OS_DEVICE_STATUS_NORMAL 或 OS_DEVICE_STATUS_REMOVED |
ref_count | 引用计数,os_device_open 时 +1,os_device_close 时 -1;为 0 时方可卸载 |
ops | 操作函数表,指向驱动实现的五个标准操作函数 |
sem | 通用信号量,用于阻塞式读写同步 |
tx_sem / rx_sem | 发送/接收信号量,用于数据收发同步 |
tx_timeout / rx_timeout | 发送/接收超时时间,通过 OS_DEVICE_CTRL_SET_RX_TIMEOUT 等设置 |
user_data | 用户私有数据指针,驱动可自由使用 |
notify_list | 设备通知回调链表,仅在开启 OS_USING_DEVICE_NOTIFY 时有效 |
2.4 IOCTL 命令体系
OneOS 使用层次化的 IOCTL 命令编码,将设备类型编码到命令的高 8 位,具体命令在低 8 位:
#define IOC_CHAR(cmd) ((OS_DEVICE_TYPE_CHAR << 8) | (cmd))
#define IOC_BLOCK(cmd) ((OS_DEVICE_TYPE_BLOCK << 8) | (cmd))
#define IOC_NETIF(cmd) ((OS_DEVICE_TYPE_NETIF << 8) | (cmd))
// ... 每种设备类型对应一个 IOC_xxx 宏
#define IOC_GENERIC(cmd) ((OS_DEVICE_TYPE_GENERIC << 8) | (cmd))通用命令(所有设备类型均支持):
#define OS_DEVICE_CTRL_FLUSH IOC_GENERIC(1) /* 刷新设备 */
#define OS_DEVICE_CTRL_SEEK IOC_GENERIC(2) /* 移动读写位置 */
#define OS_DEVICE_CTRL_SET_CB IOC_GENERIC(3) /* 设置回调函数 */
#define OS_DEVICE_CTRL_RM_CB IOC_GENERIC(4) /* 移除回调函数 */
#define OS_DEVICE_CTRL_RESUME IOC_GENERIC(5) /* 恢复设备 */
#define OS_DEVICE_CTRL_SUSPEND IOC_GENERIC(6) /* 挂起设备 */
#define OS_DEVICE_CTRL_CONFIG IOC_GENERIC(7) /* 配置设备 */
#define OS_DEVICE_CTRL_SET_RX_TIMEOUT IOC_GENERIC(8) /* 设置接收超时 */
#define OS_DEVICE_CTRL_SET_TX_TIMEOUT IOC_GENERIC(9) /* 设置发送超时 */特殊命令示例:
#define OS_DEVICE_CTRL_CHAR_STREAM 0x10 /* 字符设备流模式 */
#define OS_DEVICE_CTRL_NETIF_GETMAC 0x10 /* 获取 MAC 地址 */
#define OS_DEVICE_CTRL_MTD_FORMAT 0x10 /* 格式化 MTD 设备 */2.5 设备通知机制
当开启 OS_USING_DEVICE_NOTIFY 配置后,OneOS 提供设备事件通知功能:
struct os_device_notify_cb_info
{
device_notify_callback callback; /* 通知回调函数 */
device_notify_filter filter; /* 通知过滤函数 */
os_list_node_t list; /* 链表节点 */
};通用通知事件:
#define ION_GENERIC_REGISTER ION_GENERIC(1) /* 设备注册 */
#define ION_GENERIC_UNREGISTER ION_GENERIC(2) /* 设备注销 */
#define ION_GENERIC_OPEN ION_GENERIC(3) /* 设备打开 */
#define ION_GENERIC_CLOSE ION_GENERIC(4) /* 设备关闭 */
#define ION_GENERIC_READ_BLOCK ION_GENERIC(5) /* 阻塞读取 */
#define ION_GENERIC_READ_NONBLOCK ION_GENERIC(6) /* 非阻塞读取 */
#define ION_GENERIC_WRITE_BLOCK ION_GENERIC(7) /* 阻塞写入 */
#define ION_GENERIC_WRITE_NONBLOCK ION_GENERIC(8) /* 非阻塞写入 */
#define ION_GENERIC_CONTROL ION_GENERIC(9) /* 控制操作 */三、核心 API 详解
3.1 设备注册与注销
os_err_t os_device_register(os_device_t *dev, const char *name);
os_err_t os_device_unregister(os_device_t *dev);
os_err_t os_device_removed(os_device_t *dev);os_device_register:
- 将设备注册到全局设备列表中
- 将
name复制到dev->name - 注册成功后可通过
os_device_find按名称查找 - 返回值:
OS_EOK成功,-OS_ERROR失败(名称重复)
os_device_unregister:
- 从全局设备列表中移除设备
- 要求设备引用计数为 0,否则返回
-OS_EBUSY
os_device_removed:
- 标记设备状态为
OS_DEVICE_STATUS_REMOVED
3.2 设备查找
os_device_t *os_device_find(const char *name);- 按名称遍历全局设备列表进行查找
- 找到返回设备指针,未找到返回
OS_NULL
3.3 设备打开与关闭
os_err_t os_device_open(os_device_t *dev);
os_device_t *os_device_open_s(const char *name);
os_err_t os_device_close(os_device_t *dev);os_device_open:
- 引用计数 +1
- 首次打开时(ref_count 从 0 变为 1)自动调用
dev->ops->init(dev) - 返回值:
OS_EOK成功
os_device_open_s:
- 先通过
os_device_find查找,再调用os_device_open打开 - 找到并打开成功返回设备指针,否则返回
OS_NULL
os_device_close:
- 引用计数 -1
- 引用计数归零时自动调用
dev->ops->deinit(dev) - 返回值:
OS_EOK成功
3.4 设备读写
os_ssize_t os_device_read_block(os_device_t *dev, os_off_t pos, void *buffer, os_size_t size);
os_ssize_t os_device_read_nonblock(os_device_t *dev, os_off_t pos, void *buffer, os_size_t size);
os_ssize_t os_device_write_block(os_device_t *dev, os_off_t pos, const void *buffer, os_size_t size);
os_ssize_t os_device_write_nonblock(os_device_t *dev, os_off_t pos, const void *buffer, os_size_t size);参数说明:
dev:设备指针pos:读写位置偏移量buffer:数据缓冲区size:期望读写的数据大小
阻塞 vs 非阻塞:
_block版本:底层read/write返回 0 时会等待信号量,适用于交互式设备_nonblock版本:直接调用底层read/write并返回,不等待
3.5 设备控制
os_err_t os_device_control(os_device_t *dev, int cmd, void *arg);- 通用设备控制接口,通过
cmd区分不同命令 cmd使用IOC_xxx(cmd)宏构造,自动包含设备类型信息- 通用命令
OS_DEVICE_CTRL_*由框架层处理,类型特定命令由驱动ops->control处理
3.6 收发通知
void os_device_recv_notify(os_device_t *dev);
void os_device_send_notify(os_device_t *dev);os_device_recv_notify:释放接收信号量,唤醒等待接收数据的任务os_device_send_notify:释放发送信号量,唤醒等待发送数据的任务- 通常由驱动在中断服务程序中调用,通知上层数据已就绪
3.7 设备遍历
int32_t os_device_for_each(os_err_t (*func)(os_device_t *dev, void *data), void *data);- 遍历全局设备列表,对每个设备调用回调函数
func - 可用于设备信息统计、状态查询等场景
3.8 设备通知
void os_device_notify(os_device_t *dev, os_ubase_t event, os_ubase_t args);
os_err_t os_device_notify_register(os_device_t *dev, device_notify_callback callback, device_notify_filter filter);
os_err_t os_device_notify_unregister(os_device_t *dev, device_notify_callback callback, device_notify_filter filter);os_device_notify:向指定设备发送通知事件os_device_notify_register:注册通知回调,filter为OS_NULL时接收所有事件os_device_notify_unregister:注销通知回调
四、设备驱动注册流程
设备驱动从注册到使用的完整流程如下:
┌─────────────────────────────────────────────────────┐
│ 驱动开发阶段 │
│ │
│ 1. 定义 os_device_t 实例(或嵌入到自定义结构体中) │
│ 2. 实现 os_device_ops 中的操作函数 │
│ 3. 调用 os_device_register() 注册设备 │
│ │
└───────────────────────┬─────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────┐
│ 应用使用阶段 │
│ │
│ 4. os_device_find("device_name") 查找设备 │
│ │ │
│ ▼ │
│ 5. os_device_open(dev) 打开设备 │
│ ├─ ref_count = 0 → 调用 ops->init(dev) │
│ └─ ref_count++ │
│ │ │
│ ▼ │
│ 6. os_device_read_block / os_device_write_block │
│ 调用 ops->read / ops->write │
│ │ │
│ ▼ │
│ 7. os_device_control(dev, cmd, arg) │
│ 调用 ops->control │
│ │ │
│ ▼ │
│ 8. os_device_close(dev) 关闭设备 │
│ ├─ ref_count-- │
│ └─ ref_count = 0 → 调用 ops->deinit(dev) │
│ │
└─────────────────────────────────────────────────────┘五、使用示例
示例:查找设备、打开、读写、关闭的完整流程
#include <device.h>
#include <os_task.h>
#define BUFFER_SIZE 128
void device_demo(void)
{
os_device_t *dev;
os_ssize_t ret;
uint8_t tx_buf[BUFFER_SIZE] = "Hello OneOS Device!";
uint8_t rx_buf[BUFFER_SIZE] = {0};
/* 1. 按名称查找设备 */
dev = os_device_find("uart1");
if (dev == OS_NULL)
{
os_kprintf("Device not found!\r\n");
return;
}
/* 2. 打开设备 */
ret = os_device_open(dev);
if (ret != OS_EOK)
{
os_kprintf("Failed to open device!\r\n");
return;
}
/* 3. 设置超时时间 */
os_device_control(dev, OS_DEVICE_CTRL_SET_RX_TIMEOUT, (void *)1000);
os_device_control(dev, OS_DEVICE_CTRL_SET_TX_TIMEOUT, (void *)1000);
/* 4. 写入数据(阻塞模式) */
ret = os_device_write_block(dev, 0, tx_buf, os_strlen((const char *)tx_buf));
if (ret > 0)
{
os_kprintf("Sent %d bytes successfully\r\n", ret);
}
/* 5. 读取数据(阻塞模式) */
ret = os_device_read_block(dev, 0, rx_buf, BUFFER_SIZE);
if (ret > 0)
{
os_kprintf("Received %d bytes: %s\r\n", ret, rx_buf);
}
/* 6. 关闭设备 */
os_device_close(dev);
}示例:使用 os_device_open_s 简化操作
void device_demo_simple(void)
{
os_device_t *dev;
uint8_t data = 0x55;
/* 一步完成查找和打开 */
dev = os_device_open_s("spi1");
if (dev == OS_NULL)
{
os_kprintf("Failed to find and open device!\r\n");
return;
}
/* 写入数据 */
os_device_write_nonblock(dev, 0, &data, 1);
/* 关闭设备 */
os_device_close(dev);
}示例:遍历所有设备
#include <device.h>
static os_err_t print_device_info(os_device_t *dev, void *data)
{
os_kprintf("Device: %-16s Type: %d Ref: %d\r\n",
dev->name, dev->type, dev->ref_count);
return OS_EOK;
}
void list_all_devices(void)
{
os_kprintf("=== All Registered Devices ===\r\n");
os_device_for_each(print_device_info, OS_NULL);
}📝 本节小结
本节介绍了 OneOS 设备驱动框架的核心架构,包括:
- 统一设备模型:所有设备都以
os_device_t结构体表示,包含名称、类型、状态、引用计数、操作函数表等核心信息 - 标准操作接口:
init/deinit/read/write/control五个函数指针构成统一的操作函数表 - 设备类型体系:27 种设备类型覆盖了嵌入式系统常见外设,IOCTL 命令编码将类型信息嵌入命令高 8 位
- 引用计数:自动管理设备生命周期,防止设备在使用中被意外卸载
- 同步机制:内置信号量支持阻塞/非阻塞两种读写模式
- 通知机制:支持设备事件通知,方便上层监听设备状态变化
理解设备驱动框架是掌握后续 GPIO、I2C、Serial、SPI、Touch 等具体设备驱动的基础。