您的位置:首页 > 其它

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

2011-01-19 11:56 423 查看
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开发板上,按键的原理图是:



在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
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: