如何修改设备驱动的加载顺序
2011-05-22 01:38
281 查看
内核启动的时候,各个驱动初始化的工作在文件init/main.c中的do_basic_setup()函数中做.
------------------------------------------------------------------------------------------------------
static void __init do_basic_setup(void)
{
/* drivers will send hotplug events */
init_workqueues();
usermodehelper_init();
driver_init();
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
/* Networking initialization needs a process context */
sock_init();
do_initcalls();
}
------------------------------------------------------------------------------------------------------
其中的driver_init()做一些核心的初始化,看看代码就明白了.
相应的驱动程序的初始化在do_initcalls()中做.
------------------------------------------------------------------------------------------------------
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
char *msg;
if (initcall_debug) {
printk(KERN_DEBUG "Calling initcall 0x%p", *call);
print_fn_descriptor_symbol(": %s()", (unsigned long) *call);
printk("/n");
}
(*call)();
msg = NULL;
if (preempt_count() != count) {
msg = "preemption imbalance";
preempt_count() = count;
}
if (irqs_disabled()) {
msg = "disabled interrupts";
local_irq_enable();
}
if (msg) {
printk(KERN_WARNING "error in initcall at 0x%p: "
"returned with %s/n", *call, msg);
}
}
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
------------------------------------------------------------------------------------------------------
这个__initcall_start是在文件 arch/xxx/kernel/vmlinux.lds.S (其中的xxx 是你的体系结构的名称,例如i386)
这个文件是内核ld的时候使用的.其中定义了各个sectioin,看看就明白了。
在这个文件中有个.initcall.init, 代码如下:
------------------------------------------------------------------------------------------------------
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
------------------------------------------------------------------------------------------------------
这里有7个初始化的优先级,内核会按照这个优先级的顺序依次加载.
这些优先级是在文件include/linux/init.h 中定义的. 你注意一下宏 __define_initcall的实现就明白了.
相关代码如下:
#define __define_initcall(level,fn) /
static initcall_t __initcall_##fn __attribute_used__ /
__attribute__((__section__(".initcall" level ".init"))) = fn
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
把自己的驱动的函数名用这些宏去定义之后,
就会对应不同的加载时候的优先级。
其中,我们写驱动中所用到的module_init对应的是
#define module_init(x) __initcall(x);
而
#define __initcall(fn) device_initcall(fn)
所以,驱动对应的加载的优先级为6
在上面的不同的优先级中,
数字越小,优先级越高。
同一等级的优先级的驱动,加载顺序是链接过程决定的,由driver/Makefile确定的,改变这个makefile的内容手动设置谁先谁后。
不同等级的驱动加载的顺序是先优先级高,后优先级低。
我们可以看到,我们经常写的设备驱动程序中常用的module_init其实就是对应了优先级6:
#define __initcall(fn) device_initcall(fn)
#define module_init(x) __initcall(x);
同一个等级的情况下注册顺序跟代码链接的顺序有关系,修改driver/Makefile的内容。
加载顺序可以从system.map中看到设备的注册函数的地址。
------------------------------------------------------------------------------------------------------
static void __init do_basic_setup(void)
{
/* drivers will send hotplug events */
init_workqueues();
usermodehelper_init();
driver_init();
#ifdef CONFIG_SYSCTL
sysctl_init();
#endif
/* Networking initialization needs a process context */
sock_init();
do_initcalls();
}
------------------------------------------------------------------------------------------------------
其中的driver_init()做一些核心的初始化,看看代码就明白了.
相应的驱动程序的初始化在do_initcalls()中做.
------------------------------------------------------------------------------------------------------
static void __init do_initcalls(void)
{
initcall_t *call;
int count = preempt_count();
for (call = __initcall_start; call < __initcall_end; call++) {
char *msg;
if (initcall_debug) {
printk(KERN_DEBUG "Calling initcall 0x%p", *call);
print_fn_descriptor_symbol(": %s()", (unsigned long) *call);
printk("/n");
}
(*call)();
msg = NULL;
if (preempt_count() != count) {
msg = "preemption imbalance";
preempt_count() = count;
}
if (irqs_disabled()) {
msg = "disabled interrupts";
local_irq_enable();
}
if (msg) {
printk(KERN_WARNING "error in initcall at 0x%p: "
"returned with %s/n", *call, msg);
}
}
/* Make sure there is no pending stuff from the initcall sequence */
flush_scheduled_work();
}
------------------------------------------------------------------------------------------------------
这个__initcall_start是在文件 arch/xxx/kernel/vmlinux.lds.S (其中的xxx 是你的体系结构的名称,例如i386)
这个文件是内核ld的时候使用的.其中定义了各个sectioin,看看就明白了。
在这个文件中有个.initcall.init, 代码如下:
------------------------------------------------------------------------------------------------------
__initcall_start = .;
.initcall.init : {
*(.initcall1.init)
*(.initcall2.init)
*(.initcall3.init)
*(.initcall4.init)
*(.initcall5.init)
*(.initcall6.init)
*(.initcall7.init)
}
------------------------------------------------------------------------------------------------------
这里有7个初始化的优先级,内核会按照这个优先级的顺序依次加载.
这些优先级是在文件include/linux/init.h 中定义的. 你注意一下宏 __define_initcall的实现就明白了.
相关代码如下:
#define __define_initcall(level,fn) /
static initcall_t __initcall_##fn __attribute_used__ /
__attribute__((__section__(".initcall" level ".init"))) = fn
#define core_initcall(fn) __define_initcall("1",fn)
#define postcore_initcall(fn) __define_initcall("2",fn)
#define arch_initcall(fn) __define_initcall("3",fn)
#define subsys_initcall(fn) __define_initcall("4",fn)
#define fs_initcall(fn) __define_initcall("5",fn)
#define device_initcall(fn) __define_initcall("6",fn)
#define late_initcall(fn) __define_initcall("7",fn)
把自己的驱动的函数名用这些宏去定义之后,
就会对应不同的加载时候的优先级。
其中,我们写驱动中所用到的module_init对应的是
#define module_init(x) __initcall(x);
而
#define __initcall(fn) device_initcall(fn)
所以,驱动对应的加载的优先级为6
在上面的不同的优先级中,
数字越小,优先级越高。
同一等级的优先级的驱动,加载顺序是链接过程决定的,由driver/Makefile确定的,改变这个makefile的内容手动设置谁先谁后。
不同等级的驱动加载的顺序是先优先级高,后优先级低。
我们可以看到,我们经常写的设备驱动程序中常用的module_init其实就是对应了优先级6:
#define __initcall(fn) device_initcall(fn)
#define module_init(x) __initcall(x);
同一个等级的情况下注册顺序跟代码链接的顺序有关系,修改driver/Makefile的内容。
加载顺序可以从system.map中看到设备的注册函数的地址。
相关文章推荐
- 修改设备驱动加载顺序
- 在linux设备启动时,修改加载设备驱动的顺序
- 如何控制设备驱动程序的加载顺序
- linux设备和驱动加载的先后顺序
- 如何控制设备驱动程序的加载顺序
- 修改linux kernel驱动加载的顺序
- linux设备和驱动加载的先后顺序
- 编写嵌入式linux驱动时,如何才能自动加载设备并生成节点
- 嵌入式 hi3518c驱动lowpower.sh加载注意事项修改完成针对USB设备的支持
- linux设备和驱动加载的先后顺序
- 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
- linux设备和驱动加载的先后顺序
- linux设备和驱动加载的先后顺序
- linux设备和驱动加载的先后顺序
- 如何控制驱动加载顺序
- Linux 设备和驱动加载的先后顺序
- Linux 设备和驱动加载的先后顺序 2
- 用心写的驱动分析!!!linux设备和驱动加载的先后顺序
- 如何调整Linux内核启动中的驱动初始化顺序-驱动加载优先级
- 修改linux kernel驱动加载的顺序