linux设备驱动之字符设备驱动
一、cdev结构体
成员/功能 | 说明 | 相关操作函数/宏 | |
---|---|---|---|
kobj | 内嵌的kobject对象,用于Linux设备模型管理,实现引用计数和sysfs接口 | kobject_init() | |
owner | 指向拥有该结构体的模块指针(通常为THIS_MODULE ),防止模块卸载时设备仍被使用 | 模块宏THIS_MODULE | |
ops | 指向file_operations 结构体的指针,定义设备操作接口(如read /write ) | cdev_init() 初始化时绑定 | |
list | 链表头,用于将多个cdev 连接成链表,由内核统一管理 | list_add() 等内核链表操作 | |
dev | 设备号(32位),高12位为主设备号,低20位为次设备号 | MKDEV() 、MAJOR() 、MINOR() | |
count | 设备实例数量(如一个驱动管理多个同类设备) | 注册时通过cdev_add() 的count 参数指定 | |
初始化函数 | cdev_init() :关联cdev 与file_operations ;cdev_alloc() :动态分配cdev 内存 | cdev_init(struct cdev *, struct file_operations *) | |
注册/注销函数 | cdev_add() :向内核注册设备;cdev_del() :注销设备 | 需配合register_chrdev_region() 或alloc_chrdev_region() 使用 | |
设备号管理 | register_chrdev_region() :已知设备号时注册;alloc_chrdev_region() :动态申请未占用设备号 | 释放设备号需调用unregister_chrdev_region() |
二、字符设备驱动的组成
组件 | 功能描述 | 关键数据结构/API | 开发注意事项 |
---|---|---|---|
设备号管理 | 标识设备实例(主设备号区分驱动,次设备号区分实例) | dev_t 类型、MKDEV() /MAJOR() /MINOR() 宏、register_chrdev_region() 或动态分配alloc_chrdev_region() 48 | 需避免直接操作设备号位宽,使用内核宏保证兼容性4 |
cdev结构体 | 内核中描述字符设备的核心对象,关联操作方法与设备号 | struct cdev (含kobj 、ops 、dev 等成员)、cdev_init() 初始化、cdev_add() 注册58 | 需通过cdev_del() 注销防止内存泄漏8 |
file_operations | 定义设备操作接口(如open /read /write /ioctl ) | struct file_operations (需实现至少owner 、read 、write 等函数指针)35 | 用户空间数据交互需使用copy_{to,from}_user() 保证安全23 |
设备文件节点 | 用户空间访问设备的入口(如/dev/xxx ) | 手动mknod 或自动生成(class_create() +device_create() )18 | 推荐自动生成节点以适配现代内核1 |
模块初始化/退出 | 驱动加载/卸载时的资源管理 | module_init() /module_exit() 宏、资源释放函数(如unregister_chrdev_region() )12 | 必须实现清理逻辑防止残留2 |
同步机制 | 处理多进程/线程并发访问 | mutex_lock() 、spin_lock() 等内核同步原语7 | 需根据场景选择锁类型(如互斥锁适合长时间持有)7 |
调试与日志 | 驱动调试信息输出 | printk() 分级日志、dynamic_debug 动态调试3 | 生产环境需控制日志级别3 |
注意:
- 完整驱动流程:设备号申请 →
cdev
初始化 → 实现file_operations
→ 注册设备 → 创建设备节点。 - 用户空间交互:通过
/dev/
下的文件节点调用驱动接口,内核通过file_operations
转发到具体函数。