Linux字符设备驱动开发新框架详解
一、新旧驱动框架对比
传统字符设备驱动流程
- 手动分配设备号 (
register_chrdev_region
) - 实现
file_operations
结构体 - 使用
mknod
手动创建设备节点
新式驱动框架优势
- 自动设备号分配:动态申请避免冲突
- 自动节点创建:通过
class_create
/device_create
实现 - 更好的设备管理:通过
struct cdev
规范设备操作cdev_add
向 Linux 系统添加字符设备…
二、自动设备号申请机制
核心函数实现
/* 动态分配设备号 */
alloc_chrdev_region(&newchrled.devid, 0, 1, LED_NAME);
newchrled.major = MAJOR(newchrled.devid); // 提取主设备号
newchrled.minor = MINOR(newchrled.devid); // 提取次设备号/* 传统静态分配示例(对比) */
// register_chrdev_region(devid, 1, "led");
设备号管理流程
- 调用
alloc_chrdev_region
申请未使用设备号 - 通过
MAJOR
/MINOR
宏分解主次设备号 - 驱动卸载时使用
unregister_chrdev_region
释放
三、自动创建设备节点
现代驱动节点创建
/* 创建设备类 */
newchrled.class = class_create(THIS_MODULE, LED_NAME);/* 创建设备节点 */
newchrled.dev = device_create(newchrled.class, NULL, newchrled.devid, NULL, LED_NAME);
工作机制说明
class_create
:在/sys/class下创建设备类device_create
:基于udev机制自动创建/dev节点- 无需手动执行
mknod
命令
四、完整驱动加载流程
初始化函数实现
static int __init newchrled_init(void)
{/* 硬件初始化 */ioremap(CCM_CCGR1_BASE, 4); // 寄存器地址映射/* 字符设备注册四部曲 */1. alloc_chrdev_region() // 设备号申请2. cdev_init() // 初始化cdev结构体3. cdev_add() // 添加设备到系统4. device_create() // 自动创建设备节点
}
驱动卸载流程
static void __exit newchrled_exit(void)
{/* 逆向释放资源 */1. device_destroy() // 删除设备节点2. class_destroy() // 销毁设备类3. cdev_del() // 移除字符设备4. unregister_chrdev_region() // 释放设备号
}
五、应用层交互示例
int main(int argc, char *argv[])
{// 打开自动创建的设备节点int fd = open("/dev/newchrled", O_RDWR);// 控制指令下发unsigned char cmd = 1; // 1:开灯 0:关灯write(fd, &cmd, sizeof(cmd));// 关闭设备close(fd);return 0;
}
六、测试命令集
# 加载驱动模块
insmod newchrled.ko
# 方法二
modporbe nwechrled.ko# 查看自动生成的设备节点
ls -l /dev/newchrled# 查看内核分配的设备号
dmesg | grep newchrled# 测试LED控制
./ledAPP /dev/newchrled 1 # 开灯
./ledAPP /dev/newchrled 0 # 关灯
七、常见问题排查
-
设备节点未生成:
- 检查
class_create
返回值 - 确认udev服务正常运行
- 查看/sys/class下是否生成对应类目录
- 检查
-
权限问题:
sudo chmod 666 /dev/newchrled
-
设备号冲突:
cat /proc/devices | grep newchrled