Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> MTK6575之android驅動學習1(框架梳理)

MTK6575之android驅動學習1(框架梳理)

編輯:關於Android編程

一、內核執行流程     內核初始化設備驅動的過程: 第一個C函數從main.c (kernel\init)開始,暫且不論匯編文件 [html] view plaincopyprint? start_kernel()->rest_init()->do_basic_setup()->do_initcalls()       函數do_initcalls如下: [html]  static void __init do_initcalls(void)   {   initcall_t *fn;      /*循環調用__initcall_start與__initcall_end之間函數*/      for (fn = __early_initcall_end; fn < __initcall_end; fn++)   do_one_initcall(*fn);         /* Make sure there is no pending stuff from the initcall sequence */   flush_scheduled_work();   }             二、而關於module_init(x)是如何被加載的   [html]   1.#define module_init(x) __initcall(x);         2.#define __initcall(fn) device_initcall(fn)         3.#define device_initcall(fn) __define_initcall("6",fn)         4.#define __define_initcall(level,fn) \      static initcall_t __initcall_##fn __attribute_used__   \   __attribute__((__section__(".initcall" level ".init"))) = fn         從而可以得出:   module_init(x) = static initcall_t __initcall_##fn __attribute_used__   \   __attribute__((__section__(".initcall" level ".init"))) = x         首先分析: 1.其中 initcall_t 是個函數指針類型:typedef int (*initcall_t)(void); 2.屬性 __attribute__((__section__())) 則表示把對象放在一個這個由括號中的名稱所指代的section中。 所以這個宏定義的的含義是: 1) 聲明一個名稱為__initcall_##fn的函數指針(其中##表示替換連接,); 2) 將這個函數指針初始化為fn; 3) 編譯的時候需要把這個函數指針變量放置到名稱為 ".initcall" level ".init" 的section中(比如level="1",代表這個section的名稱是 ".initcall 1 .init")。 4)舉例說明:假如我們有這個宏定義module_init(kpd_mod_init);那麼經過預編譯替換之後就發生如下變化 將函數 kpd_mod_init 的首地址放到section的名稱是 ".initcall 6 .init" 的段中去。 注意:為什麼是6?因為我們這裡使用的是device,#define device_initcall(fn) __define_initcall("6",fn) 會被替換成6。具體對應規則如下: [html]  #define core_initcall(fn)         __define_initcall("1",fn)   #define postcore_initcall(fn)     __define_initcall("2",fn)   #define arch_initcall(fn)         __define_initcall("3",fn)   #define subsys_initcall(fn)       __define_initcall("4",fn)   #define fs_initcall(fn)           __define_initcall("5",fn)   #define device_initcall(fn)       __define_initcall("6",fn)   #define late_initcall(fn)         __define_initcall("7",fn)         在連接腳本段.initcall中將依次存放著 [html]   ".initcall 1 .init"   ".initcall 2 .init"   ".initcall 3 .init"   ".initcall 4 .init"   ".initcall 5 .init"   ".initcall 6 .init"   ".initcall 7 .init"           三、現在回到之前提到的     [html]   do_one_initcall(*fn);       注意這也是個回調函數,關於回調函數的進一步說明可以參考有關資料 不難得出,在這裡將會依次執行,上述提到的那7個段中的函數,進行有關的初始化。 假如您希望某個初始化函數在內核初始化階段就被調用,那麼您就應該使用宏__define_initcall(level,fn) 或其7個衍生宏來把這個初始化函數fn的起始地址按照初始化的順序放置到相關的section 中。 內核初始化 時的do_initcalls()將從這個section中按順序找到這些函數來執行。     幾個注意點: 1.module_init這個是只有在該模塊以module方式存在的時候才有意義,當你加載該模塊的時候才會去調用它 ,加載哪個模塊,就調用哪個模塊的module_init。如果那個模塊本身直接編譯進內核了,那它的代碼就直接 放在內核中相應的區域了,系統啟動的時候自動就調用這些函數了。在我使用的MTK平台都是將其編譯進內核 了的。 2.*(.initcall6.init)在這裡.initcall6.init是一個數據段的名稱,這句話的意思是所有聲明要放在這個段 的數據都將按順序存放在這個段裡。每個module_init都將定義一個函數指針,這些函數指針被指定要放在 .initcall6.init這個段裡,它們將按順序排列。這樣在內核啟動的時候,它會根據這些函數指針按順序調用 所有的函數。     四、接下來可以開始分析我們的kpd驅動     1.我們知道加入我們把驅動編譯進內核的話,那麼內核啟動初始化的階段會執行module_init(kpd_mod_init); 也就是kpd_mod_init這個函數Kpd.c (mediatek\platform\mt6575\kernel\drivers\keypad) 2.在這個初始化函數中,會有如下流程 kpd_mod_init() -> platform_driver_register(&kpd_pdrv) -> kpd_pdrv_probe(struct platform_device *pdev) 注意了,上述流程將是內核啟動後自動進行的初始化。當然我們假設driver和device是可以在bus上綁定的。 3.所以接下來我們可以看看這個kpd_pdrv_probe到底是做了些什麼事情。
  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved