技术知识库
字符设备驱动 MOC
字符设备驱动 MOC
本章目标
对应实验手册第 6 章。先通过可以运行的字符设备实验,掌握设备号、cdev、file_operations、设备节点和用户空间数据复制之间的关系;完成本章全部实验后,再集中阅读驱动框架及内核源码调用链。
概念导读
- 字符设备如何把设备节点连接到 file_operations
- misc 设备为什么称为杂项设备
- KFIFO 如何用环形缓冲区管理字符设备数据
- O_NONBLOCK 如何改变字符设备读写语义
- 等待队列如何实现字符设备阻塞读写
- poll 与 epoll 如何发现设备就绪
- 共享设备状态与每次 open 私有状态如何决定进程能否互相唤醒
- FASYNC 与 SIGIO 如何实现异步通知
主线笔记
- 实验 6-1:实现可读写的 martin_mailbox 字符设备
- 实验 6-2/6-3:misc 注册与普通缓冲区虚拟设备
- 实验 6-4:使用 KFIFO 实现可读写邮箱设备
- 扩展:为 KFIFO 邮箱加入 Nonblocking I/O
- 实验 6-6:使用等待队列实现阻塞 KFIFO 邮箱
- 实验 6-7:为八个 KFIFO 设备添加 poll 支持
- 实验 6-9:使用 SIGIO 实现字符设备异步通知
故障复盘
- 模块已加载但字符设备没有保留
- copy_to_user 成功但 cat 没有输出
- KFIFO 写满后 echo 持续重试
- dd 测试非阻塞写时误用了 iflag
- 每次 open 分配独立状态导致写者无法唤醒读者
- 设备节点缺失或设备号失配导致 FASYNC 测试失败
- FASYNC 登记阶段 Oops(待 GDB 分析)
当前进度
- 动态申请设备号。
- 动态分配并注册
cdev。 - 用
file_operations接通open、read和write。 - 用
class_create()、device_create()自动暴露/dev/martin_mailbox。 - 用
copy_from_user()和copy_to_user()完成内存邮箱读写闭环。 - 用
misc_register()简化注册,并通过/dev/misc_mailbox完成读写闭环。 - 理解 misc 设备共用主设备号 10、依靠次设备号区分。
- 实验 6-3:普通缓冲区虚拟设备读写;已合并在
misc_mailbox实验中。 - 实验 6-4:用 KFIFO 替换普通缓冲区,并通过
/dev/kfifo_mailbox完成读写。 - 复现并修复 KFIFO 写满后零长度写导致用户空间持续重试的问题。
- 实验 6-5:满 FIFO 的非阻塞写已返回
-EAGAIN。 - 实验 6-5:空 FIFO 的非阻塞读尚待实际验证。
- 实验 6-6:使用等待队列实现阻塞读取,并观察到空 FIFO 上的
cat进入等待。 - 实验 6-7:8 个独立 misc + KFIFO +
poll模块已完成 ARM64 交叉编译,目标系统运行验证待完成。 - 实验 6-8:已正确解释共享设备状态与每次
open()私有状态导致的唤醒差异;故意错误的目标系统复现作为可选验证保留。 - 实验 6-9:FASYNC/SIGIO 通知闭环已验证,写入 13 字节后监听进程异步读取 13 字节。
- 实验 6-9 进阶:
fasync_insert_entry()Oops 已建立用户态 GDB 类比实验,尚待调试。 - 完成本章其余实验。
- 第 6 章完成后,集中补充驱动框架、VFS 分发路径和相关源码调用链。
延后阅读清单
以下内容不是当前实验的完成阻塞项,统一留到第 6 章实验结束后:
/dev/martin_mailbox的open()如何经 VFS 找到cdev和file_operations。alloc_chrdev_region()、cdev_add()、class_create()、device_create()的内核实现。copy_to_user()、copy_from_user()的架构相关实现与异常处理。- 设备模型、sysfs、devtmpfs 和 udev 的协作过程。
misc_open()如何按次设备号找到struct miscdevice并切换到驱动的file_operations。- KFIFO 如何用递增索引和 2 的幂掩码实现环形寻址。
poll_wait()如何把 epoll 回调挂入设备等待队列,以及ep_poll_callback()如何生成就绪事件。fcntl(F_SETFL, FASYNC)到驱动.fasync、fasync_helper()的调用链。