📄 bspkeypad.cpp
字号:
{
RETAILMSG(1, (_T("KPPLayout: data structure size mismatch\r\n")));
goto Leave;
}
// Make sure that the Sc->Vk tables are the sizes that we expect
DEBUGCHK(dim(ScanCodeToVKeyTable) == (1 + ScanCodeTableLast - ScanCodeTableFirst));
*pDeviceLayout = dlKPPEngUs;
fRet = TRUE;
Leave:
return fRet;
}
#ifdef DEBUG
// Verify function declaration against the typedef.
static PFN_DEVICE_LAYOUT_ENTRY v_pfnDeviceLayout = KPPLayout;
#endif
//------------------------------------------------------------------------------
//
// Function: BSPKppRegInit
//
// Initializes the keypad port registers.
//
// Parameters:
// None.
//
// Returns:
// None.
//
//------------------------------------------------------------------------------
void BSPKppRegInit()
{
KPP_FUNCTION_ENTRY();
// Enable KPP clocks to access KPP registers
BSPKppSetClockGatingMode(TRUE);
// Enable no. of rows in keypad (KRE = 1)
// Configure columns as open-drain (KCO = 1)
INSREG16(&g_pKPP->KPCR, CSP_BITFMASK(KPP_KPCR_KRE),
CSP_BITFVAL(KPP_KPCR_KRE, KPP_ROW_MASK));
INSREG16(&g_pKPP->KPCR, CSP_BITFMASK(KPP_KPCR_KCO),
CSP_BITFVAL(KPP_KPCR_KRE, KPP_COLUMN_MASK));
// Write 0's to all columns
INSREG16(&g_pKPP->KPDR, CSP_BITFMASK(KPP_KPDR_KCD),
CSP_BITFVAL(KPP_KPDR_KCD, 0));
// Configure rows as input, columns as output
INSREG16(&g_pKPP->KDDR, CSP_BITFMASK(KPP_KDDR_KCDD),
CSP_BITFVAL(KPP_KDDR_KCDD, KPP_COLUMN_MASK));
INSREG16(&g_pKPP->KDDR, CSP_BITFMASK(KPP_KDDR_KRDD),
CSP_BITFVAL(KPP_KDDR_KRDD, 0));
// Clear KPKD and KPSR_KPKR status flag (w1c)
// Clear synchronizer chain - KDSC (w1c)
// Enable keypad interrupt - Set KDIE,
// clear KRIE (avoid false release events)
OUTREG16(&g_pKPP->KPSR,
(CSP_BITFVAL(KPP_KPSR_KPP_EN, KPP_KPSR_KPP_EN_ENABLE) |
CSP_BITFVAL(KPP_KPSR_KPKD, KPP_KPSR_KPKD_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KPKR, KPP_KPSR_KPKR_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KDSC, KPP_KPSR_KDSC_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KDIE, KPP_KPSR_KDIE_INT_ENABLE) |
CSP_BITFVAL(KPP_KPSR_KRIE, KPP_KPSR_KRIE_INT_DISABLE)));
DEBUGMSG(ZONE_PDD, (TEXT("End of Init method - ctrl: %x status: %x direction: %x data: %x\r\n"),
g_pKPP->KPCR, g_pKPP->KPSR, g_pKPP->KDDR, g_pKPP->KPDR));
// Disable KPP clocks for Power Management
BSPKppSetClockGatingMode(FALSE);
KPP_FUNCTION_EXIT();
}
//------------------------------------------------------------------------------
//
// Function: BSPKPPGetScanCodes
//
// This function gets the scan codes and key events from the KPP.
//
// Parameters:
// rguiScanCode[16] -
// [out] An array of scan codes for each key event detected.
//
// rgfKeyUp[16] -
// [out] An array of booleans telling, for each key event,
// whether the key has gone up or down.
//
// Returns:
// The number of key events.
//
//------------------------------------------------------------------------------
UINT BSPKPPGetScanCodes(UINT32 rguiScanCode[16], BOOL rgfKeyUp[16])
{
UINT eventCount;
KPP_FUNCTION_ENTRY();
// Enable KPP clocks to access registers
// during key scan sequence
BSPKppSetClockGatingMode(TRUE);
KppSaveRegState();
eventCount = KppScanSequence(rguiScanCode, rgfKeyUp, TRUE);
if (g_SysSuspend)
{
KppRestoreRegState();
g_SysSuspend = FALSE;
// Call scan sequence again with restored KPP register
// state to assure that we read the correct scan codes.
eventCount = KppScanSequence(rguiScanCode, rgfKeyUp, TRUE);
}
// Disable KPP clocks for Power Management
BSPKppSetClockGatingMode(FALSE);
// Wait, so that we do not immediately trigger another keypad
// interrupt upon completing the scan sequence and returning
// the scan codes.
Sleep(9);
KPP_FUNCTION_EXIT();
return eventCount;
}
//------------------------------------------------------------------------------
//
// Function: KppScanSequence
//
// This function scans the keypad matrix, compiling a list of key events.
//
// Parameters:
// rguiScanCode[16] -
// [out] An array of scan codes for each key event detected.
//
// rgfKeyUp[16] -
// [out] An array of booleans telling, for each key event,
// whether the key has gone up or down.
//
// allowSysCalls -
// [in] A boolean variable telling us whether or not we can
// make system calls. This is needed for the case when we are
// entering suspend and cannot make system calls.
//
// Returns:
// The number of key events.
//
//------------------------------------------------------------------------------
static UINT KppScanSequence(UINT32 rguiScanCode[16], BOOL rgfKeyUp[16], BOOL allowSysCalls)
{
static BOOL notInitialized = TRUE; // Set to false after initialization.
static CRITICAL_SECTION g_hKppLock;
UINT16 tempKPSR; // KPSR value read at start of scan sequence
UINT16 kpsrWrVal = 0;
UINT8 iRowMask;
UINT8 iColMask;
UINT8 iCol;
UINT8 iRow;
UINT8 evCnt = 0;
UINT8 index;
UINT8 rowData;
BOOL isKeyDown = FALSE;
KPP_FUNCTION_ENTRY();
// Initialize variables the first time this method is called
if (notInitialized)
{
// Do not execute initialization again
notInitialized = FALSE;
// create KPP critical section
InitializeCriticalSection(&g_hKppLock);
// Initialise key status to all release '1' and clear key down status.
memset(kppStatus, KPP_ROW_MASK, sizeof(kppStatus));
memset(keyDown, 0, sizeof(keyDown));
memset(prevDownTime, 0, sizeof(prevDownTime));
memset(keyDownSent, 0, sizeof(keyDownSent));
}
if (allowSysCalls)
{
EnterCriticalSection(&g_hKppLock);
}
// Read keypad status register
tempKPSR = INREG16(&g_pKPP->KPSR);
DEBUGMSG(ZONE_PDD, (TEXT("Before scan, tempKPSR 0x%04x, KPSR 0x%04x. \r\n"),
tempKPSR, INREG16(&g_pKPP->KPSR)));
// Disable interrupts while processing.
INSREG16(&g_pKPP->KPSR, CSP_BITFMASK(KPP_KPSR_KDIE),
CSP_BITFVAL(KPP_KPSR_KDIE, KPP_KPSR_KDIE_INT_DISABLE));
INSREG16(&g_pKPP->KPSR, CSP_BITFMASK(KPP_KPSR_KRIE),
CSP_BITFVAL(KPP_KPSR_KRIE, KPP_KPSR_KRIE_INT_DISABLE));
if(CSP_BITFEXT(tempKPSR, KPP_KPSR_KPKD) && CSP_BITFEXT(tempKPSR, KPP_KPSR_KDIE))
{
// At least 1 key depressed
DEBUGMSG(ZONE_PDD,
(TEXT("Depress interrupt, KPSR 0x%04x. \r\n"), tempKPSR));
// Write '1' to all columns
INSREG16(&g_pKPP->KPDR, CSP_BITFMASK(KPP_KPDR_KCD),
CSP_BITFVAL(KPP_KPDR_KCD, KPP_COLUMN_MASK));
// Configure column as totem-pole outputs
INSREG16(&g_pKPP->KPCR, CSP_BITFMASK(KPP_KPCR_KCO),
CSP_BITFVAL(KPP_KPCR_KCO, ~KPP_COLUMN_MASK));
// Configure columns as open drain
INSREG16(&g_pKPP->KPCR, CSP_BITFMASK(KPP_KPCR_KCO),
CSP_BITFVAL(KPP_KPCR_KCO, KPP_COLUMN_MASK));
// Scan key map for changes
for(iCol = 0, iColMask = 1; iCol < KPP_COLUMN_INUSE && !g_SysSuspend; iCol++, iColMask <<= 1)
{
// Write '0' for this column.
INSREG16(&g_pKPP->KPDR, CSP_BITFMASK(KPP_KPDR_KCD),
CSP_BITFVAL(KPP_KPDR_KCD, ~iColMask));
// Wait required to allow row outputs to propagate
if (allowSysCalls)
{
Sleep(1);
}
else
{
KppBusyWait(1);
}
// Get current key status & handle accordingly
rowData = KPP_ROW_MASK & EXTREG16(&g_pKPP->KPDR,
CSP_BITFMASK(KPP_KPDR_KRD), KPP_KPDR_KRD_LSH);
for(iRow = 0, iRowMask = 1; iRow < KPP_ROW_INUSE && !g_SysSuspend; iRow++, iRowMask <<= 1)
{
if((rowData & iRowMask) ^ (kppStatus[iCol] & iRowMask))
{
// Key status changed. Send event accordingly.
index = iCol * KPP_ROW_INUSE + iRow;
if((rowData & iRowMask))
{
// Key status changed to released.
// Handle briefly pressed keys.
if(!(kppStatus[iCol] & iRowMask) && !(keyDown[iCol] & iRowMask))
{
// Key depressed very briefly, less than 1 debounce period.
DEBUGMSG(ZONE_PDD, (TEXT("Changed: depressed < 1 period.\r\n")));
}
else
{
rguiScanCode[evCnt] = index;
rgfKeyUp[evCnt] = TRUE;
evCnt++;
keyDown[iCol] &= ~iRowMask;
keyDownSent[index] = FALSE;
DEBUGMSG(ZONE_PDD,
(TEXT("Key released, tempKPSR 0x%04x, KPSR 0x%04x. \r\n"),
tempKPSR, INREG16(&g_pKPP->KPSR)));
}
}
else
{
// Key status changed to depressed.
isKeyDown = TRUE;
DEBUGMSG(ZONE_PDD,
(TEXT("Key pressed, tempKPSR 0x%04x, KPSR 0x%04x. \r\n"),
tempKPSR, INREG16(&g_pKPP->KPSR)));
prevDownTime[index] = GetTickCount();
}
}
else // No key status change
{
if(!(rowData & iRowMask))
{
// Key still depressed.
// Send key down event after debouncing period.
isKeyDown = TRUE;
index = iCol * KPP_ROW_INUSE + iRow;
if(GetTickCount() < prevDownTime[index])
{
prevDownTime[index] = 0;
}
if((GetTickCount() - prevDownTime[index]) >= KEY_DEBOUNCE_PERIOD)
{
if(!(keyDown[iCol] & iRowMask))
{
keyDown[iCol] |= iRowMask;
}
DEBUGMSG(ZONE_PDD,
(TEXT("Keypress debounced. \r\n")));
if (!keyDownSent[index])
{
// Key down not yet sent, so process
rguiScanCode[evCnt] = index;
rgfKeyUp[evCnt] = FALSE;
evCnt++;
keyDownSent[index] = TRUE;
}
}
}
}
}
// Store current keypad status
kppStatus[iCol] = rowData;
}
// Done keypad scanning.
INSREG16(&g_pKPP->KPDR, CSP_BITFMASK(KPP_KPDR_KCD),
CSP_BITFVAL(KPP_KPDR_KCD, ~KPP_COLUMN_MASK));
INSREG16(&g_pKPP->KPCR, CSP_BITFMASK(KPP_KPCR_KCO),
CSP_BITFVAL(KPP_KPCR_KCO, KPP_COLUMN_MASK));
// Clear KPKD and KPKR status bits by writing a 1.
// Set the KPKR synchronizer chain by writing a 1 to KRSS.
// Clear the KPKD synchronizer chain by writing a 1 to KDSC.
// Re-enable KDIE and KRIE to detect key hold and key release events.
OUTREG16(&g_pKPP->KPSR, CSP_BITFVAL(KPP_KPSR_KPP_EN, KPP_KPSR_KPP_EN_ENABLE) |
CSP_BITFVAL(KPP_KPSR_KRSS, KPP_KPSR_KRSS_SET) |
CSP_BITFVAL(KPP_KPSR_KPKR, KPP_KPSR_KPKR_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KPKD, KPP_KPSR_KPKD_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KDSC, KPP_KPSR_KDSC_CLEAR) |
CSP_BITFVAL(KPP_KPSR_KDIE, KPP_KPSR_KDIE_INT_ENABLE) |
CSP_BITFVAL(KPP_KPSR_KRIE, KPP_KPSR_KRIE_INT_ENABLE));
}
else if(CSP_BITFEXT(tempKPSR, KPP_KPSR_KPKR) && CSP_BITFEXT(tempKPSR, KPP_KPSR_KRIE))
{
DEBUGMSG(ZONE_PDD,
(TEXT("Release interrupt, KPSR 0x%04x. \r\n"), tempKPSR));
// All configured keys released. Reset all key indicators
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -