看三星的5.0中断,看的一头雾水,相当郁闷。现在重新理清一下。
sontitan牛人也指示过一些。
引用楼主 wangxin_801115 的帖子:
请问这两个函数KernelIoControl和InterruptInitialize函数的区别是什么呢??
个人理解:先用KernelIoControl申请中断号
然后利用InterruptInitialize把 (从KernelIoControl申请的)中断号与事件相关联
主要作用是使能waitForSingleObject中挂起的事件
KernelIoControl这个函数有很多人都说不能申请成功
那么是否还有另外一种所谓的静态申请中断号的方法
在oalintr.h中添加中断的宏定义
然后…
1 2个函数没有任何关系;KernelIoControl是驱动/应用程序和kernel通讯的一个接口函数,具体的调用意义是看该函数的IOCTRL是什么以及kernel中对应的处理函数(ioctrl table);
2 关于中断,WINCE 5之前都是静态中断,从CE 5开始中断申请分为动态申请和静态分配2种;楼主用的KernelIoControl+IOCTL_HAL_REQUEST_SYSINTR就是动态申请的方法;静态分配其实很简单,在OEMInterruptHandler里直接switch case即可;具体实现很多,各家BSP不一样,但是道理都是如此;
其实,动态申请就是由系统维护一个table,使得OEM允许其他厂商的驱动以安装的形式动态加到这个table里。作为OEM自己,其实维护一个静态的中断分配就可以了,驱动完全不用动态申请。只不过很多参考BSP用了这个形式,导致大家都在动态申请。
后来有人提示,我们来分析如下代码
// read registry settings
// read the SDIO SYSINTR value
m_dwSDIOIrq = regDevice.ValueDW( SDIO_IRQ_TEXT, 0xffffffff );
if( m_dwSDIOIrq == 0xffffffff )
{
// invalid SDIO IRQ value!
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO IRQ value!/r/n")));
fRetVal = FALSE;
goto FUNCTION_EXIT;
}
// convert the SDI hardware IRQ into a logical SYSINTR value
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &m_dwSDIOIrq, sizeof(DWORD), &m_dwSDIOSysIntr, sizeof(DWORD), NULL))
{
// invalid SDIO SYSINTR value!
DEBUGMSG(SDCARD_ZONE_ERROR, (TEXT("invalid SDIO SYSINTR value!/r/n")));
m_dwSDIOSysIntr = SYSINTR_UNDEFINED;
fRetVal = FALSE;
goto FUNCTION_EXIT;
}
m_dwSDIOSysIntr 这个变量是在哪里定义的呢?;不过根据m_dwSDIOSysIntr = SYSINTR_UNDEFINED;
这个可以看出,这个明显和中断相关了。因为刚开始初始化中断都是m_SYSINTR_UNDEFINED的;
后来找到m_dwSDIOSysIntr有关的SD中断线程绑定
//----- 10. Setup the IST for handling SDIO data transfer interrupts -----
m_hSDIOInterruptEvent = CreateEvent(NULL, FALSE, FALSE,NULL);
if(NULL == m_hSDIOInterruptEvent)
{
status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
goto INIT_ERROR;
}
// initialize the card insertion interrupt event
if(!InterruptInitialize (m_dwSDIOSysIntr, m_hSDIOInterruptEvent,
NULL, 0))
{
status = SD_API_STATUS_INSUFFICIENT_RESOURCES;
goto INIT_ERROR;
}
m_hSDIOInterruptThread = CreateThread(NULL, 0,
(LPTHREAD_START_ROUTINE)SD_IOInterruptIstThread,
this, 0, &threadID);
后来又找到了如下函数
//----- 2. Disable and cleanup the ISTs/events ------
InterruptDisable (m_dwSDIOSysIntr);
//=====================================================
case SDHCDAckSDIOInterrupt:
DEBUGMSG (SDCARD_ZONE_INFO,(TEXT("SDHCDSlotOptionHandler option=SDHCDAckSDIOInterrupt/r/n")));
//----- 2. Clear the SDIO interrupt pending bit -----
Ack_SDIO_Interrupts();
InterruptDone(m_dwSDIOSysIntr);//--------和4.2的有什么区别?
后来我又找到了如下代码
//--IRQ_EINT0是在 s3c2440a_intr.h中定义的,现在就越来越明朗了
//--而IRQ_SDI为什么没有如下的赋值呢?因为SD卡中断在注册表中设置了
//#define IRQ_SDI 21--在注册表也设置为21,这个原理和IRQ_EINT0等价了
UINT32 g_PwrButtonIrq = IRQ_EINT0;
UINT32 g_PwrButtonSysIntr = SYSINTR_UNDEFINED;
UINT32 g_RebootButtonIrq = IRQ_EINT2;
UINT32 g_RebootButtonSysIntr = SYSINTR_UNDEFINED;
到现在已经可以对5.0的BSP方法做个推断了:5.0BSP的所谓动态中断设置方法,就是在驱动中才初始化中断(在4.2下是静态中断,在OAL中初始化的)和注册表等结合起来。使用kernelIoControl这个函数来转换物理中断和逻辑中断(至于为什么要做个转换,我真的有点不了解,有点浪费时间,也许我等级太低了。)
但是在OAL又必须初始化什么呢?以前看了好多,一直带着4.2的影子去看程序——哎,老毛病。
现在再来看看OAL的OEMInit函数以及被他调用的函数。
//------------------------------------------------------------------------------
//
// Function: OEMInit
//
// This is Windows CE OAL initialization function. It is called from kernel
// after basic initialization is made.
//
void OEMInit()
{
OALMSG(OAL_FUNC, (L"+OEMInit/r/n"));
CEProcessorType=PROCESSOR_STRONGARM;
// Set memory size for DrWatson kernel support
dwNKDrWatsonSize = 128 * 1024;
// Initilize cache globals
OALCacheGlobalsInit();
OALLogSerial(
L"DCache: %d sets, %d ways, %d line size, %d size/r/n",
g_oalCacheInfo.L1DSetsPerWay, g_oalCacheInfo.L1DNumWays,
g_oalCacheInfo.L1DLineSize, g_oalCacheInfo.L1DSize
);
OALLogSerial(
L"ICache: %d sets, %d ways, %d line size, %d size/r/n",
g_oalCacheInfo.L1ISetsPerWay, g_oalCacheInfo.L1INumWays,
g_oalCacheInfo.L1ILineSize, g_oalCacheInfo.L1ISize
);
// Initialize interrupts
if (!OALIntrInit()) {
OALMSG(OAL_ERROR, (
L"ERROR: OEMInit: failed to initialize interrupts/r/n"
));
}
// Initialize system clock
OALTimerInit(1, 17, 0); //S3C2440A_PCLK/245/16/1000=16.992
ConfigureGPIO();
InitDisplay();
// Initialize the KITL connection if required
OALKitlStart();
OALMSG(OAL_FUNC, (L"-OEMInit/r/n"));
}
我们要找的是OALIntrInit这个函数
C:/WINCE500/PLATFORM/SMDK2440A/Src/Common/Intr_dvs/intr.c(74):// Function: OALIntrInit
//------------------------------------------------------------------------------
//
// Function: OALIntrInit
//
// This function initialize interrupt mapping, hardware and call platform
// specific initialization.
//
BOOL OALIntrInit()
{
BOOL rc = FALSE;
OALMSG( OAL_FUNC&&OAL_INTR, (L"+OALInterruptInit/r/n") );
// Initialize interrupt mapping
OALIntrMapInit();
// First get uncached virtual addresses
g_pIntrRegs = (S3C2440A_INTR_REG*)OALPAtoVA(
S3C2440A_BASE_REG_PA_INTR, FALSE
);
g_pPortRegs = (S3C2440A_IOPORT_REG*)OALPAtoVA(
S3C2440A_BASE_REG_PA_IOPORT, FALSE
);
#ifdef DVS_EN
g_pLCDRegs = (S3C2440A_LCD_REG*)OALPAtoVA(
S3C2440A_BASE_REG_PA_LCD, FALSE
);
#endif
// Mask and clear external interrupts
OUTREG32(&g_pPortRegs->EINTMASK, 0xFFFFFFFF);
OUTREG32(&g_pPortRegs->EINTPEND, 0xFFFFFFFF);
// Mask and clear internal interrupts
OUTREG32(&g_pIntrRegs->INTMSK, 0xFFFFFFFF);
OUTREG32(&g_pIntrRegs->SRCPND, 0xFFFFFFFF);
// S3C2440A developer notice (page 4) warns against writing a 1 to any
// 0 bit field in the INTPND register. Instead we'll write the INTPND
// value itself.
OUTREG32(&g_pIntrRegs->INTPND, INREG32(&g_pIntrRegs->INTPND));
// Unmask the system tick timer interrupt
//看来在OAL中只有定时器中断这个心脏没有停止
CLRREG32(&g_pIntrRegs->INTMSK, 1 << IRQ_TIMER4);
#ifdef OAL_BSP_CALLBACKS
// Give BSP change to initialize subordinate controller
// 在BSP中初始化中断
rc = BSPIntrInit();
#else
rc = TRUE;
#endif
OALMSG(OAL_INTR&&OAL_FUNC, (L"-OALInterruptInit(rc = %d)/r/n", rc));
return rc;
}
既然又出来个BSPIntrInit,那我就再往下查。——果然有新发现。
C:/WINCE500/PLATFORM/SMDK2440A/Src/Kernel/Oal/intr.c(24):BOOL BSPIntrInit()
//------------------------------------------------------------------------------
//
// Function: BSPIntrInit
//
BOOL BSPIntrInit()
{
S3C2440A_IOPORT_REG *pOalPortRegs;
ULONG value;
OALMSG(OAL_INTR&&OAL_FUNC, (L"+BSPIntrInit/r/n"));
// Then get virtual address for IO port
pOalPortRegs = OALPAtoVA(S3C2440A_BASE_REG_PA_IOPORT, FALSE);
// Set GPG1 as EINT9这个EINT9用来干什么呢?
value = INREG32(&pOalPortRegs->GPGCON);
OUTREG32(&pOalPortRegs->GPGCON, (value & ~(3 << 2))|(2 << 2));
// Disable pullup
value = INREG32(&pOalPortRegs->GPGUP);
OUTREG32(&pOalPortRegs->GPGUP, value | (1 << 1));
// High level interrupt
value = INREG32(&pOalPortRegs->EXTINT1);
OUTREG32(&pOalPortRegs->EXTINT1, (value & ~(0xf << 4))|(0x1 << 4));
// Add static mapping for Built-In OHCI
OALIntrStaticTranslate(SYSINTR_OHCI, IRQ_USBH);
// OALIntrStaticTranslate(SYSINTR_USBFN, IRQ_USBFN);
OALMSG(OAL_INTR&&OAL_FUNC, (L"-BSPIntrInit(rc = 1)/r/n"));
return TRUE;
}
看来现在终于可以对5.0中断做个总结了——5.0BSP中断方法
一、静态中断——使用BSPIntrInit 不是必须的,在OAL中初始化。
二、动态中断——使用kernelIoControl——在驱动中加载/删除。
经验教训:不要乱看代码,要抓住中断流程,抓住OEMInit这个函数是关键。
看来网上有些说法未必正确。——5.0BSP中断总结,完!
本文来自CSDN博客,转载请标明出处:http://blog.csdn.net/gooogleman/archive/2008/11/10/3266018.aspx