Linux内核驱动程序初始化顺序的调整----修改版

转自:Linux内核驱动程序初始化顺序的调整----修改版[百叶琉璃]


今天在做一个驱动的时候要用到另一个驱动(I2C)提供的API,在内核初始化时碰到了一个依赖问题。

我的驱动在I2C初始化之前就运行起来了,而这时I2C提供的API还处于不可用状态。查了很多资料,网上有人说所有使用module_init这个宏的驱动程序的起动顺序都是不确定的(我没有查到权威的资料)。

所有的__init函数在区段.initcall.init中还保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。

注 意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和1)中所述的这些函数本身在.init.text区段中的顺序无关。在2.4 内核中,这些函数指针的顺序也是和链接的顺序有关的,是不确定的。在2.6内核中,initcall.init区段又分成7个子区段,分别是

.initcall1.init 
.initcall2.init 
.initcall3.init 
.initcall4.init 
.initcall5.init 
.initcall6.init 
.initcall7.init

当需要把函数fn放到.initcall1.init区段时,只要声明

core_initcall(fn);

即可。

其他的各个区段的定义方法分别是:

core_initcall(fn) --->.initcall1.init 
postcore_initcall(fn) --->.initcall2.init 
arch_initcall(fn) --->.initcall3.init 
subsys_initcall(fn) --->.initcall4.init 
fs_initcall(fn) --->.initcall5.init 
device_initcall(fn) --->.initcall6.init 
late_initcall(fn) --->.initcall7.init

而 与2.4兼容的initcall(fn)则等价于device_initcall(fn)。各个子区段之间的顺序是确定的,即先调用. initcall1.init中的函数指针,再调用.initcall2.init中的函数指针,等等。而在每个子区段中的函数指针的顺序是和链接顺序相 关的,是不确定的。

在内核中,不同的init函数被放在不同的子区段中,因此也就决定了它们的调用顺序。这样也就解决了一些init函数之间必须保证一定的调用顺序的问题。按照include/linux/init.h文件所写的,我在驱动里偿试了这样两种方式:

__define_initcall("7", fn);
late_initcall(fn);

都可以把我的驱动调整到最后调用。实际上上面两个是一回事:

#define late_initcall(fn) __define_initcall("7", fn)



<下面部分是cxmsee自己编写的>
1.
参见 内核链接脚本:arch/arm/kernel/vmlinux.lds
在程序代码段__init_start到__init_end内会依次执行 .initcall1.init ~ .initcall7.init

至于 .con_initcall.init 和 .security_initcall.init
分别对应的宏是在init.h中的console_initcall 和 security_initcall(fn)
在C入口函数start_kernel中会调用console_init, 该函数会依次调用程序代码段__con_initcall_start到__con_initcall_end内的所有(也就是用console_initcall声明)的函数

2.
如果模块驱动程序直接编译进内核,模块初始化函数都用module_init(fn)声明的话,则实际上
等价于device_initcall(fn), 如果一个子系统下有两个 module_init(fn),则这两个初始化函数的执行顺序只跟链接顺序有关。
如: 下面是drivers/serial/Makefile部分内容
#
# $Id: Makefile,v 1.8 2002/07/21 21:32:30 rmk Exp $
#

serial-8250-y :=
serial-8250-$(CONFIG_SERIAL_8250_ACPI) += 8250_acpi.o
serial-8250-$(CONFIG_PNP) += 8250_pnp.o
serial-8250-$(CONFIG_GSC) += 8250_gsc.o
serial-8250-$(CONFIG_PCI) += 8250_pci.o
serial-8250-$(CONFIG_HP300) += 8250_hp300.o

obj-$(CONFIG_SERIAL_CORE) += serial_core.o
obj-$(CONFIG_SERIAL_21285) += 21285.o
obj-$(CONFIG_SERIAL_VIRGO) += serial_virgo.o
obj-$(CONFIG_SERIAL_8250) += 8250.o $(serial-8250-y)
obj-$(CONFIG_SERIAL_8250_CS) += serial_cs.o
obj-$(CONFIG_SERIAL_8250_ACORN) += 8250_acorn.o
obj-$(CONFIG_SERIAL_8250_ORION) += 8250_orion.o
obj-$(CONFIG_SERIAL_8250_CONSOLE) += 8250_early.o
obj-$(CONFIG_SERIAL_AMBA_PL010) += amba-pl010.o
obj-$(CONFIG_SERIAL_AMBA_PL011) += amba-pl011.o
obj-$(CONFIG_SERIAL_CLPS711X) += clps711x.o
... ...
... ...


当在menuconfig中配置了8250, 8250_console以及8250
_orion 后, 链接先后顺序依次是:
    serial_core.o
    8250.o
    8250_orion.o
    8250_early.o
这几个目标文件中一共有两个module_init,分别是8250.o中的module_init(serial8250_init);
和8250_orion.o中的module_init(serial_orion_init);

所以这两个初始化函数的
先后 执行顺序依次是:
    serial8250_init
    serial_orion_init

你可能感兴趣的:(linux驱动,linux)