module_init
最近有在做一个初始化设备的动作,但是发现在相同的文件夹下已经有两个module_init,当我想再添加一个时,发现我添加的这个是最后执行的。由于其他的两个初始化中有用到我添加的部分,所以想提高优先级。没办法,只能看下module_init在initcall的优先级,然后选取一个合适的。
一、同一个文件中的三个module_init
1、我想要添加的部分
static int __init mdss_dsi_bl_driver_init(void)
{
int ret;
ret = mdss_dsi_bl_register_driver();
if (ret) {
pr_err("mdss_dsi_bl_register_driver() failed!\n");
return ret;
}
return ret;
}
module_init(mdss_dsi_bl_driver_init);
2、原始文件中已经存在的部分
module_init(mdss_dsi_driver_init);
... ...
module_init(mdss_dsi_ctrl_driver_init);
问题点:在执行时,发现会优先执行原始文件定义的这两个,即使我把module_init(mdss_dsi_bl_driver_init)的部分提到最前面也是一样的。无奈只好寻求更高优先级的方法。
二、module_init的原始定义
可以发现,module_init的定义是在init.h (kernel\include\linux)中。
#define __initcall(fn) device_initcall(fn)
... ...
/**
* module_init() - driver initialization entry point
* @x: function to be run at kernel boot time or module insertion
*
* 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.
*/
#define module_init(x) __initcall(x);
这里可以看到,module_init仅仅是个宏,实际执行的是__initcall,而__initcall也是个宏,最终执行的是device_initcall
我们就来看下定义device_initcall的地方:
/*
* A "pure" initcall has no dependencies on anything else, and purely
* initializes variables that couldn't be statically initialized.
*
* This only exists for built-in code, not for modules.
* Keep main.c:initcall_level_names[] in sync.
*/
#define pure_initcall(fn) __define_initcall(fn, 0)
#define core_initcall(fn) __define_initcall(fn, 1)
#define core_initcall_sync(fn) __define_initcall(fn, 1s)
#define postcore_initcall(fn) __define_initcall(fn, 2)
#define postcore_initcall_sync(fn) __define_initcall(fn, 2s)
#define arch_initcall(fn) __define_initcall(fn, 3)
#define arch_initcall_sync(fn) __define_initcall(fn, 3s)
#define subsys_initcall(fn) __define_initcall(fn, 4)
#define subsys_initcall_sync(fn) __define_initcall(fn, 4s)
#define fs_initcall(fn) __define_initcall(fn, 5)
#define fs_initcall_sync(fn) __define_initcall(fn, 5s)
#define rootfs_initcall(fn) __define_initcall(fn, rootfs)
#define device_initcall(fn) __define_initcall(fn, 6) //device_initcall也是个宏,但是我们发现,__define_initcall不同之处是第二个参数。由上到下依次增加
#define device_initcall_sync(fn) __define_initcall(fn, 6s)
#define late_initcall(fn) __define_initcall(fn, 7)
#define late_initcall_sync(fn) __define_initcall(fn, 7s)
最终我们调用的实际是__define_initcall,再看下__define_initcall的定义:
/* initcalls are now grouped by functionality into separate
* subsections. ordering inside the subsections is determined
* by link order.
* For backwards compatibility, initcall() puts the call in
* the device init subsection.
*
* The `id' arg to __define_initcall() is needed so that multiple initcalls
* can point at the same handler without causing duplicate-symbol build ERRORs.
*/
#define __define_initcall(fn, id) \
static initcall_t __initcall_##fn##id __used \
__attribute__((__section__(".initcall" #id ".init"))) = fn; \
LTO_REFERENCE_INITCALL(__initcall_##fn##id)
从这里可以看到__define_initcall把传给module_init的函数名组装成以__initcall为前缀的、以6为后缀的函数名,并把这个函数定义到代码段.initcall6.init里面。
只能再往下追,再来看看".initcall" #id ".init",它在kernel/msm-3.18/include/asm-generic/vmlinux.lds.h中:
VMLINUX_SYMBOL(__initcall_start) = .; \
*(.initcallearly.init) \
INIT_CALLS_LEVEL(0) \
INIT_CALLS_LEVEL(1) \
INIT_CALLS_LEVEL(2) \
INIT_CALLS_LEVEL(3) \
INIT_CALLS_LEVEL(4) \
INIT_CALLS_LEVEL(5) \
INIT_CALLS_LEVEL(rootfs) \
INIT_CALLS_LEVEL(6) \
INIT_CALLS_LEVEL(7) \
VMLINUX_SYMBOL(__initcall_end) = .;
__initcall_start = .;
INITCALLS
__initcall_end = .;
__con_initcall_start = .;
*(.con_initcall.init)
__con_initcall_end = .;
__security_initcall_start = .;
*(.security_initcall.init)
__security_initcall_end = .;
到这可以确认对应的数字0是最高优先级执行的,7是最低优先级执行。对于我们来说只需要比6高就可以了。大家可以根据自己的需要在driver中去执行不同的方法:
pure_initcall(fn)
core_initcall(fn)
core_initcall_sync(fn)
postcore_initcall(fn)
postcore_initcall_sync(fn)
arch_initcall(fn)
arch_initcall_sync(fn)
subsys_initcall(fn)
subsys_initcall_sync(fn)
fs_initcall(fn)
fs_initcall_sync(fn)
rootfs_initcall(fn)
device_initcall(fn)
device_initcall_sync(fn)
late_initcall(fn)
late_initcall_sync(fn)
参考:http://blog.chinaunix.net/uid-27664726-id-4243961.html
相关阅读
我们知道在写设备驱动的时候通常要为某个设备实现xxx_init函数,并将该函数传入module_init(xxx_init), 当kernel启动之后该设备驱