中断使能、禁止程序——之oem.c程序分析

时间:2021-02-09 19:33:09

刚才看了何宗健老师的书,在5.0BSP中,在系统启动阶段,除了时钟中断以外,其他中断都是关闭的。在加载驱动的时候,驱动程序负责加载自己所用到的驱动,方法是调用InterruptInitialize。真正工作的是OEMInterruptEnable而这个函数又调用OALIntrEnableIrqs函数。

 

现在让我们一步一步来看代码分析。

首先看InterruptInitialize----------奇怪了,在4.2中的驱动中能找到这个函数被调用,5.0下的却不行。哎怎么回事?

 

然后OEMInterruptEnable

这个函数在C:/WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/COMMON/oem.c

//------------------------------------------------------------------------------
//
//  File: oem.c
//
//  This file implements a standard implementation of OEMInterrupt functions
//  relating to enabling, disabling and finishing interrupts.
//
#include <windows.h>
#include <nkintr.h>
#include <oal.h>


//------------------------------------------------------------------------------
//
//  Function:  OEMInterruptEnable
//
//  This function enables the IRQ given its corresponding SysIntr value.
//  Function returns true if SysIntr is valid, else false.
//
BOOL OEMInterruptEnable(DWORD sysIntr, LPVOID pvData, DWORD cbData)
{
    BOOL rc = FALSE;
    const UINT32 *pIrqs;//注意这个是个常量指针,以前我总想找他的老家,汗!
    UINT32 count;

    OALMSG(OAL_INTR&&OAL_VERBOSE, 
        (L"+OEMInterruptEnable(%d, 0x%x, %d)/r/n", sysIntr, pvData, cbData
    ));

    // SYSINTR_VMINI & SYSINTR_TIMING are special cases
    if (sysIntr == SYSINTR_VMINI || sysIntr == SYSINTR_TIMING) {
        rc = TRUE;
        goto cleanUp;
    }

    // Obtain the SYSINTR's underlying IRQ number
    //下面使用的函数很有用,等下会分析。是个关键函数
    if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) {
        // Indicate invalid SysIntr
        OALMSG(OAL_ERROR, (
            L"ERROR: OEMInterruptEnable: IRQs are undefined for SysIntr %d/r/n", 
            sysIntr 
        ));
        goto cleanUp;
    }

    // Enable the interrupt
    rc = OALIntrEnableIrqs(count, pIrqs);//这个也是关键函数

cleanUp:    
    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OEMInterruptEnable(rc = 1)/r/n"));
    return rc;
}
再看OALIntrEnableIrqs这个函数

C:/WINCE500/PLATFORM/SMDK2440A/Src/Common/Intr/intr.c

 


//------------------------------------------------------------------------------
//
//  Function:  OALIntrEnableIrqs
//
BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
{
    BOOL rc = TRUE;
    UINT32 i, mask, irq;

    OALMSG(OAL_INTR&&OAL_FUNC, (
        L"+OALIntrEnableIrqs(%d, 0x%08x)/r/n", count, pIrqs
    ));

    for (i = 0; i < count; i++) {
#ifndef OAL_BSP_CALLBACKS
        irq = pIrqs[i];
#else
        // Give BSP chance to enable irq on subordinate interrupt controller
        irq = BSPIntrEnableIrq(pIrqs[i]);
#endif
        if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
        // Depending on IRQ number use internal or external mask register
        if (irq <= IRQ_ADC) {
            // Use interrupt mask register
            CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
        } else if (irq <= IRQ_EINT7) {
            // Use external mask register
            CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_EINT4_7);
            CLRREG32(&g_pPortRegs->EINTMASK, 1 << (irq - IRQ_EINT4 + 4));
        } else if (irq <= IRQ_EINT23) {
            // Use external mask register
            mask = 1 << (irq - IRQ_EINT4 + 4);
            OUTREG32(&g_pPortRegs->EINTPEND, mask);
            CLRREG32(&g_pPortRegs->EINTMASK, mask);
            mask = 1 << IRQ_EINT8_23;
            if ((INREG32(&g_pIntrRegs->INTPND) & mask) != 0) {
                OUTREG32(&g_pIntrRegs->INTPND, mask);
            }
            CLRREG32( &g_pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
        } else {
            rc = FALSE;
        }
    }        

    OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)/r/n", rc));
    return rc;    
}
------------OALIntrEnableIrqs函数的确是使能了一些中断,不过在OAL中根本没有调用这些函数(甚至这这个oem.c大部分函数都没有用到,这里只是分析一下5.0静态中断的一个方法)

中断禁止函数OEMInterruptDisable,中断完成函数OEMInterruptDone都是同样的道理(他们都在oem.c)在这里不再赘述。

下面来看OALIntrTranslateSysIntr这个关键函数

C:/WINCE500/PLATFORM/SMDK2440A/Src/Inc/oal_intr.h有这个函数的声明,但是没有具体实现(貌似这里限定了2440最大中断数目)。我觉得这是三星想自己做,但是后来没有做完——哎!这些BSP都是三星的实验版本。我们要小心使用。N多函数名相同,但是却没有使用,并且没有文档的

这下看PB下的OALIntrTranslateSysIntr

