利用Linux设备驱动程序的第一个例程:Hello World模块学习内核模块的结构。
1 #include <linux/init.h> 2 #include <linux/module.h> 3 4 static int __init hello_init(void) 5 { 6 printk(KERN_ALERT"Hello World\n"); 7 return 0; 8 } 9 10 static void __exit hello_exit(void) 11 { 12 printk(KERN_ALERT"Goodbye, cruel world\n"); 13 } 14 15 module_init(hello_init); 16 module_exit(hello_exit); 17 18 MODULE_LICENSE("GPL");
1、 所有模块都包含以下两个头文件:
#include <linux/init.h> 2 #include <linux/module.h>
module.h包含有可装载模块所需要的大量符号和函数定义。
包含init.h的目的是指定初始化和清除函数。
2、尽管不是严格要求,但模块应该指定代码所使用的许可证。
1 MODULE_LICENSE("GPL");
内核能够识别的许可证有:
1 “GPL”(任一版本的GNU通用公共许可证) 2 “GPL v2”(GPL版本2) 3 “GPL and additional rights”(GPL及附加权利) 4 “Dual BSD/GPL”(BSD/GPL双重许可证) 5 “Dual MPL/GPL”(MPL/GPL双重许可证) 6 “Proprietary”(专有)
如果一个模块没有显示地标记为上述内核可识别的许可证,则会被假定是专有的,而内核装载这种模块就会被“污染”。
另外,可在内核中包含其他描述性定义:
上述MODULE_声明可出现在源文件中源代码函数以外的任何地方,新近的内核编码习惯是将这些声明放在文件的最后。
3、初始化和关闭
初始化函数的实际定义通常如下:
__init和__initdata表明该函数仅在初始化期间使用。
__devinit和__devinitdata,只有在内核未被配置为支持可热插拔设备的情况下,才会被翻译为__init和__initdata
清除函数的实际定义通常如下:
被标记为__exit的函数只能在模块被卸载或者系统关闭时被调用。
如果一个模块未定义清除函数,则内核不允许卸载该模块。
4、Makefile分析
obj-m := hello.o
代表了我们要构造的模块名称为hello.ko,make会在当前目录下找到hello.c文件进行编译。如果hello.o是由两个源文件生成(比如file1.c和file2.c),则正确的makefile可如下编写:
obj-m := hello.o
hello-objs := file1.o file2.o
make -C $(KDIR) M=$(PWD) modules ARCH=arm CROSS_COMPILE=arm-linux-
-C $(KDIR) 指定了内核源代码的位置,其中保存有内核的顶层makefile文件。
M=$(PWD) 指定了模块源代码的位置
modules 目标指向obj-m变量中设定的模块。
insmod hello.ko
dmesg