1、头文件
#include<linux/module.h>
#include<linux/init.h>
2、初始化
static int__int module_init(void)
{
初始化代码
}
module_init(module_init);
eg:
static int __init hello_init(void)
{
printk("Hello init!%s get number is %d\n",who,num);
// printk("Hello init! The number is %d\n",num);
return 0;
}
module_init(hello_init);
__int初始化函数仅仅在初始化期间使用,一旦初始化完毕,将释放初始化函数所占用的内存,
module_init是必须的,没有该定义,内核将无法执行初始化代码;宏定义会在模块的目标代码中增加一个特殊的代码段,用于说明该初始化函数所在的位置。
当使用 insmod 将模块加载进内核的时候,初始化函数的代码将会被执行。模块初始化代码只与内核模块管理子系统打交道,并不应用程序互。
3、模块退出
static void __exit module_exit(void)
{
模块退出代码
}
module_exit(module_exit);
eg:
static void __exit hello_exit(void)
{
printk("Hello exit!\n");
}
module_exit(hello_exit);
几点说明:
(1) 模块退出没有返回值;
(2) __exit标记这段代码仅用于模块卸载;
(3) module_exit不是必须的。但是,没有module_exit定义的模块无法被卸载,如果需要支持模块卸载则必须有module_exit。
当使用 当使用 rmmod卸载模块时,退出函数的代码将被执行。 模块退出代码只与内核模块管理子系统打交道,并不直接与应用程序交互。
4、许可证
遵循GPL协议
MODULE_LICENSE("GPL")
5、符号导出
如果希望一个模块的符号能被其它模块使用,则必须显式的用将EXPORT_SYMBOL符号导出。
EXPORT_SYMBOL(module_symbol);
eg:
EXPORT_SYMBOL(rtw_get_gpio);
6、模块描述
MODULE_AUTHOR("lyf")
MODULE_DESCRIPTION("hello");
MODULE_VERSION("V1.00");
模块描述以及许可证声明一般放在文件末尾。
7、编译
在Makefile中加入如下指令:
obj-m:=文件名.o
8、带参数的内核模块
延伸参考:https://blog.csdn.net/gatieme/article/details/51009094
static int num = 1;
static char *who = "lyf";
module_param(num,int,S_IRUGO);
module_param(who,charp,S_IRUGO);
S_IRUGO 值在include/linux/stat.h中有定义,包含到module.h中了
传参模块需包含muduleparam.h头文件,包含到module.h中了
9、测试例程
文件名为hello.c,Makefile中添加:obj-m := hello.o可进行编译
#include<linux/module.h>
#include<linux/init.h>
static int num = 1;
static char *who = "lyf";
module_param(num,int,S_IRUGO);
module_param(who,charp,S_IRUGO);
static int __init hello_init(void)
{
printk("Hello init!%s get number is %d\n",who,num);
return 0;
}
static void __exit hello_exit(void)
{
printk("Hello exit!\n");
}
module_init(hello_init);
module_exit(hello_exit);
MODULE_LICENSE("GPL");
运行结果: