/*******************************************************

功能: 键盘驱动
接口: GPN0,GPN1,GPN2,GPN3,GPN4,GPN5全接上拉。
      低电平产生中断.
原理: 
说明: 本机键盘驱动PDD层
编制: 刘启明
日期: 2010-06-11

*******************************************************/

//#include <bsp.h>
//#include <winuserm.h>
#include <keybddr.h>
#include <keybdpdd.h>


#include <bsp.h>
#include <pmpolicy.h>
#include <drvmsg.h>
#include <drvlib_mem.h>


// Variables for accessing Hardware registers and Driver Globals
volatile static GPIO_REG *v_pGPIOregs=NULL;

// Keypad State
DWORD	g_dwPADCurrentKey;

// This lets us know if we're in our power handler routine, so we know
// not to make any system calls (debug messages, etc).
BOOL g_fInPowerHandler;

const UINT8 KeypadScanCodeToVKeyTable[6] =
{
	VK_LEFT,     	// 1
	VK_DOWN,		// 2
	VK_UP,    		// 0
	VK_RIGHT,		// 5
	VK_RETURN,	   	// 4
	VK_BACK,     	// 3	

};


/* 
// KEYBD define for x210
SW5		EINT28	GPH3_4
SW6		EINT29	GPH3_5
SW7		EINT4	GPH0_4
SW8		EINT7	GPH0_7
SW9		EINT9	GPH1_1
SW10	EINT16	GPH2_0

*/
#define X210II 1

#define SW5		GPH02_EXT_INT_2  //EINT 2
#define SW6		GPH03_EXT_INT_3  // EINT 3
#define SW7		GPH20_EXT_INT_16// KP_COL 0
#define SW8		GPH21_EXT_INT_17  // KP_COL 1
#define SW9		GPH22_EXT_INT_18  // KP_COL 2
#define SW10	GPH23_EXT_INT_19  // KP_COL 3

DWORD g_KEYBDInterruptPort[]={EXT_INT_2,EXT_INT_3,EXT_INT_16,EXT_INT_17,EXT_INT_18,EXT_INT_19};




#define NUM_OF_KEYS  	6

DWORD g_KEYBDPort[]={SW5,SW6,SW7,SW8,SW9,SW10};



static void keybd_Hw_Init(void)
{
		RETAILMSG(1, (TEXT("<kbd> +++keybd_Hw_Init\r\n")));

	for(int i=0;i<NUM_OF_KEYS; i++)
	{
    	Mask_EXTINT(v_pGPIOregs, g_KEYBDInterruptPort[i]);
		Set_PinFunction(v_pGPIOregs, g_KEYBDPort[i]);
		//Set_EXTINT_TRLVL(v_pGPIOregs, g_KEYBDPort[i], sgip_LOW_LEVEL);
	//	Set_EXTINT_TRLVL(v_pGPIOregs, g_KEYBDPort[i], sgip_FALLING_EDGE);
			Set_EXTINT_TRLVL(v_pGPIOregs, g_KEYBDPort[i], sgip_BOTH_EDGE);
		Set_EXTINT_FILTER(v_pGPIOregs, g_KEYBDInterruptPort[i], sgip_DELAY_FLT, 0);

		Clear_EXTINT(v_pGPIOregs, g_KEYBDInterruptPort[i]);

	}


	for(i=0;i<NUM_OF_KEYS;i++)
	{
		Unmask_EXTINT(v_pGPIOregs, g_KEYBDInterruptPort[i]);
	}
		RETAILMSG(0, (TEXT("<kbd> ---keybd_Hw_Init\r\n")));



	
}

static BOOL keybd_Hw_scanKeyboard( DWORD *pScanCode)
{
	DWORD ReadCode;
	ReadCode = 0x3f;
	Sleep(50);
	for(int i=0;i<NUM_OF_KEYS;i++)
	{
		if(!Get_PinData(v_pGPIOregs, g_KEYBDPort[i]))
		{
			ReadCode &=~(1<<i);
			RETAILMSG(1, (TEXT("<kbd> *g_KEYBDPort=%d\r\n"),i));
		}
	}

	
	if(ReadCode!=0x3f)
	{
		switch(ReadCode)
		{
			case 0x3e:*pScanCode=0;break;
			case 0x3d:*pScanCode=1;break;
			case 0x3b:*pScanCode=2;break;
			case 0x37:*pScanCode=3;break;
			case 0x1f:*pScanCode=4;break;
			case 0x2f:*pScanCode=5;break;			
			default:break;
		}

		return 1;


		
	}
	else
		return 0;

	RETAILMSG(0, (TEXT("<kbd> *pScanCode=%d\r\n"),*pScanCode));// lqm test.10-08-01
	return 1;
}

static BOOL keybd_Hw_isKeyUp(void)
{
	DWORD readcode;
//	readcode=s6410IOP->GPNDAT&0x3f;
	if(readcode!=0x3f)
		return FALSE;
	else
		return TRUE;
}


// KeypadScanCodeToVKey:  Map a keypad scan code to a virtual key.
static UINT32 KeypadScanCodeToVKey(UINT32 uKeypadScancode)
{
    RETAILMSG(1,(TEXT("[KBD]Keypad ScanCode=%d  VK=%d\r\n"), uKeypadScancode, KeypadScanCodeToVKeyTable[uKeypadScancode]));
	
    UINT32 uVKey = KeypadScanCodeToVKeyTable[uKeypadScancode];

    // Use silent repeats if necessary.
    //if(SILENT_REPEAT(uVKey))
    {
    //    uVKey |= KEYBD_DEVICE_SILENT;
    }

    return uVKey;
}

static BOOL KeybdDriverInitializeAddresses(void)
{

	BOOL bReturn = TRUE;

	// GPIO initialization
	v_pGPIOregs = (GPIO_REG*)DrvLib_MapIoSpace(BASE_REG_PA_GPIO, sizeof(GPIO_REG), FALSE);
	if (v_pGPIOregs == NULL)
	{
//		LEDERR(TRUE, (_T("Failed to allocate the v_pGPIOregs.\r\n")));
		bReturn = FALSE;
	}

	return bReturn;
}


static void KeybdPowerOn()
{
	keybd_Hw_Init();//初始化按键中断寄存器
}

static void KeybdPowerOff()
{

}

//      @doc EXTERNAL
/*      @func

Called by the MDD on system power state changes.

@comm This routine runs in kernel context and assumes that interrupts are 
disabled since it monkeys directly with registers.  It may not make any 
system calls or cause a reschedule in any way.  You can read and write to 
your own memory and that is about it.  If you put any subroutines inside 
here, they must also follow this restriction.  

*/
void WINAPI KeybdPdd_PowerHandler(
	BOOL	bOff    // @parm TRUE, the system is powering off; FALSE, the system is powering up. 
	)
{
    g_fInPowerHandler = TRUE;
    
    if (bOff) 
	{
        // Mask power switch interrupt (HW doesn't actually mask intr, but
        // this will cause ISR to ignore subsequent ON button interrupts)
         KeybdPowerOff();
    }
    else 
	{
         KeybdPowerOn();       
    }
    g_fInPowerHandler = FALSE;
}



/*============================================

功能: 在MDD层入口被调用，初始化硬件设备
参数: pfnKeybdEventCallback回传给系统

============================================*/
BOOL WINAPI KeybdPdd_InitializeDriver(PFN_KEYBD_EVENT_CALLBACK	pfnKeybdEventCallback)
{
	if (!KeybdDriverInitializeAddresses())
	{
		return FALSE;
	}

	(*pfnKeybdEventCallback)(KEYBD_DEVICE_CONNECT, 0);

	KeybdPowerOn();

	return TRUE;
}

/*
Called by the MDD to retrieve keyboard events after SYSINTR_KEYBD is signalled.
@rdesc	Number of key events.  0 is allowed.
*/
INT WINAPI KeybdPdd_GetEvent(
	UINT32	VirtualKeys[16],		// @parm Buffer to put virtual keys which were detected.
	KEY_STATE_FLAGS	KeyEvents[16]	// @parm Buffer to put key state flags.
	)
{
	UINT	nEvents = 0;
	int     iFailCount=0;
    static UINT PreKeyNo = 0;

	Sleep(50);//消抖延时
	if(!keybd_Hw_scanKeyboard(&g_dwPADCurrentKey))//没有键按下则退出
	{

		if(g_dwPADCurrentKey == 0x3f)	
		{
			KeyEvents[nEvents] &= ~KeyStateDownFlag;
		    g_dwPADCurrentKey = PreKeyNo;
		}
		else
		{
			KeyEvents[nEvents] = KeyStateToggledFlag;  //无效点
		}
		
	}
	else
	{
		KeyEvents[nEvents] |= KeyStateDownFlag;//标记为按下状态
		PreKeyNo = g_dwPADCurrentKey;
	}

	VirtualKeys[nEvents] = KeypadScanCodeToVKey(g_dwPADCurrentKey);


//	KeyEvents[nEvents] = KeyStateDownFlag;//标记为按下状态
	nEvents++;

keypad_done:

	return nEvents;
}

/*
Called by the MDD on Dll state changes.
shouldn't allow more than one attachment.
*/
BOOL WINAPI KeybdPdd_DllEntry(
	HANDLE  hinstDLL,		// @parm Standard Dll entry arg.
	DWORD   Op,				// @parm Standard Dll entry arg. 
	LPVOID  lpvReserved		// @parm Standard Dll entry arg. 
	)
{
	return TRUE;
}


