概述
这几天再调试两家TP,因为项目需要两家TP兼容,所以考虑到了两个TP驱动初始化的先后顺序的问题。
TP的驱动在I2C初始化之前就运行起来了,而这时I2C提供的API还处于不可用状态。在网上查了一些资料总结一下。
所有的__init函数在区段.initcall.init中保存了一份函数指针,在初始化时内核会通过这些函数指针调用这些__init函数指针,并在整个初始化完成后,释放整个init区段(包括.init.text,.initcall.init等)。
注意,这些函数在内核初始化过程中的调用顺序只和这里的函数指针的顺序有关,和这些函数本身在.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) |
下面是自己的一些总结:
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/input/touchscreen/Makefile部分内容
#
# Makefile for the touchscreen drivers.
#
# Each configuration option enables a list of files.
obj-$(CONFIG_TOUCHSCREEN_MSM_LEGACY) += msm_touch.o
obj-$(CONFIG_TOUCHSCREEN_CY8C_TS) += cy8c_ts.o
obj-$(CONFIG_TOUCHSCREEN_CYTTSP_I2C) += cyttsp-i2c.o
obj-$(CONFIG_TOUCHSCREEN_FT5206) += ft5x06_ts.o
obj-$(CONFIG_TOUCHSCREEN_MSG2133) += tp_msg2133.o
obj-$(CONFIG_TOUCHSCREEN_FT5306_GPIO_I2C) += ft5x06_ts_30.o
....
当在menuconfig中配置了tp_msg2133,ft5x06_ts_30后, 链接先后顺序依次是:
tp_msg2133.o
ft5x06_ts_30.o
这几个目标文件中一共有两个module_init,分别是tp_msg2133.o中的module_init(msg21xx_init);
和ft5x06_ts_30.o中的module_init(ft5x0x_ts_init);
所以这两个初始化函数的先后执行顺序依次是:
msg21xx_init
ft5x0x_ts_init
对应的probe函数也是一样。如果需要更改他们的执行顺序,只要将Makefile中链接的顺序换一下就可以了。
最后
以上就是冷酷店员为你收集整理的Linux内核驱动程序初始化顺序的调整的全部内容,希望文章能够帮你解决Linux内核驱动程序初始化顺序的调整所遇到的程序开发问题。
如果觉得靠谱客网站的内容还不错,欢迎将靠谱客网站推荐给程序员好友。
发表评论 取消回复