module_init宏
用法:
module_init(am335x_gpio_init);
功能解析:
module_init宏定义在include\linux\init.h
#ifndef MODULE
.......
/**
* module_init() - driver initialization entry point 驱动初始化入口
* @x: function to be run at kernel boot time or module insertion 参数x:内核启动或模块ins时调用的函数
*
* module_init() will either be called during do_initcalls() (if
* builtin) or at module insertion time (if a module). There can only
* be one per module.module_init()
* module_init() 当编译进内核时在do_initcalls() 调用,或者编译成模块时在模块插入时调用
*/
#define module_init(x) __initcall(x);
/**
* module_exit() - driver exit entry point
* @x: function to be run when driver is removed
*
* module_exit() will wrap the driver clean-up code
* with cleanup_module() when used with rmmod when
* the driver is a module. If the driver is statically
* compiled into the kernel, module_exit() has no effect.
* There can only be one per module.
*/
#define module_exit(x) __exitcall(x);
#else /* MODULE */
......
/* 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)));
......
#endif
有两种情况:
1.当模块被编译进内核时( builtin)
module_init(am335x_gpio_init);
展开为
static int (*__initcall_am335x_gpio_init6)(void) __used __attribute__((__section__(".initcall6.init"))) = am335x_gpio_init
module_init(am335x_gpio_init);其实就是定义一个函数指针变量名字为:_initcallam335x_gpio_init6,且该函数指针变量的值为am335x_gpio_init函数的地址,被链接到.initcall6.init段。在kernel启动过程中,会调用do_initcalls函数一次调用我们通过xxx_initcall注册的各种函数,优先级高的先执行。所以我们通过module_init注册的函数在kernel启动的时候会被顺序执行,参考module_init注册函数的执行过程。
2.编译成独立模块时
module_init(am335x_gpio_init);
展开为:
static inline initcall_t __inittest(void) \ //定义__inittest()函数用于返回am335x_gpio_init()函数的指针
{ return am335x_gpio_init; } \
int init_module(void) __attribute__((alias(am335x_gpio_init))); // 定义init_module为am335x_gpio_init函数的别名
当被编译成模块时module_init(am335x_gpio_init);定义了一个__inittest()函数用于返回am335x_gpio_init()函数的指针,定义init_module为am335x_gpio_init函数的别名,在插入模块时无需知道am335x_gpio_init名称就可以通过调用init_module别名来执行模块初始化任务,关于别名的用法,参考我的另一篇博文定义函数属性之alias