1. 程式人生 > 其它 >裝置驅動-模組-module_init巨集解析 裝置驅動-i2c驅動-module_i2c_driver的使用

裝置驅動-模組-module_init巨集解析 裝置驅動-i2c驅動-module_i2c_driver的使用

module_init 

這個巨集定義在 

include/linux/module.h

module 的含義,即 模組; 有兩類:  builtin  的模組 (存在在 Image 中) 或者  獨立的模組(存在在  xx.ko 中)

 

根據當前在編譯 builtin 還是 編譯 獨立模組, module 巨集有不同的 定義

  80#ifndef MODULE

  89#define module_init(x)  __initcall(x);

 103#else /* MODULE */

 131#define module_init(initfn)                                     \
 132
static inline initcall_t __maybe_unused __inittest(void) \ 133 { return initfn; } \ 134 int init_module(void) __copy(initfn) __attribute__((alias(#initfn))); 142#endif

 

MODULE 巨集從哪兒控制? 

如果一個 xx.c 檔案在 Kconfig 中配置的是 obj-m += xx.c ,那麼編譯這個 xx.c 檔案時,就會 定義MODULE 巨集。

這個機制是 頂層的  Makefile 和 script/Makefile.lib 配合實現的

Makefile

 503KBUILD_AFLAGS_MODULE  := -DMODULE
 504KBUILD_CFLAGS_MODULE  := -DMODULE

scripts/Makefile.lib

 188part-of-module = $(if $(filter $(basename $@).o, $(real-obj-m)),y)
 189quiet_modtag = $(if $(part-of-module),[M],   )
 190
 191modkern_cflags =                                          \
 
192 $(if $(part-of-module), \ 193 $(KBUILD_CFLAGS_MODULE) $(CFLAGS_MODULE), \ 194 $(KBUILD_CFLAGS_KERNEL) $(CFLAGS_KERNEL) $(modfile_flags))

$@ 表示正在編譯的目標,如果是 module 的一部分,則使用 KBUILD_CFLAGS_MODULE 作為 cflags ,即 -DMODULE 被引入 gcc 命令列 ;

 

作為  builtin 模組時的module_init 

就是  __initcall(x); 

include/linux/init.h

 195#define ___define_initcall(fn, id, __sec) \
 196        static initcall_t __initcall_##fn##id __used \
 197                __attribute__((__section__(#__sec ".init"))) = fn;
 

 200#define __define_initcall(fn, id) ___define_initcall(fn, id, .initcall##id)
 
 207#define early_initcall(fn)              __define_initcall(fn, early)

 216#define pure_initcall(fn)               __define_initcall(fn, 0)
 218#define core_initcall(fn)               __define_initcall(fn, 1)
 219#define core_initcall_sync(fn)          __define_initcall(fn, 1s)
 220#define postcore_initcall(fn)           __define_initcall(fn, 2)
 221#define postcore_initcall_sync(fn)      __define_initcall(fn, 2s)
 222#define arch_initcall(fn)               __define_initcall(fn, 3)
 223#define arch_initcall_sync(fn)          __define_initcall(fn, 3s)
 224#define subsys_initcall(fn)             __define_initcall(fn, 4)
 225#define subsys_initcall_sync(fn)        __define_initcall(fn, 4s)
 226#define fs_initcall(fn)                 __define_initcall(fn, 5)
 227#define fs_initcall_sync(fn)            __define_initcall(fn, 5s)
 228#define rootfs_initcall(fn)             __define_initcall(fn, rootfs)
 229#define device_initcall(fn)             __define_initcall(fn, 6)
 230#define device_initcall_sync(fn)        __define_initcall(fn, 6s)
 231#define late_initcall(fn)               __define_initcall(fn, 7)
 232#define late_initcall_sync(fn)          __define_initcall(fn, 7s)

 234#define __initcall(fn) device_initcall(fn)

紅色 標識 出 __initcall 用到的部分 ;

編譯:

234 行 -  __initcall 其實就是  device_initcall 

229 - device_initcall  是 __define_initcall(fn, 6 )  // 6 標識 id ;

200  -  __define_initcall(fn, id) 是  __define_initcall(fn, id, .initcall##id )  // 即 __define_initcall(fn, 6 , initcall6 ) ; 

195 - __define_initcall(fn , id, sec)  做出定義 

      static    initcall_t        __initcall_fn6    __used  __attribute__((__section__(  initcall6.init ))    =   fn

 

只需要將上面的 fn 替換為 module_init(xx) 中填入的 xx 即可。

示例: module_init (i2c_init) ; 

static  int    __initcall_i2c_init6     __used          __attribute__((__section__(  initcall6.init ))    =   i2c_init ; 

在 initcall6.init  這個 section 裡面定義了一個函式指標變數  __initcall_i2c_init6  , 指標賦值為  i2c_init 函式地址; 

呼叫

do_basic_setup -> do_initcalls  裡面會 遍歷  __initcall6.init 這個section 裡面的函式指標,一個個呼叫 對應的函式; 即會呼叫到  i2c_init 函式 ; 

 

作為 外部 xx.ko 模組時的module_init 

編譯

module_init(xx)  即是 希望 在 insmod xx.ko 時 呼叫 xx 函式; 

 131#define module_init(initfn)                                     \
 132        static inline initcall_t __maybe_unused __inittest(void)                \
 133        { return initfn; }                                      \
 134        int init_module(void) __copy(initfn) __attribute__((alias(#initfn)));

 

132  定義 一個 static  inline 的函式; 返回值 為 initcall_t  即 int ;  名稱為   __inittest ; 

   static  inline  int  __inittest(){

            return initfn ; 

   }

  這個的關鍵 在於  檢查 返回值;   如果  initfn 返回值 不是 int , 就會列印錯誤資訊; 

GPIO/fsl-gpio.c:46: warning: return from incompatible pointer type

 

133 行  - 為  initfn 定義一個別名函式    init_module  ; 關於gcc alias 定義別名函式, 參考這兒

https://www.cnblogs.com/zhangzhiwei122/p/16125210.html

 

這樣,每個 xx.ko 裡面肯定有一個 函式   init_module , 它是程式碼中的   module_init(xx) 定義的函式的別名 ;

呼叫流程

insmod 呼叫 init_module 函式

/include/linux/module.h 有 module 結構體定義; 裡面有 init 指標,指向 模組的 init 函式; 

 361struct module {
 362        enum module_state state;

 
 423        /* Startup function. */
 424        int (*init)(void);

在 kernel/module.c 中  do_init_module 函式 會 觸發  mod->init 函式的呼叫。

3604static noinline int do_init_module(struct module *mod)
3605{

3622        do_mod_ctors(mod);
3623        /* Start the module */
3624        if (mod->init != NULL)
3625                ret = do_one_initcall(mod->init);

 

從 insertmod 到  do_init_module 的過程,參考:

 

模組載入流程上

https://blog.csdn.net/lidan113lidan/article/details/119813256

模組載入流程下

https://blog.csdn.net/lidan113lidan/article/details/119813552

 

do_one_initcall 就是 init/main.c 中定義的,之前在 do_initcalls 裡面也使用的,呼叫 1 個 init 函式; 

1207int __init_or_module do_one_initcall(initcall_t fn)
1208{
1209        int count = preempt_count();
1210        char msgbuf[64];
1211        int ret;
1212
1213        if (initcall_blacklisted(fn))
1214                return -EPERM;
1215
1216        do_trace_initcall_start(fn);
1217        ret = fn();
1218        do_trace_initcall_finish(fn, ret);
1219
1220        msgbuf[0] = 0;
1221
1222        if (preempt_count() != count) {
1223                sprintf(msgbuf, "preemption imbalance ");
1224                preempt_count_set(count);
1225        }
1226        if (irqs_disabled()) {
1227                strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf));
1228                local_irq_enable();
1229        }
1230        WARN(msgbuf[0], "initcall %pS returned with %s\n", fn, msgbuf);
1231
1232        add_latent_entropy();
1233        return ret;
1234}

 

下一篇:

裝置驅動-i2c驅動-module_i2c_driver的使用

https://www.cnblogs.com/zhangzhiwei122/p/16125079.html