1. VxWorks 字符设备驱动基础

1.1 字符设备驱动概念

字符设备驱动是 VxWorks 中最基础、最常用的驱动类型。它管理那些以顺序字节流方式访问的硬件设备,例如串口、GPIO、I2C、SPI 等。与块设备不同,字符设备不支持随机访问和缓冲,每次读写操作直接作用于硬件寄存器或 FIFO。

核心特征:
  • 顺序访问:数据按字节流顺序处理,不支持 lseek 随机定位。
  • 无缓冲:读写操作直接穿透到硬件,不经过系统缓冲区。
  • 同步/异步:支持阻塞和非阻塞两种 I/O 模式。
  • 设备文件:通过文件系统路径(如 /tyCo/0)暴露给用户态。

在 VxWorks 中,字符设备驱动通过注册一组标准函数指针(称为 驱动表)来实现。用户态任务通过标准的 POSIX 接口(open、read、write、ioctl、close)与驱动交互,驱动内部再映射到具体的硬件操作。

字符设备驱动核心概念图 用户态任务 POSIX 系统调用 字符设备驱动 硬件设备 字符设备驱动是用户态任务与硬件设备之间的桥梁,通过标准文件接口实现交互

1.2 VxWorks I/O 系统架构

VxWorks 的 I/O 系统采用分层架构,从上到下依次为:应用层、文件系统层、I/O 子系统层、驱动层和硬件层。每一层都有明确的职责和接口契约。

层次 组件 职责
应用层 用户任务 调用 open()、read()、write() 等 API
文件系统层 dosFs、rawFs、romFs 等 提供文件目录结构,管理文件元数据
I/O 子系统 iosLib 维护文件描述符表、驱动表、设备表,分发 I/O 请求
驱动层 字符设备驱动 实现 xxOpen()、xxRead()、xxWrite() 等回调
硬件层 外设寄存器 物理硬件操作,中断处理

I/O 子系统(iosLib)是 VxWorks I/O 架构的核心。它维护三个关键数据结构:

  • 文件描述符表:每个任务私有,记录打开的文件描述符与设备/文件的映射。
  • 驱动表:全局唯一,存储每个驱动号的 DRV_ENTRY 结构体,包含 7 个标准函数指针。
  • 设备表:全局唯一,存储每个设备名与驱动号的关联。
VxWorks I/O 系统分层架构 应用层:用户任务(Task) 文件系统层:dosFs / rawFs / romFs I/O 子系统:iosLib 文件描述符表 | 驱动表 | 设备表 驱动层:字符设备驱动(xxDrv) 硬件层:外设寄存器 / 中断控制器
关键点:VxWorks 的 I/O 子系统不区分“字符设备”和“块设备”的驱动注册方式。所有驱动都通过 iosDrvInstall() 注册到驱动表,区别在于实现哪些回调函数。字符设备通常实现 open、close、read、write、ioctl,而块设备额外需要 blkRd、blkWrt。

1.3 设备驱动与文件系统关系

在 VxWorks 中,设备驱动与文件系统的关系通过设备文件来建立。设备文件是文件系统中的一个特殊节点,它不存储实际数据,而是指向一个具体的硬件设备。用户态任务通过操作设备文件来间接控制硬件。

设备驱动的注册流程通常包含以下步骤:

  1. 驱动初始化:调用 iosDrvInstall() 注册驱动回调函数,返回驱动号。
  2. 设备创建:调用 iosDevAdd() 将设备名与驱动号关联,添加到设备表。
  3. 文件系统挂载:设备文件出现在文件系统目录树中(如 /dev/)。
  4. 用户访问:任务通过 open("/dev/xxx", ...) 打开设备文件,触发驱动回调。
/* 字符设备驱动注册示例 */
STATUS myDrvInit(void)
{
    int drvNum;

    /* 1. 注册驱动回调 */
    drvNum = iosDrvInstall(myOpen,    /* open */
                           myClose,   /* close */
                           myRead,    /* read */
                           myWrite,   /* write */
                           myIoctl,   /* ioctl */
                           NULL,      /* delete (unused) */
                           NULL);     /* select (unused) */

    if (drvNum == ERROR)
        return ERROR;

    /* 2. 创建设备节点 */
    if (iosDevAdd(&myDevHdr, "/dev/myDev", drvNum) == ERROR)
        return ERROR;

    return OK;
}

设备文件与普通文件的区别:

特性 普通文件 设备文件
数据存储 存储在磁盘/Flash 无存储,映射到硬件寄存器
访问方式 通过文件系统缓存 直接穿透到驱动
生命周期 持久化存在 随驱动加载/卸载
并发访问 文件系统提供锁保护 驱动开发者自行管理
ioctl 支持 有限 核心控制接口
设备驱动与文件系统关系图 用户任务 文件系统 设备文件 驱动表 设备表 硬件设备
常见陷阱:初学者容易混淆“设备文件”和“普通文件”的并发语义。普通文件在 VxWorks 文件系统层有内置的读写锁保护,而设备文件没有任何默认的并发保护。如果多个任务同时 write() 同一个字符设备,驱动回调函数可能被并发执行,导致寄存器竞争、数据错乱甚至系统崩溃。这正是本课程后续章节要深入探讨的锁机制问题。

1.4 本章小结

本章建立了字符设备驱动的基础知识框架:

  • 字符设备驱动以顺序字节流方式访问硬件,无缓冲、无随机访问。
  • VxWorks I/O 系统采用五层架构,I/O 子系统(iosLib)是核心分发器。
  • 设备驱动通过设备文件与文件系统关联,用户态任务通过标准文件接口操作硬件。
  • 字符设备驱动没有默认的并发保护,驱动开发者必须自行实现锁机制。