标签: 杂谈 | 分类: CEstudynote |
中断
WCE有两种私有的中断表,一种是物理中断——中断请求(IRQs),另一种是逻辑中断——SYSINTR值。WinCE必须将一个物理中断和一个逻辑中断关联起来。而且,这两者必须是唯一的,而且是delicated.
物理中断号for example:
#define IRQ_GPIO0_WIFI IRQ_BULVERDE_MAX+9
#define OAL_INTR_IRQ_MAXIMUM 64
该值表示物理中断——IRQs的最大值,现在最大只支持到64。
逻辑中断号定义在:for example:
#define SYSINTR_WIFI SYSINTR_FIRMWARE+16 sysintr_firmware 也代表最大值。
两个中断表,定义在platform\c8090\platform\src\common\intr\base\map.c
static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
#define SYSINTR_DEVICES 8
#define SYSINTR_MAX_DEVICES 64
#define SYSINTR_MAXIMUM (SYSINTR_DEVICES+SYSINTR_MAX_DEVICES)
1. define IRQ and sysintr
OEM Adaptation Layer——OAL初始化函数是OEMInit(),它是WinCE的OAL层初始化函数,在基本初始化完成之后,由内核调用,定义在:
platform\c8090\platform\mainstoneii\src\kernel\oal\init.c。
在这里调用中断初始化函数:OALIntrInit(),该函数定义在:
platform\c8090\platform\common\src\arm\intel\pxa27x\intr\intr.c中,该函数首先调用函数OALIntrMapInit(),初始化前面提到的两个数组表g_oalSysIntr2Irq和goalIrq2SysIntr。该函数定义在platform\c8090\platform\common\src\common\intr\base\map.c,源码如下:
for (i = 0; i < SYSINTR_MAXIMUM; i++) {
g_oalSysIntr2Irq[i] = OAL_INTR_IRQ_UNDEFINED;
}
for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) {
g_oalIrq2SysIntr[i] = SYSINTR_UNDEFINED;
}
2. map IRQ to sysintr
然后调用函数BSPIntrInit()将物理中断和逻辑中断关联起来,该函数定义在:
platform\c8090\platform\mainstoneii\src\kernel\oal\intr.c中。
关联代码例子如下:
OALIntrStaticTranslate(SYSINTR_PMIC, IRQ_GPIO0);
OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBOHCI);
OALIntrStaticTranslate(SYSINTR_TOUCH, IRQ_GPIOXX_WM9712);
OALIntrStaticTranslate(SYSINTR_TOUCH_CHANGED, IRQ_OSMR1);
OALIntrStaticTranslate(SYSINTR_KEYPAD, IRQ_KEYPAD);
前面都是逻辑中断,后面是物理中断。OALIntrStaticTranslate函数定义在:
platform\c8090\platform\common\src\common\intr\base\map.c,源码如下:
if (irq < OAL_INTR_IRQ_MAXIMUM && sysIntr < SYSINTR_MAXIMUM) {
g_oalSysIntr2Irq[sysIntr] = irq;
g_oalIrq2SysIntr[irq] = sysIntr;
}
3. interrupt initialize
set GPIO configuration
set interrupt information including IRQ,system interrupt, IST function and so on.
setup interrupt: Use ISR to process interrupt
1. create interrupt event to interruptevent:
if(!(pMyIntrInfo->hIntrEvent = CreateEvent( NULL, FALSE, FALSE, NULL))) { DEBUGMSG(1, (TEXT("CreateEvent() FAILED"))); goto errFuncRet; }
2. convert the irq into sysinterrupt (kernelIoControl()accesses kernel to transfer OEMIoControl. OEMIoControl use I/O to achieve some function.)
IOCTL_HAL_REQUEST_SYSINTR makes OAL return the relative sysintr according to irq.
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &pMyIntrInfo->irq, sizeof(DWORD),
&pMyIntrInfo->dwSysIntr, sizeof(pMyIntrInfo->dwSysIntr), NULL))
3. create IST according to sysintr.
pMyIntrInfo->hISTHandle = CreateThread((LPSECURITY_ATTRIBUTES)NULL, 0, myIST, pMyIntrInfo, CREATE_SUSPENDED, &threadID);
4. set the priority to the IST.
CeSetThreadPriority(pMyIntrInfo->hISTHandle, DEFAULT_IST_PRIORITY);
5. mask the other interrupt with the same or lower level.(OEMIterruptDisable)
InterruptDisable(pMyIntrInfo->dwSysIntr);
interrupt service controller program (ISCP) transfers OEMinterruptDisable to close the relative interrupt pin.( mask controller)
6. use interruptinitialize to make kernel transfer OEMInterruptEnable to create mapping between ISR and IST.
if (! InterruptInitialize(pMyIntrInfo->dwSysIntr, pMyIntrInfo->hIntrEvent, NULL, 0)) { DEBUGMSG(1, (TEXT("%s - InterruptInitialize(%d,%08x) Failed\r\n"),
generate IST process the interrupt.
1. get the thread start
ResumeThread(pMyIntrInfo->hISTHandle);
2. wait for interrupt event
dwStatus = WaitForSingleObject(pMyIntrInfo->hIntrEvent, INFINITE);
3. process IST res = pMyIntrInfo->pIstFunc(pMyIntrInfo->param);
4. finish interrupt to clear the mask of interrupt(OEMInterruptDone)
InterruptDone(pMyIntrInfo->dwSysIntr);
then, host can receive the same interrupt again.