www.pudn.com > KEYBD.rar > s3c2440kbd.cpp


/*++ 
THIS CODE AND INFORMATION IS PROVIDED "AS IS" WITHOUT WARRANTY OF 
ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING BUT NOT LIMITED TO 
THE IMPLIED WARRANTIES OF MERCHANTABILITY AND/OR FITNESS FOR A 
PARTICULAR PURPOSE. 
Copyright (c) 2002. Samsung Electronics, co. ltd  All rights reserved. 
 
Module Name:   
 
Abstract: 
 
	This file implements the S3C2440 Keyboard function 
 
rev: 
	2002.4.4	: First S3C2410 version (kwangyoon LEE, kwangyoon@samsung.com) 
 
	2002.1.31	: CE.NET port (kwangyoon LEE, kwangyoon@samsung.com) 
 
Notes:  
--*/ 
 
#include  
#include  
#include  
#include  
 
#undef ZONE_INIT 
 
#include  
#include  
#include  
#include  
#include "s3c2440kbd.hpp" 
#include "S2440.h" 
 
// Pointer to device control registers 
volatile IOPreg *v_pIOPregs; 
volatile SSPreg *v_pSSPregs; 
 
// Pointer to driver globals area 
PDRIVER_GLOBALS v_pDriverGlobals; 
 
DWORD dwSysIntr_Keybd; 
 
// Scan code consts 
static const UINT8 scE0Extended	= 0xe0; 
static const UINT8 scE1Extended	= 0xe1; 
static const UINT8 scKeyUpMask	= 0x80; 
 
UINT32 
ScanCodeToVKeyEx( 
        UINT32                  ScanCode, 
        KEY_STATE_FLAGS KeyStateFlags, 
        UINT32                  VKeyBuf[16], 
        UINT32                  ScanCodeBuf[16], 
        KEY_STATE_FLAGS KeyStateFlagsBuf[16] 
        ); 
 
//	There is really only one physical keyboard supported by the system. 
Ps2Keybd *v_pp2k; 
 
extern void ReadRegDWORD( LPCWSTR szKeyName, LPCWSTR szValueName, LPDWORD pdwValue ); 
 
void WINAPI KeybdPdd_PowerHandler(BOOL bOff) 
{ 
//	DEBUGMSG(1, (TEXT("++KeybdPdd_PowerHandler\r\n"))); 
	if (!bOff) {  
	   v_pp2k->KeybdPowerOn(); 
	} 
	else { 
	   v_pp2k->KeybdPowerOff(); 
	} 
//	DEBUGMSG(1, (TEXT("--KeybdPdd_PowerHandler\r\n"))); 
	return; 
} 
 
#define ONEBIT    0x1 
 
int	putcToKBCTL(UCHAR c) 
{ 
	UINT	i; 
//	UINT	rxbuf[10]; 
//	UINT 	x; 
 
  	v_pIOPregs->rGPBDAT &= ~(ONEBIT << 6);       //Set _SS signal to low (Slave Select) 
 
	while((v_pSSPregs->rSPSTA1 & ONEBIT)==0);	// wait while busy 
 
	v_pSSPregs->rSPTDAT1 = c;	                // write left justified data 
 
	while((v_pSSPregs->rSPSTA1 & ONEBIT)==0);	// wait while busy 
   	 
   	v_pIOPregs->rGPBDAT |= (ONEBIT << 6);        //Set _SS signal to high (Slave Select) 
 
	i = v_pSSPregs->rSPRDAT1; 
 
	return(i); 
} 
 
 
void getsFromKBCTL(UINT8 *m, int cnt) { 
	int	i, j; 
	volatile tmp = 1; 
 
	for(j = 0; j < 3; j++) 
		tmp += tmp; 
	for(j = 0; j < 250 * 30; j++) 
		tmp += tmp; 
 
	for(i = 0; i < cnt; i++) { 
		m[i] = putcToKBCTL(0xFF); 
 
		for(j = 0; j < 400; j++) 
			tmp+= tmp; 
	} 
} 
 
