什么是设备驱动程序
同一个应用软件可以在不同的硬件平台的上运行。
同样的open函数可以操作不同的硬件设备,实现设备无关性。
这些功能的实现都离不开设备确定函数的支持。
设备驱动程序是操作系统内核的内容。
应用程序只能通过操作系统操作硬件,本质上是通过设备驱动程序去操作硬件。
设备驱动程序的编译方式
设备驱动程序可以直接编译进内核镜像,也可以编译成模块。
编译成模块时,可以通过一条命令加载这个设备驱动程序模块,也可以通过一条命令卸载这个设备驱动程序。这种方式在修改设备驱动程序时比较方便,不用每一次都编译一遍内核。
内核的模块化编程
Linux是一个单内核架构的操作系统,即把常用的功能放在内核内部。因此在操作系统内部编程的效率会很高。但是,如果某处需要修改,则需要整个内核都修改。
还有一种叫做微内核的操作系统,操作系统内核只有进程管理,其他的都在操作系统外面,操作起来会更麻烦,通信效率较低。
Linux发展了可加载的模块化设计机制(LKMs)。相当于就把设备驱动程序编程成模块,放在操作系统外面来。需要的时候可以动态加载。
lsmod命令可以查看当前操作系统的加载的模块的信息。
一个内核模块的编程:
- 模块加载函数
- 模块卸载函数
- 模块参数:可选
- 模块导出符号:供其他模块使用,可选
- 模块描述信息:可选
模块加载函数
static int __init test_init(void)
{
//初始化代码
}
module_init(test_init);
static表示函数只能在模块内部使用。
_ _init表示这是一个模块加载函数。
模块卸载函数
static int __exit test_exit(void)
{
//释放代码
}
module_exit(test_exit);
一般来说,模块加载函数与模块卸载函数完成相反的功能,如注册与反注册。
模块参数
例如:
Module_parm(str_pram,int,S_IRUGO);
insmod 模块名 参数1名=参数1值 参数2名=参数2值
模块导出符号
模块通过EXPOT_SYMBOL导出模块中的符号供给其他模块使用。
模块使用
1
内核必须支持模块可加载。编译时勾选相关选项。
2
modinfo命令可以查看模块的信息
3
insmod 模块名.ko 模块参数 加载模块
4
modprobe 模块名 自动处理模块依赖关系并加载模块
5
rmmod 模块名.ko 卸载模块
模块编译
1
编写Makefile文件
obj -m := <module_name>.o
根据module_name.c编译生成module_name.o,然后经过链接生成module_name.ko
2
调用Makefile编译
Make -C $KDIR M=$PWD modules
Make指令的两个参数很重要
$表示系统变量
$M=PWD表示Makefile放在当前路径
modules编译后生成.ko文件
应注意,编译这个模块,是基于哪一个内核源代码的来编译的,最后这个模块运行的时候一定要运行在这个这个源代码路径所指定的内核源代码的系统上。