I2C子系统之内核中I2C子系统的结构

说明:1.分析的内核版本为2.6.37.1

           2.开发板为TQ2440,板载ARM9(S3C2440)

           3.I2C设备为AT24C02

           4.分析顺序就是内核I2C子系统的注册顺序(即本系列文章发表的先后顺序)。

在正式进入代码分析前应摸清各初始化函数的执行先后顺序,清楚这个顺序后对i2c的整个框架也有就有数了。

1.初始化函数的执行顺序

1.1 函数执行顺序是如何确定的

内核编译链接完成后初始化函数的执行先后顺序就确定了。这是通过链接器在链接时调用链接脚本/arch/arm/kernel/vmlinux.lds来完成的。脚本规定了不同代码段,例如_init、text、data等不同属性的代码段存放的位置。假如同属_init函数A()和函数B()就全部放在脚本中定义的_init地址上,但是具体是A()函数在前还是B()函数在前呢?这是由目录下的Makefile文件来决定了。Makefile文件中函数存放的先后顺序来决定了,假如obj+y   = A()在obj+y    = B()之前,则最后连接的时候A函数就在B()函数之前执行了。所以决定函数执行的先后顺序是由1.vmlinux.lds链接脚本2.驱动目录下Makefile文件共同确定的

首先分析链接脚本中关于顺序的控制。

vmlinux.lds:

#ifndef __ARMEB__    jiffies = jiffies_64;   #else    jiffies = jiffies_64 + 4;   #endif       SECTIONS   {                   。。。 。。。                   INIT_CALL                   CON_INITCALL           SECURITY_INITCALL                   。。。 。。。   }  

其中INIT_CALLS为一个宏,定义如下:

#define INITCALLS                                                       \        *(.initcallearly.init)                      \       VMLINUX_SYMBOL(__early_initcall_end) = .;           \       *(.initcall0.init)                      \       *(.initcall0s.init)                     \       *(.initcall1.init)                      \       *(.initcall1s.init)                     \       *(.initcall2.init)                      \       *(.initcall2s.init)                     \       *(.initcall3.init)                      \       *(.initcall3s.init)                     \       *(.initcall4.init)                      \       *(.initcall4s.init)                     \       *(.initcall5.init)                      \       *(.initcall5s.init)                     \       *(.initcallrootfs.init)                     \       *(.initcall6.init)                      \       *(.initcall6s.init)                     \       *(.initcall7.init)                      \       *(.initcall7s.init)      #define INIT_CALLS                          \            VMLINUX_SYMBOL(__initcall_start) = .;           \           INITCALLS                       \           VMLINUX_SYMBOL(__initcall_end) = .;  

可以看见存放链接的顺序依次为:.initcall0.init、initcall0s.init、initcall1.init... ...

这只是连接脚本的中的语法,函数中具体是需要宏来给函数做上标记的。

具体在/include/linux/init.h中,相关代码如下:

内容版权声明:除非注明,否则皆为本站原创文章。

转载注明出处:http://www.heiqu.com/dd312a504482348b978235244198adb0.html