最近在看WINCE中断处理,有一事不明,希望大家讨论一下:
问题1:当物理中断发生后首先会被调用的函数是不是OEMInterruptHandler?
问题2:OEMInterruptHandler函数作用是根据物理中断号(IRQ)返回对应的系统中断号(SYSINTR_XXX),既然这个函数已经返回了逻辑中断号,为什么在驱动程序中还需要调用
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,...)这两个函数有什么关系吗?
平台PXA310,我所看的驱动是SDIO中的中断处理,OEMInterruptHandler代码如下:
ULONG OEMInterruptHandler(ULONG ra)
{
UINT32 irq = OAL_INTR_IRQ_UNDEFINED;
UINT32 sysIntr = SYSINTR_NOP;
if (!g_pICReg) {
return(SYSINTR_NOP);
}
// Two steps for now, maybe condense later.
irq = XllpReadINTCReg(XLLP_INTC_ICHP);
irq = (irq >> 16) & 0x3F;
OALProfIRQEvent(irq);
//add by hgeng 2009-05-26
RETAILMSG(1, (TEXT("OEMInterruptHandler@@Intr\intr.c: irq = %d \r\n"), irq));
if (irq == 0)
{
return(SYSINTR_NOP);
}
// System timer interrupt?
else if(irq == IRQ_OSMRXX_4)
{
P_XLLP_OST_T pOSTRegs = (P_XLLP_OST_T)OALPAtoVA(MONAHANS_BASE_REG_PA_OST, FALSE);
if (pOSTRegs->ossr & XLLP_OSSR_M4)
{
sysIntr = OALTimerIntrHandler();
}
else if(pOSTRegs->ossr & XLLP_OSSR_M8)
{
UINT32 utiliz;
sysIntr = IPM_WindowDone(&utiliz);
}
}
else if (irq == IRQ_OSMR0)
{
XllpINTCEnableSource(irq,XLLP_FALSE);
sysIntr = SYSINTR_NOP;
}
// Profiling timer interrupt?
else if (irq == IRQ_OSMR2)
{
// Mask the interrupt
(void) XllpINTCEnableSource(irq,XLLP_FALSE);
// The rest is up to the profiling interrupt handler (if profiling
// is enabled).
//
if (g_pProfilerISR) {
sysIntr = g_pProfilerISR(ra);
}
}
else if (irq == IRQ_OSMR3)
{
XllpINTCEnableSource(irq,XLLP_FALSE);
sysIntr = SYSINTR_NOP;
}
#ifdef ENABLE_RCOMP
else if (irq == XLLP_INTC_S_DMEM)
{
// check if the RCOMP interrupt by read DMCISR[RCI] bit.
// if so,
// 1, clear the DMCISR[RCI]
// 2, read the MDCNFG for DMCISR, use the PCODE and NCODE of it to calculate.
// 3, write the PAD_XX with the new value.
XLLP_UINT32_T regIsr;
P_XLLP_DMEM_REGISTER_T pReg = (P_XLLP_DMEM_REGISTER_T) OALPAtoVA(MONAHANS_BASE_REG_PA_DMEMC, FALSE);
XllpINTCEnableSource(irq,XLLP_FALSE);
regIsr = pReg->dmcisr;
if (pReg->dmcisr & XLLP_DMCISR_RCI )
{
OALMSG(OAL_INTR, (L"OALIntrInit: irq number %x\r\n", irq));
pReg->dmcisr &= XLLP_DMCISR_RCI; //all the bits are write-clear bit or read-only bit.
OALMSG(OAL_INTR, (L"OALIntrInit: to update Rcomp()\r\n"));
XllpMemcRcompUpdate( pReg );
}
XllpINTCEnableSource(irq,XLLP_TRUE);
sysIntr = SYSINTR_NOP;
}
#endif
// Board-level interrupts
else
{
UINT32 origIrq = irq; // save the original so we can tell if it's BSP specific irq
//OALMSG(1, (L"OAL:OEMInterruptHandler: Irq %d\r\n", irq));
if ((irq == IRQ_GPIO0)||(irq == IRQ_GPIO1))
{
// Mask the interrupt
(void) XllpINTCEnableSource(irq,XLLP_FALSE);
#ifdef OAL_BSP_CALLBACKS
// Give BSP chance to translate IRQ -- if there is subordinate
// interrupt controller in BSP it give chance to decode its status
// and change IRQ
irq = BSPIntrActiveIrq(irq);
#endif
} else if(irq == IRQ_GPIOXX_2) {
UINT32 gedr, ggroup, i;
#ifdef BSP_DEBUG_LJ // For Debug - jli@sychip.com.cn
//OALMSG(1, (L"OAL:OEMInterruptHandler: GPIO Irq %d\r\n", irq));
#endif // LJDEBUG
if ((g_pGPIO->gedr0)&0xfffffffc) { // don't care GPIO0 and GPIO1
gedr = g_pGPIO->gedr0;
ggroup = 0;
} else if (g_pGPIO->gedr1) {
gedr = g_pGPIO->gedr1;
ggroup = 1;
} else if (g_pGPIO->gedr2) {
gedr = g_pGPIO->gedr2;
ggroup = 2;
} else if (g_pGPIO->gedr3) {
gedr = g_pGPIO->gedr3;
ggroup = 3;
} else {
//TO-DO: actually, should ASSERT here.
//TEMPORARY FIX: ignore this interrupt to avoid dead loop here
return(SYSINTR_NOP);
}
// Find out which bit causes the IRQ.
i = 0;
while(!(gedr&0x1)) {
gedr = gedr>>1;
i++;
}
i = i + ggroup*32;
//OALMSG(1, (L"OAL:OEMInterruptHandler: i = %d\r\n", i));
// Get current level on that GPIO
//XllpGpioGetLevel (g_pGPIO, i, &(g_GPIOPrevLevel));
// Clear edge detect status first.
// Don't disable edge detect here.
// Otherwise, we may lose GPIO edge interrupt.
// In future, GPIO level interrupt is preferred.
//if (GPIO_RISE&g_GPIOEdgeDetect)
// XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, i, XLLP_OFF);
//if (GPIO_FALL&g_GPIOEdgeDetect)
// XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, i, XLLP_OFF);
XllpGpioClearEdgeDetectStatus (g_pGPIO, i);
// Compose the IRQ number.
irq = IRQ_GPIO_SHARE_BASE - 2 + i;
#ifdef OAL_BSP_CALLBACKS
// Give BSP chance to translate IRQ -- if there is subordinate
// interrupt controller in BSP it give chance to decode its status
// and change IRQ
irq = BSPIntrActiveIrq(irq);
#endif
} else
{
// Mask the interrupt
(void) XllpINTCEnableSource(irq,XLLP_FALSE);
}
// First find if IRQ is claimed by chain
sysIntr = (UINT16)NKCallIntChain((UCHAR)irq);
//fix the Intallable ISR error according to the MS documents.
//If the installable ISR returns SYSINTR_NOP,
//the BSP interrupt handler code will re-enable the interrupt and
//return SYSINTR_NOP.
if (sysIntr == SYSINTR_NOP)
{
//SETREG32(&g_pICReg->icmr, (1 << irq));
(void) XllpINTCEnableSource(irq,XLLP_TRUE);
return SYSINTR_NOP;
}
if (sysIntr == (UINT16)SYSINTR_CHAIN || !NKIsSysIntrValid(sysIntr))
{
// IRQ wasn't claimed, use static mapping
sysIntr = OALIntrTranslateIrq(irq);
#ifdef BSP_DEBUG_LJ
OALMSG(1, (L"-OALIntrTranslateIrq--hgeng\r\n"));
OALMSG(1, (L"+OALIntrTranslateIrq(%d)\r\n", irq));
OALMSG(1, (L"-OEMTranslateIrq(sysIntr = %d)\r\n", sysIntr));
#endif
}
// unmask interrupts in case it's NOP or invalid
if (SYSINTR_NOP == sysIntr) {
if (origIrq != irq) {
#ifdef OAL_BSP_CALLBACKS
// BSP specific irq
BSPIntrEnableIrq (irq);
#endif
if (origIrq == IRQ_GPIOXX_2) {
if (GPIO_RISE&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
XllpGpioSetRisingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
if (GPIO_FALL&g_GPIOEdgeDetect[IRQ_TO_GPIO_NUM(irq)])
XllpGpioSetFallingEdgeDetectEnable(g_pGPIO, IRQ_TO_GPIO_NUM(irq), XLLP_ON);
}
} else
{
// Unmask the interrupt
(void) XllpINTCEnableSource(irq,XLLP_TRUE);
}
}
}
return (sysIntr);
}
KernelIoControl只是向系统申请一个系统中断号码,
PXA310的写法和2440 6410几乎一致啊,连名字都一样呢,谁抄袭了谁呢?
引用: 引用楼主 cgenghui 的回复:
最近在看WINCE中断处理,有一事不明,希望大家讨论一下:
问题1:当物理中断发生后首先会被调用的函数是不是OEMInterruptHandler?
问题2:OEMInterruptHandler函数作用是根据物理中断号(IRQ)返回对应的系统中断号(SYSINTR_XXX),既然这个函数已经返回了逻辑中断号,为什么在驱动程序中还需要调用
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,...)这两个函数有什么关系吗?
1.发生中断后,CPU跳转到异常向量表处并执行IRQHandler,然后调用OEMInterruptHandler。
2.OEMInterruptHandler会根据IRQ返回对应的SYSINTR号,但前提是驱动中先通过KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,...)或其他方式建立IRQ与SYSINTR的映射,否则会返回SYSINTR_NOP