字符设备注册、CDev 与 Misc 框架
1. Dev_t
字符设备由dev_t标识:
1 | major -> 驱动/分发表 |
静态major用于兼容ABI;新驱动通常alloc_chrdev_region()动态分配。
2. CDev
标准注册:
1 | alloc_chrdev_region |
cdev_add()建立dev_t到cdev的kobject映射。device_create()只建立device model/sysfs和devtmpfs事件,二者不是同一动作。
注销逆序:
1 | device_destroy |
必须先阻止新open,并保证已有fd的私有对象仍存活。
3. Open分发
fs/char_dev.c中的chrdev_open():
- 从inode dev_t查找cdev;
- 缓存
inode->i_cdev; - 增加cdev/module引用;
- 替换
file->f_op; - 调用具体driver
.open。
后续read/write/ioctl直接进入具体fops。
4. register_chrdev
Legacy接口可一次注册整个major。Driver open再按minor分发。mem.c、virtio_console等仍使用该接口。
新多实例driver更适合明确的region+cdev,便于生命周期和sysfs对应。
5. Misc框架
misc.c固定注册major 10并维护misc list。Driver:
1 | struct miscdevice { |
调用misc_register():
MISC_DYNAMIC_MINOR从bitmap分配;- 加入全局list;
device_create_with_groups();- 默认node名来自
name或nodename。
6. Misc Open
所有misc node先进入misc_open():
- 取inode minor;
- 在misc list查找;
- 请求模块;
- 将
file->f_op替换为目标fops; - 把
file->private_data设为miscdevice; - 调目标
.open。
Driver若覆盖private_data,需理解这个初始值。
7. 并发和引用
注册表由mutex保护,但registry锁不保护driver内部状态。Driver需自己处理:
- 多open;
- remove与fd并发;
- ioctl和read并发;
- blocking wait;
- mmap在close后仍存在;
- module卸载。
.owner = THIS_MODULE只保护模块代码,不自动保护platform私有内存。
8. File Private Data
常见模式:
1 | open: |
每fd状态不要误放到全局device结构中,否则多个进程会互相覆盖offset、mode或pending command。
9. Poll
1 | poll_wait(file, &waitq, table) |
状态更新后必须先改变受锁保护的条件,再wake_up_interruptible_poll(),避免丢唤醒。
10. Compat IOCTL
64位RK3588运行32位应用时会进入.compat_ioctl。含pointer、long、alignment或可变数组的结构不能直接复用native布局。
Ioctl命令必须验证:
- magic和number;
- direction/size;
- integer range;
- user pointer;
- reserved bits;
- capability和device state。
正在加载留言…