SylixOS熱插拔概述

  • 1. 熱插拔系統簡介

  • 1.1 熱插拔系統

          熱插拔設備指支持帶電操作的一類設備,允許用戶不關閉系統、不切斷電源情況下取出或更換設備。熱插拔系統用於管理系統中所有熱插拔設備的插入、拔出狀態,從而能夠讓系統內部自動完成此類設備的創建、刪除工作而無需用戶手動處理。同時,熱插拔系統還會收集熱插拔相關信息,供應用程序使用。SylixOS熱插拔系統結構如圖 1-1所示。

    圖 1-1熱插拔系統結構

          如圖 1-1所示,SylixOS 中有一個名稱爲"t_hotplug"的內核線程,設備的熱插拔狀態通過事件的方式報告給該線程。系統中還有一個名爲"/dev/hotplug"的虛擬設備,它負責收集相關熱插拔消息,應用程序可通過讀取"/dev/hotplug"設備,獲得自己關心的熱插拔消息。

  • 1.2 實現原理

          在 SylixOS 中,可以使用如下兩種方法獲得熱插拔事件:

          1.中斷產生,例如"mini2440"開發板上SD卡熱插拔操作,當SD卡插入或者拔出時會觸發引腳中斷,中斷服務程序中會根據讀取的引腳狀態,產生相應的熱插拔事件,將需要處理的事件加入到熱插拔工作處理隊列,等待內核線程處理。

          2. 輪詢檢測,當有些熱插拔設備不產生中斷(沒有插拔中斷功能的設備),則需要輪詢檢測某些事件標誌。設備驅動程序需要將檢測函數和參數註冊到"hotplug"循環檢測鏈表中,"t_hotplug"內核線程會定時調用檢測函數,輪詢檢測函數會產生相應事件,等待內核線程處理。

          如圖 1-1所示,當設備熱插拔操作結束時,會產生一條熱插拔消息存入緩存區,應用層程序可以通過讀取虛擬設備"/dev/hotplug"(熱插拔設備驅動創建),從緩存區中獲取熱插拔消息。

  • 2 讀取熱插拔消息

           前文提到,熱插拔事件產生後會產生熱插拔消息,存放在"/dev/hotplug"設備的緩存區中,則應用層可以對"/dev/hotplug"設備進行讀取,獲得應用層需要的熱插拔消息。由於"/dev/hotplug"設備是字符設備,所以應用層可以對設備進行open、read、write、ioctl、close等操作,獲得應用層所需的熱插拔消息。

  • 2.1 獲取熱插拔消息實例

          SylixOS 中定義了當前常見的熱插拔設備消息,如 USB、SD卡、PCI等,用戶也可以自定義添加。此外,還有網卡的連接與斷開等與熱插拔行爲相似的消息。

          下面舉例說明如何獲取網卡熱插拔消息(本例程序是在mini2440開發板上測試運行),測試代碼代碼清單2-1所示。 

    代碼清單 2-1 

    #include <stdio.h>
    #include <string.h>
    
    #define      MSG_LEN_MAX                (534)
    
    int main (int  argc, char  *argv[])
    {
        UINT8   pucMsgBuff[MSG_LEN_MAX];
        INT     iFd;
        INT32   iMsgType;
        BOOL    bInsert;
        ssize_t sstReadLen;
    
        CHAR   *pcDevName = NULL;
        UINT8  *pucArg    = NULL;
        UINT8  *pucTemp   = NULL;
    
    
        iFd = open("/dev/hotplug", O_RDONLY);                             /*  打開hotplug虛擬設備         */
        if (iFd < 0) {
            fprintf(stderr, "open /dev/hotplug failed.\n");
            return (-1);
        }
    
        ioctl(iFd, LW_HOTPLUG_FIOSETMSG, LW_HOTPLUG_MSG_NETLINK_CHANGE);  /* ioctl 設置關心網卡熱插拔事件 */
        while (1) {
            sstReadLen = read(iFd, pucMsgBuff, MSG_LEN_MAX);              /* 讀取熱插拔消息               */
            if (sstReadLen < 0) {
                fprintf(stderr, "read hotplug message error.\n");
                close(iFd);
                return (-1);
            }
            if (sstReadLen < 5) {
                continue;
            }
    
            /*
             * 解析熱插拔消息
             */
            pucTemp   = pucMsgBuff;
            iMsgType  = (pucTemp[0] << 24) | (pucTemp[1] << 16) | (pucTemp[2] << 8) | (pucTemp[3]);
            pucTemp  += 4;
            bInsert   = *pucTemp ? TRUE : FALSE;
            pucTemp  += 1;
            pcDevName = (CHAR *) pucTemp;
            pucArg    = pucTemp + strlen(pcDevName) + 1;
    
            printf("get new hotplug message >>\n"                         /*  打印熱插拔消息             */
                    " message type: %d\n"
                    "device status: %s\n"
                    " device name: %s\n"
                    " arg0: 0x%01x%01x%01x%01x\n"
                    " arg1: 0x%01x%01x%01x%01x\n"
                    " arg2: 0x%01x%01x%01x%01x\n"
                    " arg3: 0x%01x%01x%01x%01x\n", iMsgType,
                    bInsert ? "insert" : "remove", pcDevName, pucArg[0], pucArg[1],
                    pucArg[2], pucArg[3], pucArg[4], pucArg[5], pucArg[6],
                    pucArg[7], pucArg[8], pucArg[9], pucArg[10], pucArg[11],
                    pucArg[12], pucArg[13], pucArg[14], pucArg[15]);
        }
    
        close(iFd);
    
        return (0);
    }

        如代碼清單2-1所示,程序實現了應用層讀取網卡熱插拔消息的功能,在開發板上運行該程序,當發生網卡熱插拔操作時,會得到網卡熱插拔消息,實驗現象如圖 2-1所示。

    圖 2-1網卡熱插拔消息

          通過分析代碼清單2-1所示代碼,用戶在讀取設備熱插拔消息時應注意以下幾點:

          1.以只讀方式打開"/dev/hotplug"設備,SylixOS中熱插拔消息在熱插拔設備創建時產生,並且寫入到設備中緩存區中。

          2.代碼清單2-1中程序通過ioctl函數實現單獨監聽網卡熱插拔消息的功能,應用程序可以根據需要設置ioctl函數中的參數來獲取對應的消息。默認情況下是讀取所有類型熱插拔消息。

          3.代碼清單2-1中read函數實現讀取網卡熱插拔消息的功能,讀取消息後對獲得的熱插拔消息進行解析,然後輸出打印。根據程序圖 2-1輸出結果可知,SylixOS中對熱插拔消息格式進行特殊規定,格式分析參照2.2節。

  • 2.2 熱插拔消息格式

          由2.1節中讀取網卡熱插拔消息實例可知,在SylixOS中熱插拔消息有規定的格式。下面對SylixOS熱插拔消息格式進行分析,如圖 2-2所示。

    圖 2-2熱插拔消息格式

          參照圖 2-2可知,消息的前4個字節標識了消息的類型。SylixOS中已經定義了USB鍵盤、USB鼠標、SD存儲卡、SDIO無線網卡等熱插拔類型。在實際的硬件平臺上,設備驅動也可以定義自己的熱插拔消息類型。

          第5個字節爲設備狀態,0表示拔出,1表示插入。

          從第 6 個字節開始,表示設備的名稱,其內容爲一個以'\0'結束的字符串,應用程序應該以此爲結束符得到完整的名稱。該名稱爲一個設備的完整路徑名稱,如"/dev/ttyUSB0"、"/media/sdcard0"等。由於SylixOS中,一個完整路徑名稱的最大長度爲512,加上結束字符'\0',因此,dev name字段的最大長度爲513。

          緊跟着設備名稱('\0'字符結尾)的是 4 個可用於靈活擴展的參數,均爲4字節長度。這4個參數可適應不同設備消息的特殊處理。SylixOS未規定每個參數的具體用法和存儲格式(大端或小端),完全由設備驅動定義。

          綜上論述,一個熱插拔消息的最大長度爲:4 + 1 + 513 + 4 + 4 + 4 + 4 = 534字節。


  • 3 熱插拔消息產生

  • 3.1 網卡熱插拔消息

          前文已經介紹了應用層如何獲取熱插拔消息,本章介紹SylixOS熱插拔消息的產生流程。SylixOS中,熱插拔消息在熱插拔事件產生時產生,由熱插拔設備驅動實現。

          下面以網卡熱插拔爲例,介紹網卡熱插拔消息產生流程,如圖 3-1所示(圖中以網卡連接爲例,網卡斷開流程與此基本一致)。

     

     

    圖 3-1網卡熱插拔消息產生流程

          如圖 3-1所示,在對網口進行必要的初始化後,將循環檢測函數dm9000_watchdog註冊到循環檢測鏈表中,檢測函數會根據網卡狀態產生不同的熱插拔消息,然後將熱插拔消息存入緩存區。

  • 3.2 模擬熱插拔實現

          下面通過信號模擬熱插拔事件,用信號SIGALRM模擬設備插入,用信號SIGUSR1模擬設備拔出。示例代碼清單3-1所示:

    代碼清單3-1 

    #define __SYLIXOS_KERNEL
    #include <SylixOS.h>
    #include <stdio.h>
    #include <string.h>
    #include <signal.h>
    #include <pthread.h>
    #include <unistd.h>
    
    static char      *msg = "Dev";
    
    void send_event (void  *arg)
    {
        int signum = (int)arg;
    
        if (signum == SIGALRM) {
            API_HotplugEventMessage(LW_HOTPLUG_MSG_ALL, 1, msg, 0, 0, 0, 0);
        } else if (signum == SIGUSR1){
            API_HotplugEventMessage(LW_HOTPLUG_MSG_ALL, 0, msg, 0, 0, 0, 0);
        }
    }
    
    void pullout_handler (int  signum)
    {
        API_HotplugEvent((VOIDFUNCPTR)send_event, (void *)signum, 0, 0, 0, 0, 0);
    }
    
    void insert_handler (int  signum)
    {
        API_HotplugEvent((VOIDFUNCPTR)send_event, (void *)signum, 0, 0, 0, 0, 0);
    }
    
    int main (int argc, char *argv[])
    {
        int   i;
    
        if (signal(SIGALRM, insert_handler) == SIG_ERR) {
            fprintf(stderr, "Install signal handler failed.\n");
            return -1;
        }
        if (signal(SIGUSR1, pullout_handler) == SIG_ERR) {
            fprintf(stderr, "Install signal handler failed.\n");
            return -1;
        }
    
        for (i = 0; i < 8; ++i) {
            alarm(2);
            pause();
            kill(getpid(), SIGUSR1);
        }
    
        return  0;
    }

           本例利用信號模擬熱插拔事件,運行2.1節中程序(註釋掉ioctl函數,獲取所有類型的熱插拔消息),再執行代碼清單3-1所示程序,會得到圖 3-2所示結果。

    圖 3-2模擬熱插拔模擬結果

  • 4 小結

          本文檔介紹了SylixOS下熱插拔系統實現原理,以網卡熱插拔爲例,分析熱插拔消息產生流程。最後通過信號模擬熱插拔事件,打印出模擬的熱插拔消息。


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章