“HelloWorld”驱动:在内核空间加载和卸载驱动
当一个设备驱动模块被加载进内核,一些诸如复位设备、预留RAM(reserving RAM)、中断和输入输出端口等预备工作经常会被执行。
我们需要展示两个函数:module_init和module_exit,这两个函数在内核完成了上述的任务。他们和用户空间的insmod和rmmod相对应,前面我们提到过,这两个命令式用来安装和卸载模块的。总的来说,用户命令insmod和rmmod使用的是内核的函数module_init 和 module_exit。
让我们来看一个实现传统程序Hello world的程序:
<hello.c> =
#include<linux/init.h>
#include<linux/module.h>
#include<linux/kernel.h>
MODULE_LICENSE("DualBSD/GPL");
static inthello_init(void) {
printk("<1>Hello world!\n");
return 0;
}
static voidhello_exit(void) {
printk("<1>Bye, cruel world\n");
}
module_init(hello_init);
module_exit(hello_exit);
实际上函数hello_init和hello_exit可以取任何你想取的名字。但是,为了将他们和对应的加载和卸载函数相对应,他们必须作为参数传递给相应的module_init和module_exit函数。
这里使用了printk函数,除了它只工作在内核空间外它和我们熟知的printf函数非常相似。符号“<1>”表明了这个消息具有高优先级(小数字)。这样,除了能够在内核系统日志文件当中得到这个消息外,你还可以在系统的控制台接收到这个消息。
在添加了它的名字到“Makefile”中后,这个模块也可以用之前的命令进行编译。
<Makefile2> =
obj-m :=nothing.o hello.o
在本片文章之后,我将编写Makefiles文件作为了一个练习留给了读者。一个可以编译本指南中所有模块的Makefile在本文的附录A中可以找到。
当一个模块被加载或者卸载的时候,在系统的控制台都将打印写在printk函数中的消息。如果这些消息没有在控制台出现,你可以使用dmesg命令查看他们或者使用命令“cat /var/log/syslog”查看系统日志。
下表显示了这两个新的函数
Event | User functions | Kernel functions |
Load module | Insmod | module_init() |
Open device |
|
|
Read device |
|
|
Write device |
|
|
Close device |
|
|
Remove module | rmmod | module_exit() |
表 设备驱动事件和与对应的在用户空间和内核空间的交互函数