Hi, can anybody can help on how to add GPIO as keypad for WinCE6 based on MX51EVK?
Following we have added two GPIO (GPIO_PORT3_2 and GPIO_PORT4_9), into power button program, but system can not run it normally, following is our program:
//------------------------------------------------------------------------------
//
// Copyright (C) 2008-2009, Freescale Semiconductor, Inc. All Rights Reserved.
// THIS SOURCE CODE, AND ITS USE AND DISTRIBUTION, IS SUBJECT TO THE TERMS
// AND CONDITIONS OF THE APPLICABLE LICENSE AGREEMENT
//
//------------------------------------------------------------------------------
//
// File: pwrbutton.c
//
// This file contains driver support for the power button.
//
//-----------------------------------------------------------------------------
#pragma warning(push)
#pragma warning(disable: 4115 4201 4204 4214)
#include <windows.h>
#include <ceddk.h>
#pragma warning(pop)
#include "bsp.h"
#include "pmic.h"
//-----------------------------------------------------------------------------
// External Functions
//-----------------------------------------------------------------------------
// External Variables
//-----------------------------------------------------------------------------
// Defines
// EVK power button is SW1. SW1 drives SYS_ON_OFF_REQ signal tied to EIM_A27.
// EIM_A27 can be muxed as GPIO2_21. Configure definitions to use GPIO2_21 for
// power button events.
#define BSP_PWRBTN_IOMUX_PIN DDK_IOMUX_PIN_EIM_A27
#define BSP_PWRBTN_IOMUX_PAD DDK_IOMUX_PAD_EIM_A27
#define BSP_PWRBTN_GPIO_PORT DDK_GPIO_PORT2
#define BSP_PWRBTN_GPIO_PIN 21
#define BSP_PWRBTN_GPIO_IRQ IRQ_GPIO2_PIN21
//GPIO3_2
#define BSP_BTN1_IOMUX_PIN DDK_IOMUX_PIN_DI1_PIN13
#define BSP_BTN1_IOMUX_PAD DDK_IOMUX_PAD_DI1_PIN13
#define BSP_BTN1_GPIO_PORT DDK_GPIO_PORT3
#define BSP_BTN1_GPIO_PIN 2
#define BSP_BTN1_GPIO_IRQ IRQ_GPIO3_PIN2
//GPIO4_9
#define BSP_BTN2_IOMUX_PIN DDK_IOMUX_PIN_CSI2_D12
#define BSP_BTN2_IOMUX_PAD DDK_IOMUX_PAD_CSI2_D12
#define BSP_BTN2_GPIO_PORT DDK_GPIO_PORT4
#define BSP_BTN2_GPIO_PIN 9
#define BSP_BTN2_GPIO_IRQ IRQ_GPIO4_PIN9
// BSP_PWRBTN_DEBOUNCE_SAMPLE_MSEC specifies the time between
// sampling of power button value.
#define BSP_PWRBTN_DEBOUNCE_SAMPLE_MSEC 10 // 10 msec
// BSP_PWRBTN_DEBOUNCE_SUSPEND_MSEC specifies the minimum
// assertion time for detecting that the user wants to suspend the system.
#define BSP_PWRBTN_DEBOUNCE_SUSPEND_MSEC 100 // 100 msec
// BSP_PWRBTN_DEBOUNCE_OFF_MSEC specifies the minimum
// assertion time for detecting that the user wants to power off the system.
#define BSP_PWRBTN_DEBOUNCE_OFF_MSEC 2000 // 2 sec
// BSP_PWRBTN_DEBOUNCE_IGNORE_MSEC specifies the minimum
// time for ignoring the power button after processing the previous
// button press.
#define BSP_PWRBTN_DEBOUNCE_IGNORE_MSEC 500 // 500 msec
#define BSP_PWRBTN_THREAD_PRIORITY 152
#define BSP_Btn1BTN_THREAD_PRIORITY 152
#define BSP_Btn2BTN_THREAD_PRIORITY 152
//-----------------------------------------------------------------------------
// Types
//-----------------------------------------------------------------------------
// Global Variables
//-----------------------------------------------------------------------------
// Local Variables
static HANDLE g_hPwrBtnThread;
static HANDLE g_hPwrBtnEvent;
static DWORD g_dwPwrBtnSysIntr = (DWORD)SYSINTR_UNDEFINED;
static HANDLE g_hBtn1Thread;
static HANDLE g_hBtn1Event;
static DWORD g_dwBtn1SysIntr = (DWORD)SYSINTR_UNDEFINED;
static HANDLE g_hBtn2Thread;
static HANDLE g_hBtn2Event;
static DWORD g_dwBtn2SysIntr = (DWORD)SYSINTR_UNDEFINED;
//-----------------------------------------------------------------------------
// Local Functions
static DWORD WINAPI PwrBtnThread (LPVOID lpParam);
static DWORD WINAPI Btn1Thread (LPVOID lpParam);
static DWORD WINAPI Btn2Thread (LPVOID lpParam);
//-----------------------------------------------------------------------------
//
// Function: DllEntry
//
// This function is an optional method of entry into a DLL. If the function
// is used, it is called by the system when processes and threads are
// initialized and terminated, or on calls to the LoadLibrary and
// FreeLibrary functions.
//
// Parameters:
// hinstDLL
// [in] Handle to the DLL. The value is the base address of the DLL.
//
// dwReason
// [in] Specifies a flag indicating why the DLL entry-point function
// is being called.
//
// lpvReserved
// [in] Specifies further aspects of DLL initialization and cleanup.
// If dwReason is DLL_PROCESS_ATTACH, lpvReserved is NULL for
// dynamic loads and nonnull for static loads. If dwReason is
// DLL_PROCESS_DETACH, lpvReserved is NULL if DllMain is called
// by using FreeLibrary and nonnull if DllMain is called during
// process termination.
//
// Returns:
// When the system calls the DllMain function with the
// DLL_PROCESS_ATTACH value, the function returns TRUE if it
// succeeds or FALSE if initialization fails.
//
// If the return value is FALSE when DllMain is called because the
// process uses the LoadLibrary function, LoadLibrary returns NULL.
//
// If the return value is FALSE when DllMain is called during
// process initialization, the process terminates with an error.
//
// When the system calls the DllMain function with a value other
// than DLL_PROCESS_ATTACH, the return value is ignored.
//
//-----------------------------------------------------------------------------
BOOL WINAPI DllEntry(HINSTANCE hDllHandle, DWORD dwReason,
LPVOID lpreserved)
{
// Remove-W4: Warning C4100 workaround
UNREFERENCED_PARAMETER(lpreserved);
switch (dwReason)
{
case DLL_PROCESS_ATTACH:
DisableThreadLibraryCalls((HMODULE) hDllHandle);
break;
case DLL_PROCESS_DETACH:
break;
default:
break;
}
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: Init
//
// This function initializes the power button driver. Called by the Device Manager to
// initialize a device.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE if successful, otherwise returns FALSE.
//
//-----------------------------------------------------------------------------
BOOL Init(void)
{
BOOL rc = FALSE;
DWORD dwIrq;
// Configure GPIO signal for power button events
DDKIomuxSetPinMux(BSP_PWRBTN_IOMUX_PIN, DDK_IOMUX_PIN_MUXMODE_ALT1, DDK_IOMUX_PIN_SION_REGULAR);
DDKIomuxSetPadConfig(BSP_PWRBTN_IOMUX_PAD, DDK_IOMUX_PAD_SLEW_NULL, DDK_IOMUX_PAD_DRIVE_NULL, DDK_IOMUX_PAD_OPENDRAIN_NULL, DDK_IOMUX_PAD_PULL_NONE, DDK_IOMUX_PAD_HYSTERESIS_ENABLE, DDK_IOMUX_PAD_INMODE_NULL, DDK_IOMUX_PAD_OUTVOLT_NULL);
DDKGpioSetConfig(BSP_PWRBTN_GPIO_PORT, BSP_PWRBTN_GPIO_PIN, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_HIGH_LEV);
DDKGpioClearIntrPin(BSP_PWRBTN_GPIO_PORT, BSP_PWRBTN_GPIO_PIN);
///gpio3_2
DDKIomuxSetPinMux(BSP_BTN1_IOMUX_PIN, DDK_IOMUX_PIN_MUXMODE_ALT1, DDK_IOMUX_PIN_SION_REGULAR);
DDKIomuxSetPadConfig(BSP_BTN1_IOMUX_PAD, DDK_IOMUX_PAD_SLEW_NULL, DDK_IOMUX_PAD_DRIVE_NULL, DDK_IOMUX_PAD_OPENDRAIN_NULL, DDK_IOMUX_PAD_PULL_NONE, DDK_IOMUX_PAD_HYSTERESIS_ENABLE, DDK_IOMUX_PAD_INMODE_NULL, DDK_IOMUX_PAD_OUTVOLT_NULL);
DDKGpioSetConfig(BSP_BTN1_GPIO_PORT, BSP_BTN1_GPIO_PIN, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_FALL_EDGE);
DDKGpioClearIntrPin(BSP_BTN1_GPIO_PORT, BSP_BTN1_GPIO_PIN);
//gpio4_9
DDKIomuxSetPinMux(BSP_BTN2_IOMUX_PIN, DDK_IOMUX_PIN_MUXMODE_ALT1, DDK_IOMUX_PIN_SION_REGULAR);
DDKIomuxSetPadConfig(BSP_BTN2_IOMUX_PAD, DDK_IOMUX_PAD_SLEW_NULL, DDK_IOMUX_PAD_DRIVE_NULL, DDK_IOMUX_PAD_OPENDRAIN_NULL, DDK_IOMUX_PAD_PULL_NONE, DDK_IOMUX_PAD_HYSTERESIS_ENABLE, DDK_IOMUX_PAD_INMODE_NULL, DDK_IOMUX_PAD_OUTVOLT_NULL);
DDKGpioSetConfig(BSP_BTN2_GPIO_PORT, BSP_BTN2_GPIO_PIN, DDK_GPIO_DIR_IN, DDK_GPIO_INTR_FALL_EDGE);
DDKGpioClearIntrPin(BSP_BTN2_GPIO_PORT, BSP_BTN2_GPIO_PIN);
// Create event for IST signaling
g_hPwrBtnEvent = CreateEvent(NULL, FALSE, FALSE, NULL);
if(g_hPwrBtnEvent == NULL)
{
ERRORMSG(TRUE, (TEXT("%s(): failed to create IST event\r\n"), __WFUNCTION__));
goto cleanUp;
}
g_hBtn1Event = CreateEvent(NULL, FALSE, FALSE, NULL);
if(g_hBtn1Event == NULL)
{
ERRORMSG(TRUE, (TEXT("%s(): failed to create IST event\r\n"), __WFUNCTION__));
goto cleanUp;
}
g_hBtn2Event = CreateEvent(NULL, FALSE, FALSE, NULL);
if(g_hBtn2Event == NULL)
{
ERRORMSG(TRUE, (TEXT("%s(): failed to create IST event\r\n"), __WFUNCTION__));
goto cleanUp;
}
// Register the GPIO IRQ
dwIrq = BSP_PWRBTN_GPIO_IRQ;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(dwIrq), &g_dwPwrBtnSysIntr, sizeof(g_dwPwrBtnSysIntr), NULL))
{
ERRORMSG(TRUE, (TEXT("%s(): failed to map irq into sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
if (!InterruptInitialize(g_dwPwrBtnSysIntr, g_hPwrBtnEvent, NULL, 0)) {
ERRORMSG(TRUE, (TEXT("%s(): failed to register sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
// Configure power button as wake source
if (!KernelIoControl(IOCTL_HAL_ENABLE_WAKE, &g_dwPwrBtnSysIntr, sizeof(g_dwPwrBtnSysIntr), NULL, 0, NULL))
{
ERRORMSG(TRUE, (TEXT("%s(): failed to register as wake source\r\n"), __WFUNCTION__));
goto cleanUp;
}
//gpio3_2
dwIrq = BSP_BTN1_GPIO_IRQ;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(dwIrq), &g_dwBtn1SysIntr, sizeof(g_dwBtn1SysIntr), NULL))
{
ERRORMSG(TRUE, (TEXT("%s(): failed to map irq into sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
if (!InterruptInitialize(g_dwBtn1SysIntr, g_hBtn1Event, NULL, 0)) {
ERRORMSG(TRUE, (TEXT("%s(): failed to register sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
//gpio4_9
dwIrq = BSP_BTN2_GPIO_IRQ;
if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &dwIrq, sizeof(dwIrq), &g_dwBtn2SysIntr, sizeof(g_dwBtn2SysIntr), NULL))
{
ERRORMSG(TRUE, (TEXT("%s(): failed to map irq into sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
if (!InterruptInitialize(g_dwBtn2SysIntr, g_hBtn2Event, NULL, 0)) {
ERRORMSG(TRUE, (TEXT("%s(): failed to register sys intr\r\n"), __WFUNCTION__));
goto cleanUp;
}
// Create IST for power button interrupts
g_hPwrBtnThread = CreateThread(NULL, 0, PwrBtnThread, NULL, 0, NULL);
if (!g_hPwrBtnThread)
{
ERRORMSG(TRUE, (_T("CreateThread failed for power button driver!\r\n")));
goto cleanUp;
}
else
{
CeSetThreadPriority(g_hPwrBtnThread, BSP_PWRBTN_THREAD_PRIORITY);
}
g_hBtn1Thread = CreateThread(NULL, 0, Btn1Thread, NULL, 0, NULL);
if (!g_hPwrBtnThread)
{
ERRORMSG(TRUE, (_T("CreateThread F6 failed!\r\n")));
goto cleanUp;
}
else
{
CeSetThreadPriority(g_hBtn1Thread, BSP_Btn1BTN_THREAD_PRIORITY);
}
g_hBtn2Thread = CreateThread(NULL, 0, Btn2Thread, NULL, 0, NULL);
if (!g_hPwrBtnThread)
{
ERRORMSG(TRUE, (_T("CreateThread F7 failed !\r\n")));
goto cleanUp;
}
else
{
CeSetThreadPriority(g_hBtn2Thread, BSP_Btn2BTN_THREAD_PRIORITY);
}
rc = TRUE;
cleanUp:
return rc;
}
//-----------------------------------------------------------------------------
//
// Function: Deinit
//
// This function deinitializes the power button driver. Called by the Device Manager to
// deinitialize a device.
//
// Parameters:
// None.
//
// Returns:
// Returns TRUE.
//
//-----------------------------------------------------------------------------
BOOL Deinit(void)
{
// Power button driver is never unloaded. This entry point is only defined
// to meet minum requirements of the stream interface.
return TRUE;
}
//-----------------------------------------------------------------------------
//
// Function: PwrBtnThread
//
// This is the interrupt service thread for the power button driver.
//
// Parameters:
// lpParam
// [in] Thread data passed to the function using the
// lpParameter parameter of the CreateThread function. Not used.
//
// Returns:
// Returns thread exit code.
//
//-----------------------------------------------------------------------------
static DWORD WINAPI PwrBtnThread (LPVOID lpParam)
{
UINT32 msec, start;
UINT32 pinVal;
WCHAR szState[MAX_PATH];
DWORD dwStateFlags = 0;
// Remove-W4: Warning C4100 workaround
UNREFERENCED_PARAMETER(lpParam);
// IST loop for servicing power button interrupts
while (WaitForSingleObject(g_hPwrBtnEvent, INFINITE) != WAIT_FAILED)
{
// Capture start time of button press
start = GetTickCount();
// Query current system power state to determine if we are resuming
// from suspend
GetSystemPowerState(szState, MAX_PATH, &dwStateFlags);
// Avoid requesting power state transition if the system is resuming from
// suspend. In such cases the POWER_STATE_SUSPEND flag will be set.
if (!(POWER_STATE(dwStateFlags) & POWER_STATE_SUSPEND))
{
// Keep track of how long button is pressed
msec = 0;
// Loop to sample power button pin
do
{
// Sleep between samples
Sleep(BSP_PWRBTN_DEBOUNCE_SAMPLE_MSEC);
// Read current power button pin
DDKGpioReadDataPin(BSP_PWRBTN_GPIO_PORT, BSP_PWRBTN_GPIO_PIN, &pinVal);
// Check if button is still pressed
if (pinVal)
{
// Update how long button is pressed
msec = GetTickCount() - start;
}
// Loop terminates if button is released or time to power off
// system is reached
} while (pinVal && (msec < BSP_PWRBTN_DEBOUNCE_OFF_MSEC));
// Check if button press indicates user wants to power off the
// system
if (msec >= BSP_PWRBTN_DEBOUNCE_OFF_MSEC)
{
// Powering off the system through hardware requires the
// two EVK SYS_ON_OFF_CTL signals to be deasserted. One of
// these signals is driven by the PMIC, the other by CPU.
// Request for the PMIC SYS_ON_OFF_CTL signal to be
// deasserted. During OEMPowerOff, the OAL will take
// care of the other SYS_ON_OFF_CTL to complete the
// power off.
PmicRegisterWrite(MC13892_PWR_MISC_ADDR,
CSP_BITFVAL(MC13892_REG_MISC_PWGT2SPIEN, 1),
CSP_BITFMASK(MC13892_REG_MISC_PWGT2SPIEN));
// Since we are powering off, disallow the power button from
// generating wake events that may disrupt powering off the
// system.
KernelIoControl(IOCTL_HAL_DISABLE_WAKE, &g_dwPwrBtnSysIntr, sizeof(g_dwPwrBtnSysIntr), NULL, 0, NULL);
// Note that we could use SetSystemPowerState to request
// POWER_STATE_OFF, but this state is not supported by
// the default Power Manager. Instead, we just let
// the code fall through to generate a POWER_STATE_SUSPEND
// request and allow the OAL power off the system
// in OEMPowerOff.
}
// Check if button press indicates user wants to suspend the
// system
if (msec >= BSP_PWRBTN_DEBOUNCE_SUSPEND_MSEC)
{
SetSystemPowerState(NULL, POWER_STATE_SUSPEND, POWER_FORCE);
}
}
// After handling the button press, delay before servicing new button
// interrupts to prevent from bouncing into suspend again
Sleep(BSP_PWRBTN_DEBOUNCE_IGNORE_MSEC);
// Clear and reenable button interrupts
DDKGpioClearIntrPin(BSP_PWRBTN_GPIO_PORT, BSP_PWRBTN_GPIO_PIN);
InterruptDone(g_dwPwrBtnSysIntr);
}
return 0;
}
static DWORD WINAPI Btn1Thread (LPVOID lpParam)
{
UINT32 pinVal;
// Remove-W4: Warning C4100 workaround
UNREFERENCED_PARAMETER(lpParam);
while (WaitForSingleObject(g_hPwrBtnEvent, INFINITE) != WAIT_FAILED)
{
Sleep(20);
// Read current power button pin
DDKGpioReadDataPin(BSP_BTN1_GPIO_PORT, BSP_BTN1_GPIO_PIN, &pinVal);
// Check if button is still pressed
if (!pinVal)
{
//send key message
keybd_event(VK_F6, 0, 0, 0);
}
for(;;)
{
DDKGpioReadDataPin(BSP_BTN1_GPIO_PORT, BSP_BTN1_GPIO_PIN, &pinVal);
if(pinVal)
{
keybd_event(VK_F6,0,KEYEVENTF_KEYUP,0);
break;
}
}
// Clear and reenable button interrupts
DDKGpioClearIntrPin(BSP_BTN1_GPIO_PORT, BSP_BTN1_GPIO_PIN);
InterruptDone(g_dwBtn1SysIntr);
}
return 0;
}
static DWORD WINAPI Btn2Thread (LPVOID lpParam)
{
UINT32 pinVal;
// Remove-W4: Warning C4100 workaround
UNREFERENCED_PARAMETER(lpParam);
while (WaitForSingleObject(g_hPwrBtnEvent, INFINITE) != WAIT_FAILED)
{
Sleep(20);
// Read current power button pin
DDKGpioReadDataPin(BSP_BTN2_GPIO_PORT, BSP_BTN2_GPIO_PIN, &pinVal);
// Check if button is still pressed
if (!pinVal)
{
//send key message
keybd_event(VK_F7, 0, 0, 0);
}
for(;;)
{
DDKGpioReadDataPin(BSP_BTN2_GPIO_PORT, BSP_BTN2_GPIO_PIN, &pinVal);
if(pinVal)
{
keybd_event(VK_F7,0,KEYEVENTF_KEYUP,0);
break;
}
}
// Clear and reenable button interrupts
DDKGpioClearIntrPin(BSP_PWRBTN_GPIO_PORT, BSP_PWRBTN_GPIO_PIN);
InterruptDone(g_dwBtn2SysIntr);
}
return 0;
}