您的位置:首页 > 职场人生

通过powerButton驱动分析WINCE的中断实现

2008-06-09 17:23 417 查看
前两天有一个朋友问了我s3c2410WINCE挂起/唤醒的实现,这两天我研究了一下s3c2410的PowerButton驱动,对WINCE的中断流程又有了进一步的了解,下面我就写一下我的心得和大家交流一下。首先和PowerButton驱动有关的文件为:1)$(_WINCEROOT)\PLATFORM\smdk2410\DRIVERS\PWRBTN文件夹下面的三个文件pwrbtn2410.c、pwrbtn2410.h和pwrbtn2410.def,这个PowerButton驱动是通过流驱动实现的,实现的过程很简单,下面会详细说明。2)$(_WINCEROOT)\PLATFORM\smdk2410\INC\oalintr.h,定义非内核模式的中断号( non-kernelinterrupt identifiers )3)$(_WINCEROOT)\PLATFORM\smdk2410\KERNEL\HAL\cfw.c,这里面主要实现了OEMInitInterrupts、OEMInterruptEnable、OEMInterruptDisable、OEMInterruptDone这几个重要的中断函数。4)$(_WINCEROOT)\PLATFORM\smdk2410\KERNEL\HAL\ARM\armint.c,这里主要实现了OEMInterruptHandler这个中断处理函数。下面我简单分析一下中断处理过程。a) 首先你为自己的硬件(键盘,按键等需要使用的中断)定义一个中断名称,比如这个电源按键就起了一个中断名称SYSINTR_POWER,然后在oalintr.h里面把它定义成SYSINTR_FIRMWARE+n的形式比如: #defineSYSINTR_POWER (SYSINTR_FIRMWARE+13)n必须小于SYSINTR_MAXUMUM or SYSINTR_FIRMWARE+23b)在cfw.c的OEMInitInterrupts中进行一些中断初始化工作,主要就是屏蔽所有中断,清除中断挂起等工作,代码我就不详细说明了,比较简单。在OEMInterruptEnable(这个函数会被InterruptInitialize函数调用)函数中主要进行中断开启工作,当驱动使用InterruptInitialize的时候(比如InterruptInitialize(SYSINTR_POWER,gPwrButtonIntrEvent, 0,0))就会把SYSINTR_POWER中断号传入,然后开启EIN0这个中断,并且把SYSINTR_POWER中断和事件gPwrButtonIntrEvent连接起来,代码如下:INTERRUPTS_OFF(); //关闭所有中断 switch (idInt) {......case SYSINTR_POWER:
s2410INT->rSRCPND = BIT_EINT0;
// S3C2410X Developer Notice(page 4) warns against writing a 1 to a 0 bit in the INTPNDregister.
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0;
s2410INT->rINTMSK &=~BIT_EINT0;
s2410INT->rSRCPND = BIT_EINT2;
// S3C2410X Developer Notice(page 4) warns against writing a 1 to a 0 bit in the INTPNDregister.
if (s2410INT->rINTPND &BIT_EINT2) s2410INT->rINTPND = BIT_EINT2;
s2410INT->rINTMSK &=~BIT_EINT2;
break;.....}INTERRUPTS_ON();//开启所有中断 这个文件里面还实现了OEMInterruptDisable函数用来禁止中断,与PowerButton相关的函数如下:INTERRUPTS_OFF();switch (idInt)
{.... case SYSINTR_POWER:
s2410INT->rINTMSK |=BIT_EINT0;
s2410INT->rINTMSK |=BIT_EINT2;
break;
..... } INTERRUPTS_ON();在这个文件中,还实现了OEMInterruptDone函数,做一些中断处理结束后的事情,当驱动调用InterruptDone时会把中断号传到这个函数来使用这个函数,与PowerButton相关的函数如下: INTERRUPTS_OFF();
switch (idInt)
{... case SYSINTR_POWER:
s2410INT->rSRCPND =BIT_EINT0;
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0;
s2410INT->rINTMSK &=~BIT_EINT0;
s2410INT->rSRCPND =BIT_EINT2;
if (s2410INT->rINTPND &BIT_EINT2) s2410INT->rINTPND = BIT_EINT2;
s2410INT->rINTMSK &=~BIT_EINT2;
break; }
INTERRUPTS_ON();以上几个中断函数都相当重要,而且功能我也讲得很清楚了,大家应该理解了吧^_^。c)在armint.c中主要实现了OEMInterruptHandler这个中断处理函数,当有硬件中断来的时候会进入这个处理函数,我们看看与PowerButton有关的代码: else if (IntPendVal ==INTSRC_EINT0) { // POWER BUTTON中断
s2410INT->rINTMSK |=BIT_EINT0;
s2410INT->rSRCPND = BIT_EINT0; /* InterruptClear */
if (s2410INT->rINTPND &BIT_EINT0) s2410INT->rINTPND = BIT_EINT0; return(SYSINTR_POWER); //返回一个中断号通知系统发生了什么中断,系统通过这个中断产生一个事件//给IST使用。在这里,我们把PowerButton和EINT0联系起来了,并且如果EINT0来了中断,就会返回系统一个中断号SYSINTR_POWER。d)我们下面再来看看PowerButton驱动的实现。在pbut2410.c文件里,我们首先看看动态链接库的init实现:PUBLIC DWORD
DSK_Init(DWORD dwContext)
{… do
{
gPwrButtonIntrThread =CreateThread(0, 0, (LPTHREAD_START_ROUTINE) PBT_IntrThread, 0, 0,&IDThread);//创建了一个PBT_IntrThread线程,这个就是PowerButton的IST if (gPwrButtonIntrThread ==0)
{
break;
}
} while (0);…}下面我们看看PBT_IntrThread的实现:DWORD
PBT_IntrThread(PVOID pArg)
{ PBT_InitializeAddresses();//得到EINI0口的虚拟地址 PBT_EnableInterrupt(); //使能EINI0口中断 gPwrButtonIntrEvent = CreateEvent(NULL, FALSE,FALSE, NULL);//创建一个事件//PowerButton事件 if (!(InterruptInitialize(SYSINTR_POWER,gPwrButtonIntrEvent, 0, 0))) //通知系统使能SYSINTR_POWER这个中断,并且当这个中断产生时产生一个gPwrButtonIntrEvent事件,//第一个参数为与这个IST连接的中断ID,第二个参数为中断产生是产生的事件
{
RETAILMSG(1, (TEXT(":::SYSINTR_POWER Init Fail\r\n")));
} while (1)
{
WaitForSingleObject(gPwrButtonIntrEvent,INFINITE);//等待中断发生
if (gOffFlag == FALSE)
{
if(PBT_IsPushed()) /*To FilterNoise *///判断是否是噪声
{
Sleep(200); if(PBT_IsPushed())
{
}
else
{//如果不是噪声则:
#if (WINCEOSVER >= 400)
if(gpfnSetSystemPowerState != NULL)
{
gpfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND,POWER_FORCE);
}
else
{
PowerOffSystem();//调用PowerOffSystem函数,在这//个函数里面又会调用OEMPowerOff函数,这个函数在power.c里
}
#else
PowerOffSystem();
#endif
DriverSleep(0, FALSE);
}
} InterruptDone(SYSINTR_POWER);//通知系统调用OEMInterruptDone
}
}
}在看看一些函数PRIVATE VOIDPBT_EnableInterrupt(VOID){ v_pIOPregs->rGPFCON &= ~(0x3 <<0); /* 设置GPF0) 为EINT0 */ v_pIOPregs->rGPFCON |= (0x2<< 0); v_pIOPregs->rEXTINT0 &= ~(0x7 <<0); /*配置EINT0为下降沿模式 */ v_pIOPregs->rEXTINT0 |= (0x2 << 0);} PRIVATE BOOLPBT_IsPushed(VOID){//判断GPF0是否被按下 return ((v_pIOPregs->rGPFDAT & (1 << 0)) ? FALSE :TRUE);} PRIVATE BOOLPBT_InitializeAddresses(VOID){//分配EINT0的虚拟地址供驱动使用 BOOL RetValue =TRUE; /* IO Register Allocation */ v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg),MEM_RESERVE, PAGE_NOACCESS); if (v_pIOPregs == NULL) { ERRORMSG(1,(TEXT("For IOPregs : VirtualAlloc failed!\r\n"))); RetValue = FALSE; } else { if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(IOP_BASE),sizeof(IOPreg), PAGE_READWRITE | PAGE_NOCACHE)) { ERRORMSG(1,(TEXT("For IOPregs: VirtualCopy failed!\r\n"))); RetValue = FALSE; } } if (!RetValue) {// RETAILMSG (1, (TEXT("::: PBT_InitializeAddresses - Fail!!\r\n"))); if (v_pIOPregs) { VirtualFree((PVOID) v_pIOPregs, 0, MEM_RELEASE); } v_pIOPregs = NULL; } else RETAILMSG (1, (TEXT("::: PBT_InitializeAddresses -Success\r\n") )); return(RetValue);} 总结:从上面PowerButton这个驱动我们就能把WINCE的中断处理过程了解清楚,基本的过程是首先在oalinitr.h中把中断IDdefine成SYSINTR_FIRMWARE+N的形式,然后OEMInitInterrupts(cfw.c) -> OEMInterruptEnable(cfw.c) ->硬件中断到达 -> OEMInterruptHandler(armint.c) ->自己写的中断服务线程(IST)-> OEMInterruptDone(cfw.c)其中IST的流程一般为:创建一个事件CreateEvent -> InterruptInitialize(SYSINTR_XXXX,XXXXXEvent, 0, 0)把中断ID和IST联系起来,并且把中断ID和事件XXXXXEvent联系起来 ->WaitForSingleObject(XXXXXEvent,INFINITE)等待这个事件的产生,由于事件和中断联系起来了,实际就是等待中断的产生-> 实际的中断处理过程 -> InterruptDone(SYSINTR_ XXXX)通过这个函数调用OEMInterruptDone
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息