WinCE6.0 DEVICEEMULATOR BSP在GEC2410开发板上的移植(3)-PwrButton驱动移植及分析

PwrButton驱动实现了按键关机(PowerOff)和重启(Reset)的功能.我们这里定义开发板上的K1为PowerOff,K3为Reset,对应与CPU的EINT0和EINT2中断.
DEVICEEMULATOR BSP中已经基本实现了该驱动,在GEC2410.bat中使能PwrButton,即设置BSP_NOPWRBTN不为1:
set BSP_NOPWRBTN=
编译后通过KITL可以看到pwrbtn2410.dll已经被加载了,但是按任何按钮都没有反应.这是由于PwrButton驱动中的IO设置与我们实际板子上还不完全匹配.
在GEC2410开发板上,按键的原理图是:
WinCE6.0 DEVICEEMULATOR BSP在GEC2410开发板上的移植(3)-PwrButton驱动移植及分析_第1张图片
在PwrButton驱动中,使用EINT0和EINT2来检测按键的输入,没有按键输入时,EINT0,EINT2被上拉为1,当K1按下时要使EINT0产生下降沿中断,KSCAN0必须为输出0,为了使K2,K9,K10按下时不产生中断,KSCAN1-3需要输出1.这样只有当K1按下时才产生EINT0的下降沿中断.
同理对K3.
我们需要的工作就是配置相应的GPIO,使KSCAN0输出0,KSCAN1-3输出1,EINT0和EINT2设置为外部中断,下降沿触发.然后在驱动中设置该中断,当中断发生时读取EINT0或EINT2对应引脚的值就可以判断K1或者K3是否按下了.
如果要读取所有键盘的值,只需要通过KSCAN0-KSCAN3分别置0扫描并读取相应的EINT管脚就能确定是哪个按键按下了.
接下来我们来看看该驱动详细的代码以及需要添加或修改的地方.
1.流驱动接口
PwrButton驱动也是个标准的流接口驱动,但是只实现了PBT_Init一个函数,其他的如PBT_Open,PBT_Read,PBT_Write都没有实现,仅仅返回0.
PBT_Init 主要工作是:
(1)从coredll.dll获得系统函数SetSystemPowerState,
(2)调用InitializeAddresses获取寄存器地址
(3)调用SetScanOutput()来设置KSCAN0-3的输出值.
(4)创建检测PowerButton(K1)和ResetButton(K3)的线程:PowerButtonIntrThread和ResetButtonIntrThread.
其中SetScanOutput()是我添加的函数,用来初始化KSCAN0-3的输出(KSCAN0为0,其余为1)
代码如下:
DWORD PBT_Init(DWORD dwContext) { DWORD IDPowerButtonThread; DWORD IDResetButtonThread; HMODULE hmCore; // // Obtain a pointer to the power manager function "SetSystemPowerState" // from the core library so we can call into it. pfnSetSystemPowerState = NULL; hmCore = (HMODULE) LoadLibrary(_T("coredll.dll")); if(hmCore != NULL) { pfnSetSystemPowerState = (PFN_SetSystemPowerState) GetProcAddress(hmCore, _T("SetSystemPowerState")); if(pfnSetSystemPowerState == NULL) { FreeLibrary(hmCore); } } // Initialize addresses now as opposed to when interrupts are handled so there are no race conditions InitializeAddresses(); SetScanOutput(); // Create a thread to handle the power button event, and one to handle the reset button event. ResetButtonIntrThreadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) ResetButtonIntrThread, 0, 0, &IDResetButtonThread); if (ResetButtonIntrThreadHandle == 0) { RETAILMSG(1, (TEXT("PBT: CreateThread() Fail/r/n"))); } PowerButtonIntrThreadHandle = CreateThread(0, 0, (LPTHREAD_START_ROUTINE) PowerButtonIntrThread, 0, 0, &IDPowerButtonThread); if (PowerButtonIntrThreadHandle == 0) { RETAILMSG(1, (TEXT("PBT: CreateThread() Fail/r/n"))); } return (dwContext); }
InitializeAddresses:
InitializeAddresses通过调用VirtualAlloc和VirtualCopy获得了GPIO寄存器和中断寄存器的虚拟地址,并转换为S3C2410X_IOPORT_REG和S3C2410X_INTR_REG结构的指针。
 static BOOL InitializeAddresses(VOID) { BOOL RetValue = FALSE; // IO Register Allocation v_pIOPregs = (volatile S3C2410X_IOPORT_REG *)VirtualAlloc(0, sizeof *v_pIOPregs, MEM_RESERVE, PAGE_NOACCESS); if (v_pIOPregs == NULL) { ERRORMSG(1,(TEXT("PBT: VirtualAlloc failed!/r/n"))); } else { if (!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(S3C2410X_BASE_REG_PA_IOPORT >> 8), sizeof *v_pIOPregs, PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { ERRORMSG(1,(TEXT("PBT: VirtualCopy failed!/r/n"))); VirtualFree((PVOID)v_pIOPregs, 0, MEM_RELEASE); v_pIOPregs = NULL; } } s2410INT = (volatile S3C2410X_INTR_REG *)VirtualAlloc(0, sizeof *s2410INT, MEM_RESERVE, PAGE_NOACCESS); if (s2410INT == NULL) { ERRORMSG(1,(TEXT("PBT: VirtualAlloc failed!/r/n"))); } else { if (!VirtualCopy((PVOID)s2410INT, (PVOID)(S3C2410X_BASE_REG_PA_INTR >> 8), sizeof *s2410INT, PAGE_PHYSICAL | PAGE_READWRITE | PAGE_NOCACHE)) { ERRORMSG(1,(TEXT("PBT: VirtualCopy failed!/r/n"))); VirtualFree((PVOID)s2410INT, 0, MEM_RELEASE); s2410INT = NULL; } } if(v_pIOPregs && s2410INT) { RetValue = TRUE; } return (RetValue); }
SetScanOutput:
设置KSCAN0为0,KSCAN1-3为1
static VOID SetScanOutput(VOID) { //only enable K1 and K3 key input detect v_pIOPregs->GPGDAT |= (1<<6)|(1<<2); //GPG6,2((KSCAN1,KSCAN3) output 1 v_pIOPregs->GPEDAT |= (1<<13); //GEE13(KSCAN2) output 1 v_pIOPregs->GPEDAT &= ~(1<<11); //GPE11(KSCAN0) output 0 }
2.PowerButtonIntrThread和ResetButtonIntrThread
PowerButtonIntrThread:
(1).调用EnablePowerButtonInterrupt()来初始化IO和使能中断EINT0.
(2).创建中断事件PwrButtonIntrEvent,调用KernelIoControl向系统申请IRQ_EINT0对应的逻辑中断号PwrButtonSysIntr.
(3).调用InterruptInitialize将PwrButtonSysIntr关联PwrButtonIntrEvent事件并初始化中断.
(4).等待中断事件发生
(5).中断发生后,调用PowerButtonIsPushed来检测按钮是否按下,延时200ms并再次判断是否按键释放,如果释放了确定按键有效.
(6).pfnSetSystemPowerState存在时,调用其来设置系统状态为POWER_STATE_SUSPEND
pfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
否则调用PowerOffSystem()关闭系统.
(7).最后InterruptDone(PwrButtonSysIntr);来通知系统中断完成.
以下是PowerButtonIntrThread代码:
static DWORD PowerButtonIntrThread(PVOID pArg) { RETAILMSG(1, (TEXT("PowerButtonIntrThread./r/n"))); EnablePowerButtonInterrupt(); PwrButtonIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // // Request a SYSINTR value from the OAL. // if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &PwrButtonIrq, sizeof PwrButtonIrq, &PwrButtonSysIntr, sizeof PwrButtonSysIntr, NULL)) { RETAILMSG(1, (TEXT("PBT: Error! Failed to request sysintr value for power button interrupt./r/n"))); return(0); } if (!(InterruptInitialize(PwrButtonSysIntr, PwrButtonIntrEvent, 0, 0))) { RETAILMSG(1, (TEXT("ERROR: PwrButton: Interrupt initialize failed./r/n"))); } // Handle power button presses. for (;;) { WaitForSingleObject(PwrButtonIntrEvent, INFINITE); if (PowerButtonIsPushed()) // Guard against noise triggering an interrupt. { Sleep(200); // Check again in 200 Ms. to fend off a continuous press. if (!PowerButtonIsPushed()) // Must be held+released in less than .2 seconds. { // // Soft reset and standard suspend-resume both start with suspend for now. // Call whichever shutdown API is available. // if(pfnSetSystemPowerState != NULL) { RETAILMSG(1,(TEXT("PBT: Signalling power manager to suspend.../r/n"))); pfnSetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE); } else { RETAILMSG(1,(TEXT("PBT: Suspending by calling PowerOffSystem.../r/n"))); PowerOffSystem(); } // // Acquiesce to other threads since our work is complete as of // the call to PowerOffSystem, or the signalling of the power // manager. // Sleep(0); } else RETAILMSG(1,(TEXT("PBT: Button held too long (ignored)/r/n"))); } else RETAILMSG(1,(TEXT("PBT: Feeble button press or noise triggered it (ignored)/r/n"))); InterruptDone(PwrButtonSysIntr); } }
ResetButtonIntrThread:
(1).调用EnableResetButtonInterrupt()来初始化IO和使能中断EINT2.
(2).创建中断事件ResetButtonIntrEvent,调用KernelIoControl向系统申请IRQ_EINT2对应的逻辑中断号ResetButtonSysIntr.
(3).调用InterruptInitialize将ResetButtonSysIntr关联ResetButtonIntrEvent事件并初始化中断.
(4).等待中断事件发生
(5).中断发生后,首先屏蔽EINT11中断(原来的EINT11是连接存储设备的,而我们的板子连接的是键盘,这句代码可以不用)
(6)调用PowerButtonIsPushed来检测按钮是否按下,延时200ms并再次判断是否按键释放,如果释放了确定按键有效.
(7).pfnSetSystemPowerState存在时,调用其来设置系统状态为POWER_STATE_RESET
pfnSetSystemPowerState(NULL, POWER_STATE_RESET, POWER_FORCE);
否则调用KernelIoControl(IOCTL_HAL_REBOOT,NULL,0,NULL,0,NULL)来重启系统.
(8).最后InterruptDone(ResetButtonSysIntr);来通知系统中断完成.
以下是ResetButtonIntrThread代码:
static DWORD ResetButtonIntrThread(PVOID pArg) { RETAILMSG(1, (TEXT("ResetButtonIntrThread./r/n"))); EnableResetButtonInterrupt(); ResetButtonIntrEvent = CreateEvent(NULL, FALSE, FALSE, NULL); // // Request a SYSINTR value from the OAL. // if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &ResetButtonIrq, sizeof ResetButtonIrq, &ResetButtonSysIntr, sizeof ResetButtonSysIntr, NULL)) { RETAILMSG(1, (TEXT("PBT: Error! Failed to request sysintr value for reset button interrupt./r/n"))); return(0); } if (!(InterruptInitialize(ResetButtonSysIntr, ResetButtonIntrEvent, 0, 0))) { RETAILMSG(1, (TEXT("ERROR: ResetButton: Interrupt initialize failed./r/n"))); } // Handle power button presses. for (;;) { WaitForSingleObject(ResetButtonIntrEvent, INFINITE); //Mask the storage device interrupt EINT11 so we don't service it before reboot is finished s2410INT->INTMSK = (s2410INT->INTMSK | (0x1 << 0x5)); if (ResetButtonIsPushed()) // Guard against noise triggering an interrupt. { // // Soft reset and standard suspend-resume both start with suspend for now. // Call whichever shutdown API is available. // if(pfnSetSystemPowerState != NULL) { RETAILMSG(1,(TEXT("PBT: Signalling power manager to reset.../r/n"))); pfnSetSystemPowerState(NULL, POWER_STATE_RESET, POWER_FORCE); } else { RETAILMSG(1,(TEXT("PBT: Resetting by calling KernelIoControl(IOCTL_HAL_REBOOT).../r/n"))); KernelIoControl(IOCTL_HAL_REBOOT,NULL,0,NULL,0,NULL); } // // Acquiesce to other threads since our work is complete as of // the call to PowerOffSystem, or the signalling of the power // manager. // Sleep(0); } else RETAILMSG(1,(TEXT("PBT: Feeble button press or noise triggered it (ignored)/r/n"))); InterruptDone(ResetButtonSysIntr); } }
3.EnablePowerButtonInterrupt,EnableResetButtonInterrupt,PowerButtonIsPushed,ResetButtonIsPushed
EnablePowerButtonInterrupt和EnableResetButtonInterrupt初始化EINT0和EINT2的功能管脚和中断设置(下降沿触发)
static VOID EnablePowerButtonInterrupt(VOID) { v_pIOPregs->GPFCON &= ~(0x3 << 0); // Set EINT0(GPF0) as EINT0 v_pIOPregs->GPFCON |= (0x2 << 0); v_pIOPregs->EXTINT0 &= ~(0x7 << 0); // Configure EINT0 as Falling Edge Mode v_pIOPregs->EXTINT0 |= (0x2 << 0); } static VOID EnableResetButtonInterrupt(VOID) { v_pIOPregs->GPFCON &= ~(0x3 << 4); // Set EINT2(GPF2) as EINT2 v_pIOPregs->GPFCON |= (0x2 << 4); v_pIOPregs->EXTINT0 &= ~(0x7 << 8); // Configure EINT2 as Falling Edge Mode v_pIOPregs->EXTINT0 |= (0x2 << 8); }
PowerButtonIsPushed和ResetButtonIsPushed读取GPF0和GPF2的状态来确定按钮是否按下.
static BOOL PowerButtonIsPushed(VOID) { // // Switches are pulled up when open, and driven low when closed. // Return true if switch 1 (EINT0) is closed. // RETAILMSG(1, (TEXT("PowerButtonIsPushed./r/n"))); return ((v_pIOPregs->GPFDAT & (1 << 0)) ? FALSE : TRUE); } static BOOL ResetButtonIsPushed(VOID) { // // Switches are pulled up when open, and driven low when closed. // Return true if switch 1 (EINT2) is closed. // RETAILMSG(1, (TEXT("ResetButtonIsPushed./r/n"))); return ((v_pIOPregs->GPFDAT & (1 << 2)) ? FALSE : TRUE); }
4.增加OAL中的GPIO初始化
KSCAN0-3的GPIO寄存器配置在OAL中的OEMInit()函数中完成,调用以下的InitGPIO来进行初始化:
具体的引脚及其功能见如下代码及注释:
void InitGPIO() { S3C2410X_IOPORT_REG *pOalPortRegs; RETAILMSG(1, (L"+GPIO_Init.../r/n")); pOalPortRegs = OALPAtoVA(S3C2410X_BASE_REG_PA_IOPORT, FALSE); //KEY Board GPIO settings pOalPortRegs->GPGCON = pOalPortRegs->GPGCON & (~((3<<12)|(3<<4))) | ((1<<12)|(1<<4)) ; //GPG6(KSCAN1) GPG2(KSCAN3), set output //pOalPortRegs->GPGDAT &= (~((1<<6)|(1<<2))); //GPG6,2((KSCAN1,KSCAN3) output 0 pOalPortRegs->GPECON = pOalPortRegs->GPECON & (~((3<<26)|(3<<22))) | ((1<<26)|(1<<22)); //GPE13(KSCAN2),GPE11(KSCAN0) set output //pOalPortRegs->GPGDAT &= (~((1<<13)|(1<<11))); //GPE13(KSCAN2) GPE11(KSCAN0) output 0 pOalPortRegs->GPGCON = pOalPortRegs->GPGCON & (~((3<<22)|(3<<6))) | ((2<<22)|(2<<6)) ; //GPG11(EINT19),GPG3(EINT11) set EINT pOalPortRegs->GPFCON = pOalPortRegs->GPFCON & (~((3<<4)|(3<<0))) | ((2<<4)|(2<<0)) ; //GPF2(EINT2) GPF0(EINT0), set EINT //pOalPortRegs->GPFUP = 0xf0; // GPF4-7:disabled pull up; GPF0-4: enable pull up }

你可能感兴趣的:(manager,null,button,WinCE,output,Allocation)