void putsToKBCTL(UINT8 *m,  int cnt) 
{ 
	int	i, j, x; 
	volatile tmp = 1; 
	 
	for(j = 0; j < 3; j++) 
		x = j; 
	for(j = 0; j < 3; j++) 
		tmp += tmp; 
	for(j = 0; j < 250 * 30; j++) 
		tmp += tmp; 
 
	for(i = 0; i < cnt; i++) { 
 
		j = putcToKBCTL(m[i]); 
 
		for(j = 0; j < 400; j++) 
			tmp+= tmp; 
		for(j = 0; j < 400; j++) 
			x = j; 
    } 
} 
 
char lrc(UINT8 *buffer, int count) 
{ 
    char lrc; 
    int n; 
 
    lrc = buffer[0] ^ buffer[1]; 
 
    for (n = 2; n < count; n++) 
    { 
        lrc ^= buffer[n]; 
    } 
 
    if (lrc & 0x80) 
        lrc ^= 0xC0; 
 
    return lrc; 
} 
 
int USAR_WriteRegister(int reg, int data) 
{ 
    UINT8 cmd_buffer[4]; 
 
    cmd_buffer[0] = 0x1b; //USAR_PH_WR; 
    cmd_buffer[1] = (unsigned char)reg; 
    cmd_buffer[2] = (unsigned char)data; 
 
    cmd_buffer[3] = lrc((UINT8 *)cmd_buffer,3); 
    putsToKBCTL((UINT8 *)cmd_buffer,4); 
 
    return TRUE; 
} 
 
 
BOOL 
KeybdDriverInitializeAddresses( 
	void 
	) 
{ 
	bool RetValue = TRUE; 
	DWORD dwIOBase; 
	DWORD dwSSPBase; 
 
	DEBUGMSG(1,(TEXT("++KeybdDriverInitializeAddresses\r\n"))); 
 
	ReadRegDWORD(TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("IOBase"), &dwIOBase ); 
	if(dwIOBase == 0) { 
		DEBUGMSG(1, (TEXT("Can't fount registry entry : HARDWARE\\DEVICEMAP\\KEYBD\\IOBase\r\n"))); 
		goto error_return; 
	} 
	DEBUGMSG(1, (TEXT("HARDWARE\\DEVICEMAP\\KEYBD\\IOBase:%x\r\n"), dwIOBase)); 
 
	ReadRegDWORD(TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("SSPBase"), &dwSSPBase ); 
	if(dwSSPBase == 0) { 
		DEBUGMSG(1, (TEXT("Can't fount registry entry : HARDWARE\\DEVICEMAP\\KEYBD\\SSPBase\r\n"))); 
		goto error_return; 
	} 
	DEBUGMSG(1, (TEXT("HARDWARE\\DEVICEMAP\\KEYBD\\SSPBase:%x\r\n"), dwSSPBase)); 
 
	v_pIOPregs = (volatile IOPreg *)VirtualAlloc(0, sizeof(IOPreg), MEM_RESERVE, PAGE_NOACCESS); 
	if(v_pIOPregs == NULL) { 
		DEBUGMSG(1,(TEXT("[KBD] v_pIOPregs : VirtualAlloc failed!\r\n"))); 
		goto error_return; 
	} 
	else { 
		if(!VirtualCopy((PVOID)v_pIOPregs, (PVOID)(dwIOBase), sizeof(IOPreg), PAGE_READWRITE|PAGE_NOCACHE ))  
		{ 
			DEBUGMSG(1,(TEXT("[KBD] v_pIOPregs : VirtualCopy failed!\r\n"))); 
			goto error_return; 
		} 
	} 
	DEBUGMSG(1, (TEXT("[KBD] v_pIOPregs mapped at %x\r\n"), v_pIOPregs)); 
	 
	v_pSSPregs = (volatile SSPreg *)VirtualAlloc(0, sizeof(SSPreg), MEM_RESERVE, PAGE_NOACCESS); 
	if (v_pSSPregs == NULL) { 
		DEBUGMSG(1, (TEXT("[KBD] v_pSSPregs : VirtualAlloc failed!\r\n"))); 
		goto error_return; 
	} 
	else { 
		if (!VirtualCopy((PVOID)v_pSSPregs, (PVOID)(dwSSPBase), sizeof(SSPreg), PAGE_READWRITE | PAGE_NOCACHE))  
		{ 
		    	DEBUGMSG(1, (TEXT("[KBD] v_pSSPregs : VirtualCopy failed!\r\n"))); 
				goto error_return; 
		} 
	} 
 
	DEBUGMSG(1, (TEXT("[KBD] v_pSSPregs mapped at %x\r\n"), v_pSSPregs)); 
	 
	v_pDriverGlobals = (PDRIVER_GLOBALS)VirtualAlloc(0, DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE, 
                                                     MEM_RESERVE, PAGE_NOACCESS); 
	if (v_pDriverGlobals == NULL) 
	{ 
		DEBUGMSG(1, (TEXT("[KBD] v_pDriverGlobals : VirtualAlloc failed!\r\n"))); 
		goto error_return; 
	} 
 
	if (!VirtualCopy((PVOID)v_pDriverGlobals, 
                      (PVOID)DRIVER_GLOBALS_PHYSICAL_MEMORY_START, 
                      DRIVER_GLOBALS_PHYSICAL_MEMORY_SIZE, 
                      PAGE_READWRITE|PAGE_NOCACHE)) 
	{ 
		DEBUGMSG(1, (TEXT("[KBD] v_pDriverGlobals : VirtualCopy failed!\r\n"))); 
		goto error_return; 
	} 
	 
	DEBUGMSG(1,(TEXT("--KeybdDriverInitializeAddresses\r\n"))); 
	 
	return TRUE; 
 
error_return: 
	if ( v_pIOPregs ) 
		VirtualFree((PVOID)v_pIOPregs, 0, MEM_RELEASE); 
	if ( v_pSSPregs ) 
		VirtualFree((PVOID)v_pSSPregs, 0, MEM_RELEASE); 
	if ( v_pDriverGlobals ) 
		VirtualFree((PVOID)v_pDriverGlobals, 0, MEM_RELEASE); 
	v_pIOPregs = 0; 
	v_pSSPregs = 0; 
	v_pDriverGlobals = 0; 
 
	DEBUGMSG(1,(TEXT("--KeybdDriverInitializeAddresses[FAILED!!!]\r\n"))); 
 
	return FALSE; 
} 
 
