2015年9月2日 星期三

在一般 AP 中模擬 kernel 的 module_init() 方式註冊功能.

    最近要寫一堆測試程式, 並且將來可能會增加 , 也會隨著某些機種不同而, 有些測試項目可能會移除,增加.

    我們的機器雖然是 linux , 但並非相同 (亂改了很多東西)  , 最頭痛的就是 key pad input 介面.這個介面不是使用 linux 的 input 方式, 反而有點像一般 MCU 的 getkey() 方式.
所以就比較難寫 AP. 要不時的檢查有沒有 key input , 導致正個 Test AP 結構混亂.

所以我想了一個方式, 這個方式有點像是 event-driven 方式, 每個測試程式當作一個 Frame (因為有自己的選單, 操作介面 , 所以我暫時稱為 Frame). 每個 Frame 有固定下列幾個 even-driven 介面: 


       void *frame_data;

        int (*init_func)(void *arg);
        int (*event_func)(void *arg,int key);
        int (*timer_tick)(void *arg);
        int (*exit_func)(void *arg);


簡單說明一下:
     init_func => initial frame ,當這個 frame 被致能 (active) 的時候會先呼叫這個 initial .

     event_func => 當有 key input 的時候會將 key value 透過這個 function 傳到 active 的 frame.

      timer_tick  => 每 一小段時間 (不是很準) 就會驅動這個 tick function , 可以在這個 function 中作一些 polling  , timeout wait 等動作.

     exit_func  => 當這個 Frame 被 inactive 的時候會呼叫這個 function , 可以釋放 一些 resource .

    主題來了, 每個測試 Frame 可能會增加 , 抽換 . 我想要做到每個測試 frame 都獨立, 並可以在 compile 的時候選擇要不要加入.想了想好像 kernel 的 driver init  動作 (module_init() function ). 如果我可以在 AP 中模擬 kernel 的 module_init() 方式 , 或許可以解決我的問題.

    網路上google 了很多有關 kernel module_init() 的方式和 Trace 了一下 kernel source code 後, 發現也蠻簡單. 其實就是利用 compiler 的時候將 init 的 function point 放到一個 特定的 section 中, booting 過程由這 section 中取出 function point 然後執行它即可.


    首先定義 frame_init() 的 macro function , 如下:

  typedef void (*initlist_func)(void);
#define __initlist      __attribute__((section("initlist")))
#define frame_init(fn) \
        initlist_func __initlist_##fn##__               __initlist = fn


extern initlist_func __start_initlist;
extern initlist_func __stop_initlist;


    要使用 __attribute__ + section, section 的名稱最好前面不要有 .xxxx , 通常 .xxxx 為預定的
section , 如 .code .text .data 等.
另外宣告兩個 start & stop point , 一般 GCC 會自動產生這兩個 point, 只要宣告拿來用即可.

    使用上就是將init function 用 farme_init() 來宣告, 內容將 event-driven 的 function call 放入即可  , 如下:


 void main_frame_register(void)
{
struct frame_function info;

        DEBUG_MSG("");

//      info.frame_index = -1;                  // Not need specifity.
        info.frame_layer = 0;
        info.frame_name = "MAIN_FRAME",
        info.frame_item = NULL,                 // main menu is first frame , not need title.

//---- functions of main frame.
        info.frame_data = (void *)&main_menu_data,
        info.init_func  = main_init,
        info.event_func = main_event,
        info.timer_tick = NULL,
        info.exit_func  = main_exit,


        Register_Frame(&info);
}

frame_init(main_frame_register);



     在程式啟動的時候進行這些 frame_init() code 的執行, code 如下:

         for (init_fc_p = &__start_initlist ;
                         init_fc_p != &__stop_initlist ; init_fc_p ++)
                        (*init_fc_p)();


    這樣就可以模擬 kernel 的 module_init() 的功能了,接下來就是處理如何 切換 frame , 和 派送 event-driven 對應的 function call 了.







沒有留言:

張貼留言