Linux模块化增加设备驱动程序
目录
目的
- 采用模块方法,添加一个新的字符设备驱动程序,实现打开/关闭、读/写等基本操作
- 编写一个应用程序,测试添加的驱动程序
开发环境
- 操作系统: ubuntu 16.04LTS 64位
- 内核版本:linux-4.14.141
- 内存:8G
- 处理器: IntelR CoreTM i5-6200U CPU@ 2.30GHz×4
- 编辑器: Vim
- 编译器: gcc version 5.4.0 20160609
实验步骤
- 编写设备驱动程序源文件
mydev.c - 编写
Makefile 文件,用于执行编译任务 - 将设备驱动程序源文件和Makefile文件拷贝到
/usr/src/linux-4.14.141/drivers/misc/mydev 目录下,在该目录打开终端 - 执行
make 命令,利用Makefile文件进行设备驱动模块编译,编译成功后生成mydev.ko 文件 - 执行
insmod mydev.ko ,加载设备驱动模块 - 通过
lsmod 命令查看模块是否加载成功,通过cat /proc/devices 命令查看新增设备名mydev和主设备号241 - 进入
/dev 目录,执行命令mknod /dev/mydev c 241 0 ,生成设备文件,其中,mydev为设备文件名,241为主设备号,0为从设备号,c表示字符设备,执行成功后在/dev目录中会生成一个新设备文件 - 编译测试程序,执行并进行测试
关键代码
打开设备
-
通过 MAJOR 和MINOR 返回主次设备号: printk("mydev: Main device number is %d \n Slave device number is %d\n", MAJOR(inode->i_rdev), MINOR(inode->i_rdev));
-
使用静态变量保存打开设备的进程数: static int open_process = 0;
-
当设备未被占用,占有设备,当设备被占用,进程挂起:
if (open_process == 0) {
open_process++;
try_module_get(THIS_MODULE);
return 0;
} else {
printk(KERN_ALERT "Another process open the char device.\n");
return -1;
}
释放设备,解除占用
--open_process;
module_put(THIS_MODULE);
读取设备缓冲区内容到终端
从内核拷贝数据到用户空间,调用内核函数copy_to_user
copy_to_user(buf, buffer, sizeof(buffer);
输入字符串,从终端读取,写入设备缓冲区
数据从用户空间拷贝到内核,调用内核函数copy_from_user
copy_from_user(buffer, buf, sizeof(buffer);
注册字符设备
result = register_chrdev(DEVICE_NUM, "mydev", &mydev_fops);
注销字符设备
unregister_chrdev(device_num, "mydev");
添加模块宏定义和许可协议
module_init(mydev_init);
module_exit(mydev_exit);
MODULE_LICENSE("GPL");
调试记录
- 使用
Makefile文件 编译设备驱动模块
- 执行
insmod mydev.ko ,加载设备驱动模块
- 通过
cat /proc/devices 命令查看新增设备名mydev和主设备号
- 执行命令
mknod /dev/mydev c 241 0 ,生成设备文件,查看设备文件
- 编译测试程序,执行并进行测试
测试代码目录说明
开源地址:OS_Kernel/compile_kernel&add_syscall
modularly_add_device_drivers 模块化添加驱动设备源文件目录
Linux模块化增加设备驱动程序.md
help.txt Makefile与make命令参考
Makefile make编译脚本
mydev.c 驱动程序源文件
test 测试程序
test.c 测试程序源代码
|