module_init宏

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

猜你喜欢

转载自blog.csdn.net/qq_36412526/article/details/83661953