Linux内核模块加载函数一般以__init标识声明,典型的模块加载函数的形式如代码清单4.2所示。
代码清单4.2 内核模块加载函数
1static int _ _init initialization_function(void) 2{ 3 /* 初始化代码 */ 4} 5module_init(initialization_function);
模块加载函数以“module_init(函数名)”的形式被指定。它返回整型值,若初始化成功,应返回0。而在初始化失败时,应该返回错误编码。在Linux内核里,错误编码是一个接近于0的负值,在<linux/errno.h>中定义,包含-ENODEV、-ENOMEM之类的符号值。总是返回相应的错误编码是种非常好的习惯,因为只有这样,用户程序才可以利用perror等方法把它们转换成有意义的错误信息字符串。
在Linux内核中,可以使用request_module(const char*fmt,…)函数加载内核模块,驱动开发人员可以通过调用下列代码:
request_module(module_name);
灵活地加载其他内核模块。
在Linux中,所有标识为__init的函数如果直接编译进入内核,成为内核镜像的一部分,在连接的时候都会放在.init.text这个区段内。
#def ine _ _init _ _attribute_ _ ((_ _section_ _ (".init.text")))
所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数,并在初始化完成后,释放init区段(包括.init.text、.initcall.init等)的内存。
除了函数以外,数据也可以被定义为__initdata,对于只是初始化阶段需要的数据,内核在初始化完后,也可以释放它们占用的内存。例如,下面的代码将hello_data定义为__initdata:
static int hello_data __initdata = 1; static int __init hello_init(void) { printk(KERN_INFO "Hello, world %d\n", hello_data); return 0; } module_init(hello_init); static void __exit hello_exit(void) { printk(KERN_INFO "Goodbye, world\n"); } module_exit(hello_exit);