WINCE5.0的中斷深入瞭解

WINCE5.0 的中斷深入瞭解
1 .總體瞭解流程
首先描述 wince5.0 2440 BSP )的中斷流程:
流程 1 .創建事件 a à 創建線程 IST à InterruptInitialize 系統 中斷號綁定線程 IST à 線程 IST 進入等待事件 a 狀態(掛起狀態)。
流程 2 .外部引發中斷 à OEMInterruptHandler< 屏蔽中斷 à 把物理中斷轉換成系統中斷 , 其他 à 重新使能中斷。 (ISR 過程 )> à 操作系統根據系統中斷號觸發事件 a
流程 3 .掛起的 IST 線程等待到事件 a 進入就緒狀態,得到執行時間後開始執行中斷服務代碼 , 最後調用 InterruptDone 重新使能當前的中斷。

你需要爲你的設備驅動寫好中斷處理請求(ISR)和中斷服務線程(IST),並牢記這些事件的順序:
1).當一箇中斷髮生,處理器跳轉到核心的中斷處理程序(exception handler );
2).這個中斷處理程序禁止所有同級或低優先級的其他中斷,然後爲當前的IRQ調用對應的ISR;
3).ISR中會按照中斷標識的形式,返回一個邏輯中斷號給中斷處理程序,並會置位板級設備中斷;
4).中斷處理程序重新使能所有的中斷,而目前的中斷已經在上一步中置位了,然後就觸發對應的IST事件;
5).IST就緒,服務於中斷設備,然後完成對中斷的處理;
6).IST調用InterruptDone函數,該函數將順序調用OAL層的OEMInterruptDone函數,它將重新使能當前的中斷。
1.1 物理中斷和邏輯中斷的對應關係 如何建立
這個函數用將物理中斷號來獲取邏輯中斷號:
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &g_PwrButtonIrq, sizeof(UINT32), &g_PwrButtonSysIntr, sizeof(UINT32), NULL))
其中:UINT32 g_PwrButtonIrq = IRQ_EINT0;

從help裏面查出,KernelIoControl函數最終是調用OEMIoControl函數。
在D:/WINCE500/PLATFORM/COMMON/SRC/COMMON/IOCTL裏找到它的定義了,關鍵代碼:
// Execute the handler
    rc = g_oalIoCtlTable.pfnHandler(
        code, pInBuffer, inSize, pOutBuffer, outSize, pOutSize
    );
SMDK2440/Src/Kernel/Oal/ioctl.c 中可以找到:
const OAL_IOCTL_HANDLER g_oalIoCtlTable[] = {
#include "ioctl_tab.h"
};

在SMDK2440/Src/Inc/ioctl_tab.h文件中,找到這個表的定義。這個命令對應的函數是OALIoCtlHalRequestSysIntr。
PLATFORM/COMMON/SRC/COMMON/IOCTL/ioctl.c找到這個函數定義:
// Find if it is new or old call type
    if (inpSize > sizeof(UINT32) && pInpData[0] == -1) {
        // Second UINT32 contains flags, third and subsequents IRQs
        sysIntr = OALIntrRequestSysIntr(inpSize/sizeof(UINT32) - 2, &pInpData[2], pInpData[1]); }
else {        
        // This is legacy call, first UINT32 contains IRQ
        sysIntr = OALIntrRequestSysIntr(1, pInpData, 0);
    }

在WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c找到OALIntrRequestSysIntr定義:
irq = pIrqs[0];
sysIntr = g_oalIrq2SysIntr[irq];

在同一個文件中定義:static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
對這個表格賦值僅有兩個地方:VOID OALIntrStaticTranslate(UINT32 sysIntr, UINT32 irq)
{
    OALMSG(OAL_FUNC&&OAL_INTR, (
        L"+OALIntrStaticTranslate(%d, %d)/r/n", sysIntr, irq
    ));
    if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) {
        g_oalSysIntr2Irq[sysIntr] = irq;
        g_oalIrq2SysIntr[irq] = sysIntr;
    }        
    OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrStaticTranslate/r/n"));
}

OALIntrStaticTranslate 和OALIntrRequestSysIntr本身兩個函數負責建立對應表。後者如果在現有的中斷表中找不到已經建立的對應關係,就會分配一個未定義的 Sysintr邏輯中斷號給這個物理中斷號。因此邏輯中斷和物理中斷的對應,可以說是隨機的,只要保證兩者是一一對應就好了,不必要硬性建立一箇中斷號表 格(像WINCE4.2那樣)。代碼中只找到OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);是靜態對應。當中斷處理程序獲得了邏輯中斷號,那麼就會觸發該中斷號關聯着的事件。
1.2 核心部分的中斷處理程序如何獲得物理中斷號
這個問題的目的是:如何添加一個原來系統中沒有的物理中斷。Physical interrupts (IRQs) are hardware lines over which devices can send interrupt signals to the microprocessor. Logical interrupts (SYSINTRs) are a mapping of the IRQ, which the OAL specifies.一般情況下將ISR與中斷處理程序相關聯的註冊在系統啓動的時候進行。在啓動過程中,在OAL層kernel調用OEMInit函 數。然後,OEMInit調用HookInterrupt 函數來通知中斷處理程序,哪些ISR對應到某個物理中斷。WINCE500/PUBLIC/COMMON/OAK/INC/nkintr.h,定義了某些 邏輯中斷號,聲明瞭hookInterrupt等函數。除此之外,再沒有hookInterrupt的定義。看看WINCE500/PLATFORM /SMDK2440A/src/kernel/oal/init.c裏面的OEMinit函數做了些什麼:
// Initialize interrupts
    if (!OALIntrInit()) {
        OALMSG(OAL_ERROR, (
            L"ERROR: OEMInit: failed to initialize interrupts/r/n"
        ));
    }

