WINCE6.0 中断处理OEMInterruptHandler--KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,...)

lzj000008   2009-5-27 11:40 楼主
最近在看WINCE中断处理,有一事不明,希望大家讨论一下:
问题1:当物理中断发生后首先会被调用的函数是不是OEMInterruptHandler?
问题2:OEMInterruptHandler函数作用是根据物理中断号(IRQ)返回对应的系统中断号(SYSINTR_XXX),既然这个函数已经返回了逻辑中断号,为什么在驱动程序中还需要调用
KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR,...)这两个函数有什么关系吗?

回复评论 (4)

平台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);
}
点赞  2009-5-27 11:42
我帮顶
点赞  2009-9-21 10:00
KernelIoControl只是向系统申请一个系统中断号码,
PXA310的写法和2440 6410几乎一致啊,连名字都一样呢,谁抄袭了谁呢?
点赞  2009-9-21 10:16
引用: 引用楼主 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
点赞  2009-9-23 11:01
电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 京公网安备 11010802033920号
    写回复