//------------------------------------------------------------------------------
//
//  File:  C:/WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c
//
//  The file implement simple table/array based mapping between IRQ and SYSINTR
//  which is suitable for most OAL implementations.
//
#include <windows.h>
#include <nkintr.h>
#include <oal_intr.h>
#include <oal_log.h>

//------------------------------------------------------------------------------

static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];

//------------------------------------------------------------------------------
//
//  Function:  OALIntrTranslateSysIntr
//
//  This function maps a SYSINTR to its corresponding IRQ. It is typically used
//  in OEMInterruptXXX to obtain IRQs for given SYSINTR.
//
BOOL OALIntrTranslateSysIntr(
    UINT32 sysIntr, UINT32 *pCount, const UINT32 **ppIrqs
) {
    BOOL rc;

    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OALTranslateSysIntr(%d)/r/n", sysIntr));
    
    // Valid SYSINTR?
    if (sysIntr >= SYSINTR_MAXIMUM) {
        rc = FALSE;
        goto cleanUp;
    }
    *pCount = 1;
    //从下一句可以看出,这里只是取出相应的中断而已,不过g_oalIrq2SysIntr这个存储
    //中断向量的数组是static类型,并没有得到初始化,所以我据此推测我这个三星
   //BSP并没有使用这个OEM函数中断使能、禁止的中断方法而是使用的是KernelIoControl
    *ppIrqs = &g_oalSysIntr2Irq[sysIntr];
    rc = TRUE;

cleanUp:
    OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALTranslateSysIntr(rc = %d)/r/n", rc));
    return rc;
}
不过C:/WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c(32)://  Function:  OALIntrMapInit这个函数在我的BSP中使用到了,他的作用是初始化中断为未定义类型

 

//------------------------------------------------------------------------------

static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];


//------------------------------------------------------------------------------
//
//  Function:  OALIntrMapInit
//
//  This function must be called from OALInterruptInit to initialize mapping
//  between IRQ and SYSINTR. It simply initialize mapping arrays.
//
VOID OALIntrMapInit()
{
    UINT32 i;
    
    OALMSG(OAL_FUNC&&OAL_INTR, (L"+OALIntrMapInit/r/n"));

    // Initialize interrupt maps
    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;
    }

    OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrMapInit/r/n"));
}
它是在哪里被使用的呢?来看看,我至今不明白它是怎么被调用的。

 

其他关于使用OEM函数禁止中断的函数也在这个map.c里面,

 

注意:这个笔记还没有完成,可能我的认识有极大错误,请大家看了不要太深信,如果发现有误,请在博客留言给我。谢谢。


iwillbeback008 发表于2008年12月21日 21:54:36  IP:举报回复删除
OALIntrMapInit() ,只是填充了
g_oalSysIntr2Irq[]和g_oalIrq2SysIntr[]填充了UNDEFINED值,比没有大的作用!
正真有意义的为这两个数组填充元素内容的通常是在要使用某个中断序号的外设的驱动的初始化函数中。
比如在BSPItrInit函数的最后,使用OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH)iwillbeback008 发表于2008年12月21日 21:54:47  IP:举报回复删除
OALIntrMapInit() ,只是填充了
g_oalSysIntr2Irq[]和g_oalIrq2SysIntr[]填充了UNDEFINED值,比没有大的作用!
正真有意义的为这两个数组填充元素内容的通常是在要使用某个中断序号的外设的驱动的初始化函数中。
比如在BSPItrInit函数的最后,使用OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH)iwillbeback008 发表于2008年12月21日 21:57:02  IP:举报回复删除
也就是说OALIntrMapInit() 函数目前只是拿来先给两个数组的填充些无聊的值,估计是三星是为了“他们想以后改进或是为啥功能预留”的!iwillbeback008 发表于2008年12月21日 22:01:39  IP:举报回复删除
5.0下,InterruptInitialize(),这个函数,我也暂时没有找到,不过应该用处不大,也就是在驱动程序开始创建对应线程是调用的,同时也调用InterruptDone()函数。这个可以从串口的COM_Init函数中调用StartDispatchThread()函数中看得出来gooogleman 发表于2008年12月22日 9:19:06  IP:举报回复删除
@iwillbeback008
——————
其实上面的东西是微软留的静态接口,2440 5.0的BSP并没有用到。
5.0的BSP采用动态中断。这些我在后面的文章都做了补充,这里我就没有再修改了。gooogleman 发表于2008年12月22日 9:19:08  IP:举报回复删除
@iwillbeback008
——————
其实上面的东西是微软留的静态接口,2440 5.0的BSP并没有用到。
5.0的BSP采用动态中断。这些我在后面的文章都做了补充,这里我就没有再修改了。iwillbeback008 发表于2008年12月25日 19:52:45  IP:举报回复删除
5.0的BSP采用动态中断。这些我在后面的文章都做了补充,这里我就没有再修改了。
---指的是这篇《KernelIoControl和OEMIoControl的分析和使用》博文么?gooogleman 发表于2008年12月25日 21:29:11  IP:举报回复删除
不是,我记得我发了好几篇2440 5.0中断的文章。
就是这个月发的,记得,你看看吧。

本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gooogleman/archive/2008/11/11/3276578.aspx