分类: LINUX
2007-04-19 20:26:44
构建和运行模块快速参考
__KERNEL__,__MODULE__预处理程序符号。在编译模块化内核代码时都必须定义。可以在源文件中定义,也可以在gcc参数中定义。
#include
module_init(init_function);
module_init(init_function);
2.4内核中用来标记模块的初始化和清除函数
#include
MOD_INC_USE_COUNT;
MOD_DEC_USE_COUNT;
MOD_IN_USE;计数非0时返回真。
操作使用计数的宏。
/proc/modules
当前装入内核的模块列表。
内核符号表相关:
EXPORT_SYMTAB;
预处理程序宏,在模块需要导出符号时定义。
EXPORT_NO_SYMBOLS;
该宏指明模块不需要导出任何符号到内核。
EXPORT_SYMBOL(symbol);
EXPORT_SYMBOL_NOVERS(symbol);
用来导出单个符号到内核的宏。第二个宏导出的符号不带版本控制信息。
MODULE_PARM(variable,type);
MODULE_PARM_DESC(variable,description);
将一个模块变量定义为参数的宏,用户随后可以在装入模块时调整这个变量的值。
eg:insmod module名 variable=(type)设定值
模块也可以从命令行获取参数。但不是通过以前你习惯的argc/argv。要传递参数给模块,首先将获取参数值的变量声明为全局变量。然后使用宏 MODULE_PARM()(在头文件linux/module.h)。运行时,insmod将给变量赋予命令行的参数,如同 ./insmod mymodule.o myvariable=5。为使代码清晰,变量的声明和宏都应该放在 模块代码的开始部分。宏MODULE_PARM()需要两个参数,变量的名字和其类型。支持的类型有" b": 比特型,"h": 短整型, "i": 整数型," l: 长整型和 "s": 字符串型,其中正数型既可为signed也可为unsigned。 字符串类型应该声明为"char *"这样insmod就可以为它们分配内存空间。你应该总是为你的变量赋初值。 这是内核编程,代码要编写的十分谨慎。举个例子:
int myint = 3;
char *mystr;
MODULE_PARM(myint, "i");
MODULE_PARM(mystr, "s");
数组同样被支持。在宏MODULE_PARM中在类型符号前面的整型值意味着一个指定了最大长度的数组。 用'-'隔开的两个数字则分别意味着最小和最大长度。下面的例子中,就声明了一个最小长度为2,最大长度为4的整形数组。
int myshortArray[4];
MODULE_PARM (myintArray, "3-9i");
将初始值设为缺省使用的IO端口或IO内存是一个不错的作法。如果这些变量有缺省值,则可以进行自动设备检测, 否则保持当前设置的值。
最后,还有这样一个宏,MODULE_PARM_DESC()被用来注解该模块可以接收的参数。该宏 两个参数:变量名和一个格式自由的对该变量的描述。
MODULE_AUTHOR(author);
MODULE_DESCRIPTION(description);
MODULE_SUPPORTED_DEVICE(device);
在目标文件中添加关于模块的文档信息。
#inculde
必须的头文件。除非定义了__NO__VERSION__,否则它被包含在
__NO_VERSION__
预处理程序符号。用来防止在
#include
int printk(const char * fmt , ...);
函数printf的内核版。
#include
void *kmalloc(unsigned int size , int priority);
void kfree(void *obj);
函数malloc和free的内核版,使用GFP_KERNEL作为priority参数值。
#include
int check_region(unsigned long from, unsigned long extent);
struct resource *request_region(unsigned long from, unsigned long extern, const char *name);
void release_region(unsigned ling from, unsigned long extern);
注册和释放I/O内存区域的宏。
__init和__exit宏
展示了内核2.2以后引入的一个新特性。注意在负责“初始化”和“清理收尾”的函数定义处的变化。宏 __init的使用会在初始化完成后丢弃该函数并收回所占内存,如果该模块被编译进内核,而不是动态加载。
宏__initdata同__init 类似,只不过对变量有效。
宏__exit将忽略“清理收尾”的函数如果该模块被编译进内核。同宏 __exit一样,对动态加载模块是无效的。这很容易理解。编译进内核的模块 是没有清理收尾工作的, 而动态加载的却需要自己完成这些工作。
这些宏在头文件linux/init.h定义,用来释放内核占用的内存。 当你在启动时看到这样的Freeing unused kernel memory: 236k freed内核输出,上面的 那些正是内核所释放的。
/proc/ksyms
公共内核了符号表。
/proc/ioports
系统中安装的设备所占用的I/O端口列表。
/proc/iomen
已分配内存区域的列表。