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

作者:wogoyixikexie@gliet

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

 

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

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

 

然后OEMInterruptEnable

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

  1. //------------------------------------------------------------------------------
  2. //
  3. //  File: oem.c
  4. //
  5. //  This file implements a standard implementation of OEMInterrupt functions
  6. //  relating to enabling, disabling and finishing interrupts.
  7. //
  8. #include <windows.h>
  9. #include <nkintr.h>
  10. #include <oal.h>
  11. //------------------------------------------------------------------------------
  12. //
  13. //  Function:  OEMInterruptEnable
  14. //
  15. //  This function enables the IRQ given its corresponding SysIntr value.
  16. //  Function returns true if SysIntr is valid, else false.
  17. //
  18. BOOL OEMInterruptEnable(DWORD sysIntr, LPVOID pvData, DWORD cbData)
  19. {
  20.     BOOL rc = FALSE;
  21.     const UINT32 *pIrqs;//注意这个是个常量指针,以前我总想找他的老家,汗!
  22.     UINT32 count;
  23.     OALMSG(OAL_INTR&&OAL_VERBOSE, 
  24.         (L"+OEMInterruptEnable(%d, 0x%x, %d)/r/n", sysIntr, pvData, cbData
  25.     ));
  26.     // SYSINTR_VMINI & SYSINTR_TIMING are special cases
  27.     if (sysIntr == SYSINTR_VMINI || sysIntr == SYSINTR_TIMING) {
  28.         rc = TRUE;
  29.         goto cleanUp;
  30.     }
  31.     // Obtain the SYSINTR's underlying IRQ number
  32.     //下面使用的函数很有用,等下会分析。是个关键函数
  33.     if (!OALIntrTranslateSysIntr(sysIntr, &count, &pIrqs)) {
  34.         // Indicate invalid SysIntr
  35.         OALMSG(OAL_ERROR, (
  36.             L"ERROR: OEMInterruptEnable: IRQs are undefined for SysIntr %d/r/n"
  37.             sysIntr 
  38.         ));
  39.         goto cleanUp;
  40.     }
  41.     // Enable the interrupt
  42.     rc = OALIntrEnableIrqs(count, pIrqs);//这个也是关键函数
  43. cleanUp:    
  44.     OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OEMInterruptEnable(rc = 1)/r/n"));
  45.     return rc;
  46. }

再看OALIntrEnableIrqs这个函数

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

 

  1. //------------------------------------------------------------------------------
  2. //
  3. //  Function:  OALIntrEnableIrqs
  4. //
  5. BOOL OALIntrEnableIrqs(UINT32 count, const UINT32 *pIrqs)
  6. {
  7.     BOOL rc = TRUE;
  8.     UINT32 i, mask, irq;
  9.     OALMSG(OAL_INTR&&OAL_FUNC, (
  10.         L"+OALIntrEnableIrqs(%d, 0x%08x)/r/n", count, pIrqs
  11.     ));
  12.     for (i = 0; i < count; i++) {
  13. #ifndef OAL_BSP_CALLBACKS
  14.         irq = pIrqs[i];
  15. #else
  16.         // Give BSP chance to enable irq on subordinate interrupt controller
  17.         irq = BSPIntrEnableIrq(pIrqs[i]);
  18. #endif
  19.         if (irq == OAL_INTR_IRQ_UNDEFINED) continue;
  20.         // Depending on IRQ number use internal or external mask register
  21.         if (irq <= IRQ_ADC) {
  22.             // Use interrupt mask register
  23.             CLRREG32(&g_pIntrRegs->INTMSK, 1 << irq);
  24.         } else if (irq <= IRQ_EINT7) {
  25.             // Use external mask register
  26.             CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_EINT4_7);
  27.             CLRREG32(&g_pPortRegs->EINTMASK, 1 << (irq - IRQ_EINT4 + 4));
  28.         } else if (irq <= IRQ_EINT23) {
  29.             // Use external mask register
  30.             mask = 1 << (irq - IRQ_EINT4 + 4);
  31.             OUTREG32(&g_pPortRegs->EINTPEND, mask);
  32.             CLRREG32(&g_pPortRegs->EINTMASK, mask);
  33.             mask = 1 << IRQ_EINT8_23;
  34.             if ((INREG32(&g_pIntrRegs->INTPND) & mask) != 0) {
  35.                 OUTREG32(&g_pIntrRegs->INTPND, mask);
  36.             }
  37.             CLRREG32( &g_pIntrRegs->INTMSK, 1 << IRQ_EINT8_23);
  38.         } else {
  39.             rc = FALSE;
  40.         }
  41.     }        
  42.     OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALIntrEnableIrqs(rc = %d)/r/n", rc));
  43.     return rc;    
  44. }