OALIntrInit函數在WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/intr.c文件中定義:調用OALIntrMapInit()函數初始化寄存器;最後調用:
#ifdef OAL_BSP_CALLBACKS
    // Give BSP change to initialize subordinate controller
    rc = BSPIntrInit();
#else
    rc = TRUE;
#endif

OALIntrMapInit()函數裏面對兩個中斷表做了初始化:
for (i = 0; i < SYSINTR_MAXIMUM; i++) {
        g_oalSysIntr2Irq = OAL_INTR_IRQ_UNDEFINED;
    }
    for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) {
        g_oalIrq2SysIntr = SYSINTR_UNDEFINED;
    }

WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/sources:
TARGETNAME=oal_intr_s3c2440a
TARGETTYPE=LIBRARY
SYNCHRONIZE_DRAIN=1
NOMIPS16CODE=1
CDEFINES=$(CDEFINES) -DCEDDK_USEDDKMACRO -D OAL_BSP_CALLBACKS
----------------------------------------------------------------------------------
CDEFINES=-DSomeDef : This sets one or more preprocessor definitions. You must include the -D switch on each define you add. You can add new defines by using this syntax: "CDEFINES=$(CDEFINES) -DAnotherDef", or you can ignore existing settings with this syntax: "CDEFINES=-DOnlyDef".
----------------------------------------------------------------------------------

因此BSPIntrInit會被執行。
在WINCE500/PLATFORM/SMDK2440A/Src/Kernel/Oal/intr.c有這個函數的定義:
// Set GPG1 as EINT9
// Add static mapping for Built-In OHCI
OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);

到這裏,無法瞭解如何添加一個物理中斷。在CPU接收到中斷後,對中斷的處理是在 OEMInterruptHandler()中,該函數的首先屏蔽該中斷,最後得到實際中斷IRQ所對應的sysintr的 值”OEMInterruptHandler函數在WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG /S3C2440A/Intr/intr.c文件中,感覺到它實際上就是上面中斷序列中談到的“中斷處理程序”和ISR。就是說,中斷髮生之後,CPU並 不知道到底是哪個中斷髮生了,實際上WINCE中也沒有建立中斷矢量表,而是直接跳轉到OEMInterruptHandler函數,然後在其中查看 g_pIntrRegs->INTOFFSET寄存器,來查看到底發生了什麼中斷。
在s3c2440a_intr.h文件裏面有中斷號宏定義:
#define IRQ_EINT0           0           // Arbiter 0
#define IRQ_EINT1           1
#define IRQ_EINT2           2
#define IRQ_EINT3           3
......

INTOFFSET寄存器的值與這個宏定義是完全一一對應。這樣,也就搞清楚了物理中斷號如何獲得,又如何對應到邏輯中斷號,最後,觸發了IST,整個中 斷處理就結束了。2440全部的中斷源都已經被納入了,添加一個採用某個中斷源的設備驅動,只需要用kernelIOControl函數通過物理中斷產生 一個邏輯中斷號就可以了!這樣的話,只要在0x18位置有一個跳轉指令就可以了(但還沒有找到這條跳轉指令)。
1 3 其他中斷相關函數了解
關注WINCE500/PLATFORM/COMMON/SRC/ARM/SAMSUNG/S3C2440A/Intr/intr.c中的其他函數:
OEMInterruptHandler包含了對以下中斷的判斷和處理:
IRQ_TIMER4,這個是系統節拍;
IRQ_TIMER2,作用未知(Profiling timer);
IRQ_EINT4_7,EINT8_23,外部中斷;
任何一箇中斷髮生後,先mask該中斷(禁止中斷),然後再清除中斷請求:
       mask = 1 << irq;
            SETREG32(&g_pIntrRegs->INTMSK, mask);
            OUTREG32(&g_pIntrRegs->SRCPND, mask);
            OUTREG32(&g_pIntrRegs->INTPND, mask);

其它中斷獲取邏輯中斷號:
   // First find if IRQ is claimed by chain
        sysIntr = NKCallIntChain((UCHAR)irq);
        if (sysIntr == SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr)) {
            // IRQ wasn't claimed, use static mapping
            sysIntr = OALIntrTranslateIrq(irq);
        }

關於NKCallIntChain的說明:
如果沒有與ISR關聯的IRQ事件,返回SYSINTR_CHAIN ;
除此之外,將返回IRQ對應的SYSINTR值。

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