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值。
WINCE5.0的中斷深入瞭解
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.