0. 前提:
该模块是为了内核2.6的准备的.据说,2.6前的与现在不同.呵呵,不好意思,我现在的内核版本已经是3.*.*了.
1. linux内核模块的程序结构-
1. 模块加载函数(必须)
2. 模块卸载函数(必须)
3. 模块许可证声明(必须)
4. 模块参数(可选)
5. 模块导出符号(可选)
6. 模块作者的等信息声明(可选)
2. 模块加载:
static int __init initialization_function(void)
{
/*初始化代码*/
}
module_init(initialization_function);
模块加载函数必须使用module_init(函数名)的形式被指定。
它返回整型值,若初始化成功,应返回0,而初始化失败时,应返回错误编码。
在linux内核中,错误编码是一个负值,在中定义,包括-ENODEV、-ENOMEM之类的符号值
1. 加载其它系统模块:
request_module(module_name);
或
request_module("char-major-%d-%d",MAJOR(dev),MINOR(dev));
3. 模块卸载:
static void __exit cleanup_function(void)
{
/*释放代码*/
}
module_exit(cleanup_function);
功能说明:
1. 模块加载的东西,在模块卸载时清除;
2. __init与__exit会在对应函数运行完成后自动回收内存,实际上这两个均是宏
4. 模块许可证:
MODULE_LICENSE("GPL/GPL v2/GPL and additional rights/Dual BSD");
若不加入该模块,则当模块被加载时,将会收到内核被污染(kernel tainted)的警告
5. 模块参数:
module_param(name,type,perm) or
module_parm_arrary(name,type,num,perm);
MODULE_PARM_DESC(name, "string"); //这个的目的是生成对于变量name的描述信息
其中,name指参数名(也就是变量名),type(参数类型) num(数组长度) perm(权限掩码)
type有: bool, charp(字符串指针), int, long, short, uint, ulong, ushort
perm: =0时,根本没有sysfs项; S_IRUGO,可读不可改; S_IRUGO | S_IWUGO允许root来改变参数;
1. 模块参数是指模块加载时可以传递给模块的值,它本身对应模块内部的变量
2. 模块内部的全局变量,最好加static前缀,让变量拥有文件作用域,就不会污染其它模块的变量
3. 模块被加载时,若perm非0,则模块可以在/sys/module目录下出现该模块名对应的目录;
6. 模块导出函数:
EXPORT_SYMBOL(符号名);
EXPORT_SYMBOL_GPL(符号名);
EXPORT_SYMBOL(sub_func);
这个导出函数会在/proc/kallsyms中找到对应的导出符号
7. 其它信息:
MODULE_AUTOR("作者信息");
MODULE_DESCRIPTION("模块描述信息");
MODULE_VERSION("版本信息");
MODULE_ALIAS("别名信息");
MODULE_DEVICE_TABLE("设备表信息"); //对于USB或PCI等设备驱动,会创建支持设备列表
8. 相关Makefile的写法
Makefile:
obj-m := module_param.o
//PWD = $(shell pwd); 该变量已经自动定义
INC = /lib/modules/$(shell unamr -r)/build
all:
make -C $(INC) M=$(PWD) modules
clean:
make -C $(INC) M=$(PWD) clean
然后,执行make命令,编译生成module_param.ko文件
9. 模块加载相关:
lsmod: 列出所有模块
insmod:加载模块,不会自动寻找信赖项
modprobe:加载模块,自动寻找相关依赖项
depmod: 生成modules.dep与map文件