static UINT KeybdPdd_GetEventEx2(UINT uiPddId, UINT32 rguiScanCode[16], BOOL rgfKeyUp[16]) 
{ 
    SETFNAME(_T("KeybdPdd_GetEventEx2")); 
 
    UINT32   scInProgress = 0; 
    static UINT32   scPrevious; 
 
    BOOL            fKeyUp; 
    UINT8           ui8ScanCode; 
    UINT            cEvents = 0; 
 
    DEBUGCHK(rguiScanCode != NULL); 
    DEBUGCHK(rgfKeyUp != NULL); 
 
	getsFromKBCTL(&ui8ScanCode, 1); 
 
    DEBUGMSG(ZONE_SCANCODES,  
        (_T("%s: scan code 0x%08x, code in progress 0x%08x, previous 0x%08x\r\n"), 
        pszFname, ui8ScanCode, scInProgress, scPrevious)); 
 
    scInProgress = ui8ScanCode; 
    if (scInProgress == scPrevious) { 
        //	mdd handles auto-repeat so ignore auto-repeats from keybd 
    } else { 
        // Not a repeated key.  This is the real thing. 
        scPrevious = scInProgress; 
         
        if (ui8ScanCode & scKeyUpMask) { 
            fKeyUp = TRUE; 
            scInProgress &= ~scKeyUpMask; 
        } else { 
            fKeyUp = FALSE; 
        } 
         
        rguiScanCode[cEvents] = scInProgress; 
		rgfKeyUp[cEvents] = fKeyUp; 
        ++cEvents; 
    } 
 
    return cEvents; 
} 
 
 
void WINAPI KeybdPdd_ToggleKeyNotification(KEY_STATE_FLAGS	KeyStateFlags) 
{ 
	unsigned int	fLights; 
 
	DEBUGMSG(1, (TEXT("KeybdPdd_ToggleKeyNotification\r\n"))); 
	fLights = 0; 
	if (KeyStateFlags & KeyShiftCapitalFlag) { 
		fLights |= 0x04; 
		} 
	if (KeyStateFlags & KeyShiftNumLockFlag) { 
		fLights |= 0x2; 
		} 
	/* 
	Keyboard lights is disabled once driver is installed because the 
	PS2 controller sends back a response which goes to the IST and corrupts 
	the interface.  When we figure out how to disable the PS2 response we 
	can re-enable the lights routine below 
	*/ 
 
	return; 
} 
 
 
BOOL Ps2Keybd::IsrThreadProc() 
{ 
	DWORD dwPriority; 
 
	// look for our priority in the registry -- this routine sets it to zero if 
	// it can't find it. 
	ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Priority256"), &dwPriority ); 
	if(dwPriority == 0) { 
//		dwPriority = 145;	// default value is 145 
		dwPriority = 240;	// default value is 145 
	} 
 
    DEBUGMSG(1, (TEXT("IsrThreadProc:\r\n"))); 
    m_hevInterrupt = CreateEvent(NULL,FALSE,FALSE,NULL); 
    if (m_hevInterrupt == NULL) { 
        DEBUGMSG(1, (TEXT("IsrThreadProc: InterruptInitialize\r\n"))); 
		goto leave; 
	} 
 
	ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("SysIntr"), &dwSysIntr_Keybd ); 
	if( !dwSysIntr_Keybd ) { 
		goto leave; 
	} 
 
	if (!InterruptInitialize(dwSysIntr_Keybd,m_hevInterrupt,NULL,0)) { 
		DEBUGMSG(1, (TEXT("IsrThreadProc: KeybdInterruptEnable\r\n"))); 
		goto leave; 
	} 
 
	// update the IST priority 
	CeSetThreadPriority(GetCurrentThread(), (int)dwPriority); 
 
#if	0 
while (1) 
{ 
	if ( WaitForSingleObject(m_hevInterrupt, INFINITE) == WAIT_TIMEOUT ) 
		DEBUGMSG(1, (TEXT("timeout\r\n")));		 
	else 
		DEBUGMSG(1, (TEXT("I got one\r\n"))); 
	InterruptDone(dwSysIntr_Keybd); 
} 
#endif 
 
	extern UINT v_uiPddId; 
	extern PFN_KEYBD_EVENT v_pfnKeybdEvent; 
 
	KEYBD_IST keybdIst; 
	keybdIst.hevInterrupt = m_hevInterrupt; 
	keybdIst.dwSysIntr_Keybd = dwSysIntr_Keybd; 
	keybdIst.uiPddId = v_uiPddId; 
	keybdIst.pfnGetKeybdEvent = KeybdPdd_GetEventEx2; 
	keybdIst.pfnKeybdEvent = v_pfnKeybdEvent; 
		 
	KeybdIstLoop(&keybdIst); 
 
leave: 
    return 0; 
} 
 
DWORD Ps2KeybdIsrThread(Ps2Keybd *pp2k) 
{ 
	DEBUGMSG(1,(TEXT("Ps2KeybdIsrThread:\r\n"))); 
	pp2k->IsrThreadProc(); 
	return 0; 
} 
 
BOOL Ps2Keybd::IsrThreadStart() 
{ 
	HANDLE	hthrd; 
 
	DEBUGMSG(1,(TEXT("IsrThreadStart:\r\n"))); 
	hthrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)Ps2KeybdIsrThread,this,0,NULL); 
	//	Since we don't need the handle, close it now. 
	CloseHandle(hthrd); 
	return TRUE; 
} 
 
