最近有在做一個初始化設備的動作,但是發現在相同的文件夾下已經有兩個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