------------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

  1. //------------------------------------------------------------------------------
  2. //
  3. //  File:  C:/WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c
  4. //
  5. //  The file implement simple table/array based mapping between IRQ and SYSINTR
  6. //  which is suitable for most OAL implementations.
  7. //
  8. #include <windows.h>
  9. #include <nkintr.h>
  10. #include <oal_intr.h>
  11. #include <oal_log.h>
  12. //------------------------------------------------------------------------------
  13. static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
  14. static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
  15. //------------------------------------------------------------------------------
  16. //
  17. //  Function:  OALIntrTranslateSysIntr
  18. //
  19. //  This function maps a SYSINTR to its corresponding IRQ. It is typically used
  20. //  in OEMInterruptXXX to obtain IRQs for given SYSINTR.
  21. //
  22. BOOL OALIntrTranslateSysIntr(
  23.     UINT32 sysIntr, UINT32 *pCount, const UINT32 **ppIrqs
  24. ) {
  25.     BOOL rc;
  26.     OALMSG(OAL_INTR&&OAL_VERBOSE, (L"+OALTranslateSysIntr(%d)/r/n", sysIntr));
  27.     
  28.     // Valid SYSINTR?
  29.     if (sysIntr >= SYSINTR_MAXIMUM) {
  30.         rc = FALSE;
  31.         goto cleanUp;
  32.     }
  33.     *pCount = 1;
  34.     //从下一句可以看出,这里只是取出相应的中断而已,不过g_oalIrq2SysIntr这个存储
  35.     //中断向量的数组是static类型,并没有得到初始化,所以我据此推测我这个三星
  36.    //BSP并没有使用这个OEM函数中断使能、禁止的中断方法而是使用的是KernelIoControl
  37.     *ppIrqs = &g_oalSysIntr2Irq[sysIntr];
  38.     rc = TRUE;
  39. cleanUp:
  40.     OALMSG(OAL_INTR&&OAL_VERBOSE, (L"-OALTranslateSysIntr(rc = %d)/r/n", rc));
  41.     return rc;
  42. }

不过C:/WINCE500/PLATFORM/COMMON/SRC/COMMON/INTR/BASE/map.c(32)://  Function:  OALIntrMapInit这个函数在我的BSP中使用到了,他的作用是初始化中断为未定义类型

 

  1. //------------------------------------------------------------------------------
  2. static UINT32 g_oalSysIntr2Irq[SYSINTR_MAXIMUM];
  3. static UINT32 g_oalIrq2SysIntr[OAL_INTR_IRQ_MAXIMUM];
  4. //------------------------------------------------------------------------------
  5. //
  6. //  Function:  OALIntrMapInit
  7. //
  8. //  This function must be called from OALInterruptInit to initialize mapping
  9. //  between IRQ and SYSINTR. It simply initialize mapping arrays.
  10. //
  11. VOID OALIntrMapInit()
  12. {
  13.     UINT32 i;
  14.     
  15.     OALMSG(OAL_FUNC&&OAL_INTR, (L"+OALIntrMapInit/r/n"));
  16.     // Initialize interrupt maps
  17.     for (i = 0; i < SYSINTR_MAXIMUM; i++) {
  18.         g_oalSysIntr2Irq[i] = OAL_INTR_IRQ_UNDEFINED;
  19.     }
  20.     for (i = 0; i < OAL_INTR_IRQ_MAXIMUM; i++) {
  21.         g_oalIrq2SysIntr[i] = SYSINTR_UNDEFINED;
  22.     }
  23.     OALMSG(OAL_FUNC&&OAL_INTR, (L"-OALIntrMapInit/r/n"));
  24. }

它是在哪里被使用的呢?来看看,我至今不明白它是怎么被调用的。

 

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

 

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

转载请表明wogoyixikexie@gliet桂林电子科技大学一系科协,如有错误,希望能够指出。

评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值