BOOL Ps2Keybd::Initialize() 
{ 
	DEBUGMSG(1,(TEXT("Ps2Keybd::Initialize\r\n"))); 
 
	DEBUGMSG(1,(TEXT("Ps2Keybd::Initialize Done\r\n"))); 
	return TRUE; 
} 
 
 
BOOL Ps2Keybd::KeybdPowerOn() 
{ 
    UINT8 msg[5]; 
    int t; 
    char dummy = (char)0xff; 
 
	DEBUGMSG(1,(TEXT("++Ps2Keybd::KeybdPowerOn\r\n"))); 
 
	// Setup IO port for SPI interface & Keyboard 
	 
	// Setup EINT1 (KBDINT) 
    v_pIOPregs->rGPFCON &= ~(0x3 << 2); 	// Clear GPF1  
    v_pIOPregs->rGPFCON |= (0x2 << 2);  	// Set GPF1 to EINT1 for Keyboard interrupt 
 
    v_pIOPregs->rEXTINT0 &= ~(0x7 << 4);    // Clear EINT1 
    v_pIOPregs->rEXTINT0 |= (0x2 << 4);     // fallig edge triggered for EINT1 
 
	// setup SPI interface 
	// GPG5 : SPIMISO (KBDSPIMISO) 
	// GPG6 : SPIMOSI (KBDSPIMOSI) 
	// GPG7 : SPICLK  (KBDSPICLK) 
    v_pIOPregs->rGPGCON &= ~((0x3 << 10) | (0x3 << 12) | (0x3 << 14));   // Clear GPG5,6,7 
    v_pIOPregs->rGPGCON |= ((0x3 << 10) | (0x3 << 12) | (0x3 << 14));     
      
	// setup _SS signal(nSS_KBD) 
    v_pIOPregs->rGPBCON &= ~(0x3 << 12);         // Clear GPB6 
    v_pIOPregs->rGPBCON |= (ONEBIT << 12);        // Set Port GPB6 to output for nSS signal 
 
	// setup _PWR_OK signal (KEYBOARD) 
    v_pIOPregs->rGPBCON &= ~(0x3 << 0);         // Clear GPB0  
    v_pIOPregs->rGPBCON |= (ONEBIT << 0);       // Set Port GPB0 to output for _PWR_OK signal 
 
    v_pIOPregs->rGPDDAT &=~(ONEBIT << 0);        // set _PWR_OK to 0 
     
	// Setup SPI registers 
    // Interrupt mode, prescaler enable, master mode, active high clock, format B, normal mode 
    v_pSSPregs->rSPCON1 = (ONEBIT<<5)|(ONEBIT<<4)|(ONEBIT<<3)|(0x0<<2)|(ONEBIT<<1); 
     
	// Developer MUST change the value of prescaler properly whenever value of PCLK is changed. 
    v_pSSPregs->rSPPRE1 = 255;// 99.121K = 203M/4/2/(255+1) PCLK=50.75Mhz FCLK=203Mhz SPICLK=99.121Khz 
          
    for(t=0;t<20000; t++); // delay 
	    msg[0] = (char)0x1b; msg[1] = (char)0xa0; msg[2] = (char)0x7b; msg[3] = (char)0; // Initialize USAR 
    	for(t=0; t < 10; t++) { 
    	dummy = putcToKBCTL(0xff); 
    } 
     
    for(t=0; t<10; t++) { // wait for a while 
        putsToKBCTL(msg,3); 
        for(t=0;t<20000; t++); 
    } 
    t = 100; 
    while(t--) { 
        if((v_pIOPregs->rGPFDAT & 0x2)==0) { // Read _ATN 
            break; 
        } 
    }	//check _ATN 
    if(t != 0) { 
        getsFromKBCTL(msg,3); 
    }     
    t=100000; 
    while(t--); // delay 
	msg[0] = (char)0x1b; msg[1] = (char)0xa1; msg[2] = (char)0x7a; msg[3] = (char)0; //Initialization complete 
	putsToKBCTL(msg,3); 
 
	DEBUGMSG(1,(TEXT("--Ps2Keybd::KeybdPowerOn\r\n"))); 
	return(TRUE); 
} 
 
BOOL Ps2Keybd::KeybdPowerOff() 
{ 
	DEBUGMSG(1,(TEXT("++Ps2Keybd::KeybdPowerOff\r\n"))); 
 
	DEBUGMSG(1,(TEXT("--Ps2Keybd::KeybdPowerOff\r\n"))); 
	return(TRUE); 
}