1. 字符设备驱动概述

1.1.1 字符设备的概念

字符设备(Character Device)是 Linux 驱动模型中最基础、最常用的设备类型。它以字节流的形式进行数据传输,数据按顺序、逐个字节地读写,不支持随机访问。典型的字符设备包括:串口、键盘、鼠标、触摸屏、LED、GPIO、I2C/SPI 从设备等。

核心特征:字符设备的数据访问如同读写文件——打开、读取、写入、关闭,操作接口与普通文件高度一致。用户空间通过 open()、read()、write()、close() 等系统调用与字符设备交互。

1.1.2 字符设备 vs 块设备 vs 网络设备

Linux 内核将设备划分为三大类型,理解它们的区别是驱动开发的基础。

对比维度 字符设备 块设备 网络设备
数据访问方式 字节流,顺序读写 块(固定大小,如 512B/4KB),随机访问 数据包(Packet),异步收发
设备节点 /dev/ttyS0、/dev/input/event0 /dev/sda、/dev/mmcblk0 无设备节点,通过 socket 接口访问
文件操作接口 open/read/write/ioctl/close open/read/write/mmap + 块层缓存 socket/bind/send/recv
内核实现 struct file_operations struct block_device_operations + 块层框架 struct net_device_ops + 网络协议栈
典型硬件 UART、GPIO、I2C、SPI、ADC eMMC、NAND Flash、SD 卡、硬盘 以太网 PHY、WiFi、CAN
是否经过内核缓存 通常不经过页缓存(直接 I/O) 经过页缓存(Page Cache) 经过网络协议栈缓存
开发视角:嵌入式 Linux 驱动开发中,字符设备驱动占比最高(约 70% 以上)。掌握字符设备驱动是入门内核驱动开发的第一步,也是理解更复杂驱动框架(如块设备、网络设备、USB、PCIe)的基础。

1.1.3 驱动在内核中的角色

设备驱动是操作系统与硬件之间的桥梁。在内核架构中,驱动承担以下关键职责:

  • 硬件抽象:将硬件寄存器、中断、DMA 等底层细节封装为统一的操作接口。
  • 系统调用分发:将用户空间的 read/write/ioctl 等请求转化为硬件操作序列。
  • 中断处理:响应硬件中断,完成数据接收、状态通知、唤醒等待进程等任务。
  • 资源管理:管理硬件寄存器地址、中断号、DMA 通道、时钟等系统资源。
  • 电源管理:配合内核 PM 框架实现设备的休眠、唤醒、频率调节。
Linux 内核中字符设备驱动的角色与分层 用户空间(User Space) 应用程序:open / read / write / ioctl / close 系统调用层(VFS 虚拟文件系统) 字符设备驱动层(Character Device Driver) struct file_operations:.open / .read / .write / .ioctl / .release 设备号注册 | cdev 初始化 | 硬件操作封装 硬件抽象层(HAL / 寄存器操作) ioremap / readl / writel / GPIO 操作 / 中断注册 硬件设备(Hardware) UART 控制器 / GPIO 引脚 / I2C 从设备 / 传感器 驱动是内核中唯一直接操作硬件寄存器的软件层,对上层提供标准化接口

1.1.4 驱动开发流程总览

一个完整的字符设备驱动开发遵循以下标准化流程,本课程将逐一深入每个环节:

  1. 设备号申请:使用 alloc_chrdev_region() 或 register_chrdev_region() 获取主/次设备号。
  2. cdev 初始化与注册:调用 cdev_init() 绑定 file_operations,通过 cdev_add() 将设备加入内核。
  3. 硬件初始化:映射寄存器地址(ioremap)、注册中断(request_irq)、初始化 GPIO/时钟。
  4. 实现 file_operations:编写 .open、.read、.write、.ioctl、.release 等回调函数。
  5. 设备节点创建:手动 mknod 或通过 udev/mdev 自动创建设备节点。
  6. 用户空间测试:编写应用程序调用驱动接口,验证功能正确性。
  7. 驱动卸载与清理:调用 cdev_del()、unregister_chrdev_region()、释放硬件资源。
字符设备驱动开发全流程 ① 设备号申请 alloc_chrdev_region ② cdev 注册 cdev_init + cdev_add ③ 硬件初始化 ioremap / request_irq ④ 实现操作函数 file_operations 回调 ⑤ 设备节点创建 mknod / udev 自动创建 ⑥ 用户空间测试 应用程序验证驱动 ⑦ 驱动卸载清理 cdev_del / 资源释放 本课程将按照此流程,从第 2 章开始逐步骤实现一个完整的字符设备驱动
常见误区:初学者容易跳过“硬件初始化”直接编写 file_operations,导致驱动加载成功但无法操作硬件。正确的顺序是:先确保硬件寄存器映射和中断注册成功,再实现数据读写接口。

1.1.5 本章小结

  • 字符设备以字节流方式工作,是嵌入式 Linux 中最常见的设备类型。
  • 与块设备(随机访问、有缓存)和网络设备(数据包、无设备节点)有本质区别。
  • 驱动在内核中承担硬件抽象、系统调用分发、中断处理、资源管理四大核心角色。
  • 开发流程分为7 个标准步骤,从设备号申请到卸载清理形成完整闭环。