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)

 

创建ARM Liunx环境的步骤 

  1、 确定几个系统变量cd ……/……/ export TARGET=arm-linux export PREFIX=……/arm/tool-chain export TARGET_PREFIX=$PREFIX/$TARGET export KERNEL_SOURCE_LOCATION=……/arm/kernel/linux-2.4.21 export PATH=$PREFIX/bin:$PATH

  几个系统变量经常要用到,TARGET定义了目标机,PREFIX是工具链的安装目录,KERNEL_SOURCE_LOCATION是内核文件位置。

  2、 创建binutils运行如下命令来创建binutils cd ./build-dir/build-binutils configure ……/……/src-dir/binutils-2.14/configure –target=$TARGET –prefix=$PREFIX make make install这时$PREFIX/bin下创建了一些文件,包括arm-linux-ld,arm-linux-as等。

  3、 编译内核

  cd ……/……/kernel/linux-2.4.21

  改Makefile文件使ARCH = arm CROSS_COMPILE=arm-linux-

  make menuconfig在System Types中选择正确的硬件类型

  make dep

  之后执行如下操作mkdir $TARGET_PREFIX/include cp dR $KERNEL_SOURCE_LOCATION/include/arm-asm RGET_PREFIX/include/asm cp dR $KERNEL_SOURCE_LOCATION/include/linux RGET_PREFIX/include/linux

  4、 创建boot-trap gcc,这个GCC没有glibc库的支持,所以只能用于编译内核,bootloader等,后面创建C库也要用到这个编译器,所以创建它主要是为创建C库做准备,如果只想编译内核和bootloader那么,就可以到此结束。

  cd ……/……/build-dir/build-gcc……/……/src-dir/gcc-2.95.3/configure –target=$TARGET –prefix=$PREFIX——with-headers=$ERNEL_SOURCE_LOCATION/include –enable-language=c——disable-threads然后修改src-dir/gcc-2.95.3/gcc/config/arm/t-linux文件,在TARGET_LIBGCC2_CFLAGS中添加如下两个定义-Dinhibit-libc –D__gthr_posix_h make make install这时$PREFIX/bin下创建了一些文件,主要创建了arm-linux-gcc. 5、 创建gblic cd ……/build-glibc export CC=arm-linux-gcc……/……/src-dir/glibc-2.2.4/configure –host=$TARGET –prefix=$TARGET_PREFIX——enable-add-ons make make install

  6、 创建功能健全的GCC,并创建G++在成功创建了libc之后,我们就可以创建功能丰富的GCC编译器了,并且可以创建支持编译C++程序的G++. cd ……/……/src-dir tar –xvzf ……/setup-dir/ gcc-g++2.95.3.tar.gz cd ……/build-dir/build-gcc export CC=gcc……/……/src-dir/gcc-2.95.3/configure –target=$TARGET –prefix=$PREFIX–enable-language=c,c++

  然后修改src-dir/gcc-2.95.3/gcc/config/arm/t-linux文件,在TARGET_LIBGCC2_CFLAGS中去除如下两个定义-Dinhibit-libc –D__gthr_posix_h

  make make install