1 模块的初始化和退出函数
初始化与退出函数:
module_init(dm9000_init);
module_exit(dm9000_cleanup);
其实是宏定义,在模块执行时告诉内核初始化函数和去初始化的位置让其执行初始化和退出操作。
目前linux支持两种方式运行设备驱动,一种是built-in kernel,另一种module。
1.1 built-inmodule_init(x) 相关宏定义:
#define module_init(x) __initcall(x);
#define __initcall(fn) device_initcall(fn)
#define device_initcall(fn) __define_initcall("6",fn,6)
#define __define_initcall(level,fn,id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" level ".init"))) = fn
typedef int (*initcall_t)(void);
把上面的宏变换展开:
Static initcall_t __initcall_dm9000_init_6 __used __attribute__((__section__(“.initcall” 6 “.init”)))=dm9000_init
其实是定义了一个Static initcall_t类型的函数指针__initcall_dm9000_init_6
这里我们需要了解一下gcc的__attribute__机制,是在编译的过程中告诉编译器该函数一些属性,__attribute__((__section__(“.initcall” 6 “.init”)))意思是把函数放入“.initcall” 6 “.init” 段中,然后把dm9000_init赋值给它。
__used也是一个__attribute__相关宏:
#if __GNUC_MINOR__ >= 3
# define __used __attribute__((__used__))
#else
# define __used __attribute__((__unused__))
#endif
中关于used与unused有解释,__attribute__修饰的函数或变量可能使用/不使用,可以避免编译器产生告警。
结合vmlinux.lds中的
.initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {
__initcall_start = .;
*(.initcallearly.init) __early_initcall_end = .; *(.initcall0.init) *(.initcall0s.init) *(.initcall1.init) *(.initcall1s.init) *(.initcall2.init) *(.initcall2s.init) *(.initcall3.init) *(.initcall3s.init) *(.initcall4.init) *(.initcall4s.init) *(.initcall5.init) *(.initcall5s.init) *(.initcallrootfs.init) *(.initcall6.init) *(.initcall6s.init) *(.initcall7.init) *(.initcall7s.init)
__initcall_end = .;
}
系统启动时
start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls()
do_initcalls:
static void __init do_initcalls(void)
{
initcall_t *call;
for (call = __initcall_start; call < __initcall_end; call++)
do_one_initcall(*call);
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
1.2module按如下宏展开:
/* Each module must use one module_init(). */
#define module_init(initfn) \
static inline initcall_t __inittest(void) \
{ return initfn; } \
int init_module(void) __attribute__((alias(#initfn)));
/* This is only required if you want to be unloadable. */
#define module_exit(exitfn) \
static inline exitcall_t __exittest(void) \
{ return exitfn; } \
void cleanup_module(void) __attribute__((alias(#exitfn)));
在用insmod加载模块时会调用模块的init函数.