天天看點

DM9000驅動詳細分析(一)1    子產品的初始化和退出函數1.1 built-in 1.2module

1    子產品的初始化和退出函數

初始化與退出函數: module_init(dm9000_init); module_exit(dm9000_cleanup); 其實是宏定義,在子產品執行時告訴核心初始化函數和去初始化的位置讓其執行初始化和退出操作。 目前linux支援兩種方式運作裝置驅動,一種是built-in kernel,另一種module。

1.1 built-in 

module_init(x) 相關宏定義: #define module_init(x)     __initcall(x); #define __initcall(fn) device_initcall(fn) #define device_initcall(fn)                 __define_initcall("6",fn,6) #define __define_initcall(level,fn,id) \          static initcall_t __initcall_##fn##id __used \          __attribute__((__section__(".initcall" level ".init"))) = fn typedef int (*initcall_t)(void); 把上面的宏變換展開: Static initcall_t __initcall_dm9000_init_6 __used __attribute__((__section__(“.initcall” 6 “.init”)))=dm9000_init  其實是定義了一個Static initcall_t類型的函數指針__initcall_dm9000_init_6 這裡我們需要了解一下gcc的__attribute__機制,是在編譯的過程中告訴編譯器該函數一些屬性,__attribute__((__section__(“.initcall” 6 “.init”)))意思是把函數放入“.initcall” 6 “.init” 段中,然後把dm9000_init指派給它。 __used也是一個__attribute__相關宏: #if __GNUC_MINOR__ >= 3 # define __used        __attribute__((__used__)) #else # define __used        __attribute__((__unused__)) #endif http://gcc.gnu.org/onlinedocs/gcc-4.3.2//gcc/Function-Attributes.html 中關于used與unused有解釋,__attribute__修飾的函數或變量可能使用/不使用,可以避免編譯器産生告警。 結合vmlinux.lds中的 .initcall.init : AT(ADDR(.initcall.init) - (0xc0000000 -0x00000000)) {    __initcall_start = .;    *(.initcallearly.init) __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)    __initcall_end = .;    } 系統啟動時 start_kernel()->rest_init()->kernel_init()->do_basic_setup()->do_initcalls() do_initcalls: static void __init do_initcalls(void) {          initcall_t *call;          for (call = __initcall_start; call < __initcall_end; call++)                    do_one_initcall(*call);          /* Make sure there is no pending stuff from the initcall sequence */          flush_scheduled_work(); }  

1.2module

按如下宏展開: /* Each module must use one module_init(). */ #define module_init(initfn)                                            \          static inline initcall_t __inittest(void)               \          { return initfn; }                                              \          int init_module(void) __attribute__((alias(#initfn)));   /* This is only required if you want to be unloadable. */ #define module_exit(exitfn)                                          \          static inline exitcall_t __exittest(void)             \          { return exitfn; }                                             \          void cleanup_module(void) __attribute__((alias(#exitfn)));   在用insmod加載子產品時會調用子產品的init函數.