//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

#include <windows.h>
#include <ceddk.h>
#include <nkintr.h>
#include <Pmpolicy.h>

#undef ZONE_INIT

#include <keybddbg.h>
#include <keybddr.h>
#include <keybdpdd.h>
#include <keybdist.h>
#include <oal.h>
#include <register_map.h>
#include <drvlib_mem.h>
#include <drvmsg.h>

#include "keymatrix.hpp"

#include <bsp.h>

#include <pmplatform.h>


//#define BP_CLK_IP_KEYIF   (1<<8)                      // PCLKCON
#define FT_CLK_DIV     (FIN/32000 - 1)


// Pointer to device control registers
static volatile GPIO_REG		*v_pGPIOregs = NULL;
static volatile KEYPAD_REG		*v_pKEYIFregs = NULL;
static volatile CMU_CLK_REG		*v_pCMUCLKregs = NULL;

BOOL g_bHandleWakeup=FALSE;

HANDLE g_hPwrControl 			= INVALID_HANDLE_VALUE;


#if defined(project_wpc)
static HANDLE v_hevtKeyPressed;
#endif

// There is really only one physical keyboard supported by the system.
KeyMatrix *Keyboard;

extern void ReadRegDWORD( LPCWSTR szKeyName, LPCWSTR szValueName, LPDWORD pdwValue );



/*****************************************************************************
*    Function Name : GPIO Handling function
*    Function Desc  : GPIO_PuEnable, GPIO_CtrlHandler
*            Pull up Enable/Disable
*            GPIO Control register configuration only related to KEYPAD
*            GPIO Data register setting only related to KEYPAD
*/

typedef enum {
    ENUM_INPUT = 0,
    ENUM_OUTPUT,
    ENUM_AUXFUNC,
    ENUM_EXTINT,
    ENUM_RESERVED,
} ENUM_GPIO_FUNC;

typedef enum {
    ENUM_ROW,
    ENUM_COL
} ENUM_COL_ROW;



/****************************************************************************/
#if ((MATRIX_LAYOUT == LAYOUT0)||(MATRIX_LAYOUT == LAYOUT2))
#define SIZE_BITS   8
#define SIZE_COLS   8
#define SIZE_ROWS   8
#elif (MATRIX_LAYOUT == LAYOUT1)
#define SIZE_BITS   2
#define SIZE_COLS   5
#define SIZE_ROWS   2
#elif (MATRIX_LAYOUT == LAYOUT3)
#define SIZE_BITS   4
#define SIZE_COLS   4
#define SIZE_ROWS   4
#endif

DWORD ChangeState[SIZE_COLS];
DWORD KeyState[SIZE_COLS];
DWORD FaultKey;


#define KCODE_TYPE_NORMAL  0x0001
#define KCODE_TYPE_SL      0x0002

#define SIZE_KEY        SIZE_COLS * SIZE_ROWS

#define CNT_VALIDKEY    1
#define CNT_LONGKEY     30
#define TIME_KEYSCAN    10
#define SCAN_EXT        0xe000

struct KSTATE
{
    WORD Mask;
    WORD Cnt;
};

struct KCODE
{
    DWORD Type;
    DWORD Scan;
    DWORD TimeoutCnt;    // used by KCODE_TYPE_SL
    BOOL Fin;
};

#if (MATRIX_LAYOUT == LAYOUT0) 
struct KSTATE KeyChange[SIZE_KEY];
struct KCODE KeyCode[SIZE_KEY] =
{
    {KCODE_TYPE_NORMAL , 0x0000 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0001 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0002 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0003 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0004 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0005 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0006 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0007 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0008 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0009 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0010 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0011 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0012 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0013 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0014 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0015 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0016 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0017 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0018 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0019 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0020 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0021 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0022 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0023 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0024 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0025 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0026 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0027 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0028 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0029 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0030 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0031 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0032 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0033 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0034 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0035 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0036 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0037 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0038 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0039 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003f , 0, 0},
};
#elif (MATRIX_LAYOUT == LAYOUT1)
struct KSTATE KeyChange[SIZE_KEY];
struct KCODE KeyCode[SIZE_KEY] =
{
    {KCODE_TYPE_NORMAL , 0x0000 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0001 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0002 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0003 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0004 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0005 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0006 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0007 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0008 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0009 , 0, 0}
};
#elif (MATRIX_LAYOUT == LAYOUT2) 
struct KSTATE KeyChange[SIZE_KEY];
struct KCODE KeyCode[SIZE_KEY] =
{
    {KCODE_TYPE_NORMAL , 0x0000 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0001 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0002 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0003 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0004 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0005 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0006 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0007 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0008 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0009 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x000f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0010 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0011 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0012 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0013 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0014 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0015 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0016 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0017 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0018 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0019 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x001f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0020 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0021 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0022 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0023 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0024 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0025 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0026 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0027 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0028 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0029 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x002f , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0030 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0031 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0032 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0033 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0034 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0035 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0036 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0037 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0038 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x0039 , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003a , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003b , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003c , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003d , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003e , 0, 0},
    {KCODE_TYPE_NORMAL , 0x003f , 0, 0}
};
#elif (MATRIX_LAYOUT == LAYOUT3)
struct KSTATE KeyChange[SIZE_KEY];

#if defined(BSP_HW_ID) && (BSP_HW_ID == 0)
	struct KCODE KeyCode[SIZE_KEY] =
	{
	    {KCODE_TYPE_NORMAL , 0x0000 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0001 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0002 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0003 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0004 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0005 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0006 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0007 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0008 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0009 , 0, 0},
	    {KCODE_TYPE_SL     , 0x000a , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000b , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000c , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000d , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000e , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000f , 0, 0}
	};
#elif defined(BSP_HW_ID) && (BSP_HW_ID == 1)
	struct KCODE KeyCode[SIZE_KEY] =
	{
	    {KCODE_TYPE_NORMAL , 0x0000 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0001 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0002 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0003 , 0, 0},
	    {KCODE_TYPE_SL     , 0x0004 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0005 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0006 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0007 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0008 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x0009 , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000a , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000b , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000c , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000d , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000e , 0, 0},
	    {KCODE_TYPE_NORMAL , 0x000f , 0, 0}
	};
#else
	#error Unsupported target board.
#endif

#endif





static void GPIO_PuEnable(ENUM_COL_ROW iClass, bool bFlag);
static void GPIO_CtrlHandler(ENUM_COL_ROW iClass, ENUM_GPIO_FUNC iLevel);

static void KEYIF_Column_Set(DWORD dVal);
static void KEYIF_Column_Bitset(bool bVal, int cIdx);
static DWORD KEYIF_Row_Read(void);
static void KEYIF_Status_Clear(void);
/*****************************************************************************/

/*****************************************************************************
*    Function Name : KeybdPdd_PowerHandler
*    Function Desc  : Power Handler
*
*/
void WINAPI KeybdPdd_PowerHandler(BOOL bOff)
{
    if (!bOff)
    {
        g_bHandleWakeup=TRUE;
        Keyboard->KeybdPowerOn();
    }
    else
    {
        g_bHandleWakeup=FALSE;
        Keyboard->KeybdPowerOff();
    }
    return;
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KeybdDriverInitializeAddresses
*    Function Desc  : KeyBoard Driver Initialization
*                     Read Registry
*
*/
BOOL KeybdDriverInitializeAddresses(void)
{
    bool RetValue = TRUE;

    KBDMSG(KEY_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

	memset(ChangeState, 0, sizeof(ChangeState));
	memset(KeyState, 0, sizeof(KeyState));


	// Clock Management Unit
    v_pCMUCLKregs = (CMU_CLK_REG *)DrvLib_MapIoSpace(BASE_REG_PA_CMU_CLK, sizeof(CMU_CLK_REG), FALSE);
    if (v_pCMUCLKregs == NULL)
    {
        KBDERR(TRUE, (TEXT("Failed to allocate v_pCMUCLKregs.\r\n")));
		goto ERROR_RETURN;
    }
    
    // GPIO
    v_pGPIOregs = (GPIO_REG *)DrvLib_MapIoSpace(BASE_REG_PA_GPIO, sizeof(GPIO_REG), FALSE);
    if (v_pGPIOregs == NULL)
    {
        KBDERR(TRUE, (TEXT("Failed to allocate v_pGPIOregs.\r\n")));
        goto ERROR_RETURN;
    }

    // KEYIF
    v_pKEYIFregs = (KEYPAD_REG *)DrvLib_MapIoSpace(BASE_REG_PA_KEYIF, sizeof(KEYPAD_REG), FALSE);
    if (v_pKEYIFregs == NULL)
    {
        KBDERR(TRUE, (TEXT("Failed to allocate v_pKEYIFregs.\r\n")));
        goto ERROR_RETURN;
    }

   
    KBDMSG(KEY_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return TRUE;

ERROR_RETURN:

    if(v_pCMUCLKregs)
    {
    	DrvLib_UnmapIoSpace((PVOID)v_pCMUCLKregs);
    	v_pCMUCLKregs = NULL;
    }

    if(v_pGPIOregs)
    {
        DrvLib_UnmapIoSpace((PVOID)v_pGPIOregs);
        v_pGPIOregs = NULL;
    }

    if(v_pKEYIFregs)
    {
        DrvLib_UnmapIoSpace((PVOID)v_pKEYIFregs);
        v_pKEYIFregs = NULL;
    }

    KBDMSG(KEY_FUNC, (TEXT("--KeybdDriverInitializeAddresses[FAILED!!!]\r\n")));
    
    return FALSE;
}

/*****************************************************************************
*    Function Name : VarInit, AreAllKeysUp
*    Function Desc  : Miscellaneous Function
*
*/
void VarInit(void)
{
    int i;

    for( i=0; i<SIZE_KEY; i++)
    {
        KeyChange[i].Mask = 0;
        KeyChange[i].Cnt  = 0;
    }
}

BOOL AreAllKeysUp(void)
{
    DWORD tmp = 0, tmp1 = 0, i;

    for(i=0;i<SIZE_COLS;i++)
    {
        tmp |= KeyState[i];
        tmp1 |= ChangeState[i];
    }

    return (tmp || tmp1)? FALSE:TRUE;
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : _KScan_ProcState
*    Function Desc  : Handle KeyMatrix State
*
*/
//- kidx  : column number
//- idx   : scan code table index
//- key   : scan code
//- press : press state (FALSE : pressed,  TRUE : released)
DWORD _KScan_ProcState(int kidx, int idx, PDWORD key, PBOOL press)
{
    int val, i;
    DWORD count = 0;
    int mask;

    val = ChangeState[kidx];				// row values for the column

	
    for(i=0;i<SIZE_BITS;i++)
    {
        mask = 1<<i;						// select a row

        if( (KeyState[kidx] & mask) && (KeyCode[idx].Type == KCODE_TYPE_SL) && (KeyCode[idx].Fin == 0) )
        {
 			// the SL key was pressed
 			
            if( (KeyCode[idx].TimeoutCnt == CNT_LONGKEY) )
            {
            	// Long key was pressed.
            	
                // key down
                *key++ = KeyCode[idx].Scan | SCAN_EXT;
                *press++ = FALSE;
                // key up
                *key++ = KeyCode[idx].Scan | SCAN_EXT;
                *press++ = TRUE;
                count+=2;

                KeyCode[idx].TimeoutCnt = 0;
                KeyCode[idx].Fin = TRUE;
                KBDMSG(KEY_DBG, (TEXT(">>> KSCAN:LONG[%d] - %d, key - 0x%x\r\n"), idx, KeyCode[idx].Scan,*key));
            }
            else
            {
            	// the counter increases while the key is pressed.
                KeyCode[idx].TimeoutCnt++;
            }
        }

        if( val & mask )
        {
	        // A key press state was changed. (pressed or released)
        
            // Need to check whether the key was changed really
            if( KeyChange[idx].Cnt == 0 ) // in counting
            {
                KeyChange[idx].Cnt = CNT_VALIDKEY;
                KeyChange[idx].Mask = ( KeyState[kidx] & mask )? 0: mask;
            }
            else
            {
            // checked key state
                if( KeyChange[idx].Mask != (KeyState[kidx] & mask) )
                {
                    if( --KeyChange[idx].Cnt == 0 )
                    {
                        if( KeyChange[idx].Mask == 0 )
                        {
// Key UP
                            if( KeyCode[idx].Type == KCODE_TYPE_NORMAL )
                            {
                                *key++ = KeyCode[idx].Scan;
                                *press++ = TRUE;
                                count++;

                                KBDMSG(KEY_DBG, (TEXT(">>> KSCAN:UP  [%d] - %d\r\n"), idx, KeyCode[idx].Scan));
                            }
                            else
                            {
                                // KCODE_TYPE_SL
                                if( KeyCode[idx].Fin == FALSE )
                                {
                                    // key down
                                    *key++ = KeyCode[idx].Scan;
                                    *press++ = FALSE;
                                    // key up
                                    *key++ = KeyCode[idx].Scan;
                                    *press++ = TRUE;
                                    count+=2;

                                    KeyCode[idx].Fin = TRUE;

                                    KBDMSG(KEY_DBG, (TEXT(">>> KSCAN:SHORT[%d] - %d\r\n"), idx, KeyCode[idx].Scan));
                                }
                            }

                            KeyState[kidx] &= ~mask;
                        }
                        else
                        {
// Key Down
                            if( KeyCode[idx].Type == KCODE_TYPE_NORMAL )
                            {
                                *key++ = KeyCode[idx].Scan;
                                *press++ = FALSE;
                                count++;

                                KBDMSG(KEY_DBG, (TEXT(">>> KSCAN:DOWN[%d] - %d\r\n"), idx, KeyCode[idx].Scan));
                            }
                            else
                            {
                                // KCODE_TYPE_SL
                                KeyCode[idx].TimeoutCnt = 0;
                                KeyCode[idx].Fin = FALSE;
                            }

                            KeyState[kidx] |= mask;
                        }
                    }
                }
                else
                {
                    KeyChange[idx].Cnt = 0;
                    KBDMSG(KEY_DBG, (TEXT(">>> KSCAN:Must be not occurred[%d] %x, %llx, %llx\r\n"), idx,KeyChange[idx].Mask,KeyState,mask));
                }
            }
        }
        else
        {
            if( KeyChange[idx].Cnt ) // in counting
            {
                KeyChange[idx].Cnt = 0;
                KBDMSG(0, (TEXT(">>> KSCAN:Canceled [%d]\r\n"), idx));
            }
        }
        idx++;
    }
    
#if defined(project_wpc)
    if (count && v_hevtKeyPressed)
    {
        // Signal shell to disable SIP.
        SetEvent(v_hevtKeyPressed);
    }
#endif

    return count;
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KScan_ProcIO
*    Function Desc  : Scan code
*                     Read KEYIF
*
*/
void KScan_ProcIO(void)
{
    int i;
	DWORD dwROW;
	
    for(i = 0 ; i < SIZE_COLS; i++)
    {
    	// Select a column line and make all others to high-z.
        KEYIF_Column_Bitset(0, i);

        Sleep(1);								// Setup time

		dwROW = KEYIF_Row_Read();
		
        ChangeState[i] = KeyState[i]^(~dwROW);

		
        KBDMSG(KEY_USR4, (TEXT("COL %d : ROW %d%d%d%d%d%d%d%d\r\n"), i,
        		(dwROW >> 7) & 0x1,
        		(dwROW >> 6) & 0x1,
        		(dwROW >> 5) & 0x1,
        		(dwROW >> 4) & 0x1,        		
        		(dwROW >> 3) & 0x1,
        		(dwROW >> 2) & 0x1,
        		(dwROW >> 1) & 0x1,
        		(dwROW >> 0) & 0x1));
     }

	// Make all columns LOW to detect key press
    KEYIF_Column_Set(0x00);
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KScan_SetINTMode
*    Function Desc  : Initialize the H/W
*
*/
void KScan_SetINTMode(void)
{
     // select all column - Set Keypad column GPIO to output(low)
    GPIO_CtrlHandler(ENUM_COL, ENUM_AUXFUNC);
	GPIO_PuEnable(ENUM_COL, FALSE);			// Disable default pull-up/pull-down for COLUMN lines

    KEYIF_Column_Set(0x0);

    // configure - Set Keypad row GPIO to [Key PAD ROW]
    GPIO_CtrlHandler(ENUM_ROW, ENUM_AUXFUNC);

#if defined(BSP_HW_ID) && (BSP_HW_ID == 1)
	GPIO_PuEnable(ENUM_ROW, FALSE);
#else
	#if ((MATRIX_LAYOUT == LAYOUT0)||(MATRIX_LAYOUT == LAYOUT2))
		GPIO_PuEnable(ENUM_ROW, FALSE);
	#else
	    GPIO_PuEnable(ENUM_ROW, TRUE);
	#endif
#endif

    // unmask the key interrupt
    KEYIF_Status_Clear();
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KeybdPdd_ToggleKeyNotification
*    Function Desc  : Toggle Key
*
*/
void WINAPI KeybdPdd_ToggleKeyNotification(KEY_STATE_FLAGS  KeyStateFlags)
{
    unsigned int fLights;

    KBDMSG(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;
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : IsrThreadProc
*    Function Desc  : IST of KeyBD D/D
*        Create IST
*        Wait for Event according to the KEYPAD INT
*        KScan_SetIOMode() : Handle H/W
*        KScan_ProcIO() :
*        _KScan_ProcState() :
*
*/
extern UINT v_uiPddId;
extern PFN_KEYBD_EVENT v_pfnKeybdEvent;

BOOL KeyMatrix::IsrThreadProc()
{
    DWORD		dwPriority;
    DWORD		i, step;

    DWORD		rguiScanCode[SIZE_KEY];
    BOOL		rgfKeyUp[SIZE_KEY];
    UINT		cEvents;
    DWORD		ret;
    DWORD		dwTimeout;
    HANDLE		gEventIntr;
    DWORD		irq, sysintr;

	DWORD		dwEventIndex;
	

    KBDMSG(KEY_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));


    ReadRegDWORD( TEXT("HARDWARE\\DEVICEMAP\\KEYBD"), _T("Priority256"), &dwPriority );
    if(dwPriority == 0)
    {
        dwPriority = 145;
    }


    // update the IST priority
    CeSetThreadPriority(GetCurrentThread(), (int)dwPriority);


	// IRQ registration
    irq = IRQ_KEYPAD;
    if (!KernelIoControl(IOCTL_HAL_REQUEST_SYSINTR, &irq, sizeof(UINT32), &sysintr, sizeof(UINT32), NULL))
    {
        KBDERR(TRUE, (TEXT("Failed to get a SYSINTR for the IRQ_KEYPAD.\r\n")));
        sysintr = SYSINTR_UNDEFINED;

        goto CLEAN_UP;
    }

    gEventIntr = CreateEvent(NULL, FALSE, FALSE, NULL);
    if(NULL == gEventIntr)
    {
        KBDERR(TRUE, (TEXT("Failed to create an event.\r\n")));
        goto CLEAN_UP;
    }

    if(InterruptInitialize(sysintr, gEventIntr, NULL, 0) == FALSE)
    {
    	KBDERR(TRUE, (TEXT("Failed to initialize the interrupt.\r\n")));
		goto CLEAN_UP;
	}

    dwTimeout = INFINITE;

    // An infinite loop
    while(1)
    {
		KBDMSG(KEY_DBG, (TEXT("+ Wait for a KEYBD interrupt\r\n")));
		
        ret = WaitForSingleObject(gEventIntr, dwTimeout);

		KBDMSG(KEY_DBG, (TEXT("- Wait for a KEYBD interrupt\r\n")));
        
        if(ret == WAIT_OBJECT_0)
        {
            KBDMSG(KEY_DBG, (TEXT("Got a KEYBD interrupt.\r\n")));
            dwTimeout = TIME_KEYSCAN;
        }

        // WAIT_TIMEOUT

        if(g_bHandleWakeup)
        {
            PowerPolicyNotify(PPN_POWERBUTTONPRESSED, 0);
            g_bHandleWakeup=FALSE;
            KBDMSG(1,(TEXT("IsrThreadProc: WakeUp\r\n")));
        }
        
        // Clear Pressed/Released Interrupt
        KEYIF_Status_Clear();
        // Read the Matrix
        KScan_ProcIO();


        for(i=0, step=0;i< SIZE_COLS;i++, step+=SIZE_ROWS)
        {
            cEvents = _KScan_ProcState(i, step, rguiScanCode, rgfKeyUp);

            if(cEvents)
            {
                for(dwEventIndex = 0; dwEventIndex < cEvents; ++dwEventIndex)
                {
                    v_pfnKeybdEvent(v_uiPddId, rguiScanCode[dwEventIndex], rgfKeyUp[dwEventIndex]);
                    KBDMSG(KEY_DBG, (TEXT("PddID : %x, ScanCode : %x, KeyUp : %d\r\n"), 
                    	v_uiPddId, rguiScanCode[dwEventIndex], rgfKeyUp[dwEventIndex]));
                }
            }
        }

        if(TRUE == AreAllKeysUp())
        {
            dwTimeout = INFINITE;
        }

        InterruptDone(sysintr);
    }// INFINITE LOOP ____________________________________________________________________

CLEAN_UP:

    KBDMSG(KEY_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return FALSE;
    
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KBDISRThread
*    Function Desc  : Keybd IST Wrapper
*        Call KeyMatrix.IsrThreadProc()
*
*/
DWORD KBDISRThread(KeyMatrix *pp2k)
{
    KBDMSG(KEY_FUNC,(TEXT("[KEYBD]KBDISRThread:\r\n")));
    pp2k->IsrThreadProc();
    return 0;
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : IsrThreadStart
*    Function Desc  : IST start function
*
*/
BOOL KeyMatrix::IsrThreadStart()
{
    HANDLE   hthrd;

    KBDMSG(KEY_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));
    hthrd = CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)KBDISRThread,this,0,NULL);
    // Since we don't need the handle, close it now.
    CloseHandle(hthrd);

#if defined(project_wpc)
    v_hevtKeyPressed = CreateEvent(NULL, FALSE, FALSE, TEXT("_KeyPress"));
#endif

    KBDMSG(KEY_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
    return TRUE;
}
/****************************************************************************/


/*****************************************************************************
*    Function Name : KeybdPowerOn
*    Function Desc  : Power on function
*        Key array (mask, cnt) initialization, GPIO, Interrupt Initialization
*
*/
BOOL KeyMatrix::KeybdPowerOn()
{
    KBDMSG(KEY_FUNC,(TEXT("++[KEYBD]KeyMatrix::KeybdPowerOn\r\n")));
    
#if 0
	// TODO : EINT wakeup test code (ROW0 ~ ROW3)
    Clear_EXTINT(v_pGPIOregs, EXT_INT_24);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_25);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_26);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_27);
    
    Mask_EXTINT(v_pGPIOregs, EXT_INT_24);
    Mask_EXTINT(v_pGPIOregs, EXT_INT_25);
    Mask_EXTINT(v_pGPIOregs, EXT_INT_26);
    Mask_EXTINT(v_pGPIOregs, EXT_INT_27);
#endif

    //
    // enable the Keypad Clock (PCLK)
    //
	DWORD dwIPIndex;
	DWORD dwBytes;

	if(g_hPwrControl == INVALID_HANDLE_VALUE)
	{
		// Open a POWERCONTROL device
	    g_hPwrControl = CreateFile( L"PWC0:", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
	    if (INVALID_HANDLE_VALUE == g_hPwrControl)
	    {
	        KBDERR(TRUE, (TEXT("Failed to open PWC0!\r\n")));
	        goto CLEAN_UP;
	    }
	}

	// Turn off the clock
	dwIPIndex = CLK_IP3_KEYIF;
	if(!DeviceIoControl(g_hPwrControl, IOCTL_PWRCON_SET_CLOCK_ON, &dwIPIndex, sizeof(DWORD), NULL, 0, &dwBytes, NULL))
	{
		KBDERR(TRUE, (TEXT("Failed to turn on the clock of KEYIF!\r\n")));
	}




    v_pKEYIFregs->KEYIFCON = WAKEUPEN_EN|INT_F_EN|INT_R_DIS|DF_EN_EN|FC_EN_EN;

    //Keypad interfae debouncing filter clock division register
    v_pKEYIFregs->KEYIFFC = FC_DIV_VAL(FT_CLK_DIV);

    VarInit();
    KScan_SetINTMode();

CLEAN_UP:
    KBDMSG(KEY_FUNC,(TEXT("--[KEYBD]KeyMatrix::KeybdPowerOn\r\n")));
    return(TRUE);
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : KeybdPowerOff
*    Function Desc  : Power off function
*        Mask KEYIF INT, Column Low
*
*/
BOOL KeyMatrix::KeybdPowerOff()
{
    KBDMSG(KEY_PM, (TEXT("+%s\r\n"), _T(__FUNCTION__)));
    
    // Clear Pressed/Released Interrupt
    KEYIF_Status_Clear();


#if (S5PV210_EVT > 0)
    // select all column - Set Keypad column GPIO to output(low)
    GPIO_CtrlHandler(ENUM_COL, ENUM_AUXFUNC);

    KEYIF_Column_Set(0x0);
#else
// Workaround : set KEYIF_COLx to GPIO_OUTPUT.
	GPIO_CtrlHandler(ENUM_COL, ENUM_OUTPUT);

#if (MATRIX_LAYOUT == LAYOUT0) || (MATRIX_LAYOUT == LAYOUT2)
	Set_PinData(v_pGPIOregs, KEYIF_COL0, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL1, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL2, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL3, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL4, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL5, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL6, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL7, 0);
#elif (MATRIX_LAYOUT == LAYOUT1)
	Set_PinData(v_pGPIOregs, KEYIF_COL3, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL4, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL5, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL6, 0);
	Set_PinData(v_pGPIOregs, KEYIF_COL7, 0);
#elif (MATRIX_LAYOUT == LAYOUT3)
	Set_PinData(v_pGPIOregs, KBC0, 0);
	Set_PinData(v_pGPIOregs, KBC1, 0);
	Set_PinData(v_pGPIOregs, KBC2, 0);
	Set_PinData(v_pGPIOregs, KBC3, 0);
#endif

#endif


#if 1
	// KEYIF wakeup
    // configure - Set Keypad row GPIO to [Key PAD ROW]
    GPIO_CtrlHandler(ENUM_ROW, ENUM_AUXFUNC);

#if defined(BSP_HW_ID) && (BSP_HW_ID == 1)
	GPIO_PuEnable(ENUM_ROW, FALSE);
#else
    GPIO_PuEnable(ENUM_ROW, TRUE);
#endif	

#else

	// EXTINT wakeup test (ROW0 ~ ROW3)
	GPIO_CtrlHandler(ENUM_ROW, ENUM_EXTINT);
	GPIO_PuEnable(ENUM_ROW, TRUE);

	Set_EXTINT_TRLVL(v_pGPIOregs, EXT_INT_24, sgip_LOW_LEVEL);
	Set_EXTINT_TRLVL(v_pGPIOregs, EXT_INT_25, sgip_LOW_LEVEL);
	Set_EXTINT_TRLVL(v_pGPIOregs, EXT_INT_26, sgip_LOW_LEVEL);
	Set_EXTINT_TRLVL(v_pGPIOregs, EXT_INT_27, sgip_LOW_LEVEL);

	Set_EXTINT_FILTER(v_pGPIOregs, EXT_INT_24, sgip_DELAY_FLT, 0);
	Set_EXTINT_FILTER(v_pGPIOregs, EXT_INT_25, sgip_DELAY_FLT, 0);
	Set_EXTINT_FILTER(v_pGPIOregs, EXT_INT_26, sgip_DELAY_FLT, 0);
	Set_EXTINT_FILTER(v_pGPIOregs, EXT_INT_27, sgip_DELAY_FLT, 0);
	
    Clear_EXTINT(v_pGPIOregs, EXT_INT_24);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_25);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_26);
    Clear_EXTINT(v_pGPIOregs, EXT_INT_27);
    
    Unmask_EXTINT(v_pGPIOregs, EXT_INT_24);
    Unmask_EXTINT(v_pGPIOregs, EXT_INT_25);
    Unmask_EXTINT(v_pGPIOregs, EXT_INT_26);
    Unmask_EXTINT(v_pGPIOregs, EXT_INT_27);
	
#endif



	//Clock Off
	DWORD dwIPIndex;
	DWORD dwBytes;

	if(g_hPwrControl == INVALID_HANDLE_VALUE)
	{
		// Open a POWERCONTROL device
	    g_hPwrControl = CreateFile( L"PWC0:", GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);
	    if (INVALID_HANDLE_VALUE == g_hPwrControl)
	    {
	        KBDERR(TRUE, (TEXT("Failed to open PWC0!\r\n")));
	        goto CLEAN_UP;
	    }
	}

	// Turn off the clock
	dwIPIndex = CLK_IP3_KEYIF;
	if(!DeviceIoControl(g_hPwrControl, IOCTL_PWRCON_SET_CLOCK_OFF, &dwIPIndex, sizeof(DWORD), NULL, 0, &dwBytes, NULL))
	{
		KBDERR(TRUE, (TEXT("Failed to turn off the clock of KEYIF!\r\n")));
	}


	
CLEAN_UP:

    KBDMSG(KEY_PM, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
    return(TRUE);
}
/****************************************************************************/

/*****************************************************************************
*    Function Name : GPIO Handling function
*    Function Desc  : GPIO_PuEnable, GPIO_CtrlHandler
*            Pull up Enable/Disable
*            GPIO Control register configuration only related to KEYPAD
*            GPIO Data register setting only related to KEYPAD
*
*/
/**
    [iClass] 0: Column, 1: Row
    [bFlag] 0: Pull up Enable, 1 : Pull up Disable
*/
static void GPIO_PuEnable(ENUM_COL_ROW iClass, bool bFlag)
{
#if ((MATRIX_LAYOUT == LAYOUT0)||(MATRIX_LAYOUT == LAYOUT2))
    if(iClass == ENUM_COL)    // Column setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL0, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL1, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL2, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL3, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL4, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL5, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL6, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL7, sgip_PULL_UP);
        }
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL0, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL1, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL2, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL3, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL4, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL5, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL6, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL7, sgip_PULL_DISABLE);
        }
    }
    else         // Row Setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW0, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW1, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW2, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW3, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW4, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW5, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW6, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW7, sgip_PULL_UP);
       	}
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW0, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW1, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW2, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW3, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW4, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW5, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW6, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW7, sgip_PULL_DISABLE);
        }
    }
#elif (MATRIX_LAYOUT == LAYOUT1)
    if(iClass == ENUM_COL)    // Column setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL3, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL4, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL5, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL6, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL7, sgip_PULL_UP);
        }
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL3, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL4, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL5, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL6, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_COL7, sgip_PULL_DISABLE);
        }
    }
    else         // Row Setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW0, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW1, sgip_PULL_UP);
       	}
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW0, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KEYIF_ROW1, sgip_PULL_DISABLE);
        }
    }
#elif (MATRIX_LAYOUT == LAYOUT3)
    if(iClass == ENUM_COL)    // Column setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KBC0, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBC1, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBC2, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBC3, sgip_PULL_UP);
        }
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KBC0, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBC1, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBC2, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBC3, sgip_PULL_DISABLE);
        }
    }
    else         // Row Setting
    {
        if(bFlag)        // Pull up Enable
        {
			Set_PinPullUD(v_pGPIOregs, KBR0, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBR1, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBR2, sgip_PULL_UP);
			Set_PinPullUD(v_pGPIOregs, KBR3, sgip_PULL_UP);
       	}
        else         // Pull up Disable
        {
			Set_PinPullUD(v_pGPIOregs, KBR0, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBR1, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBR2, sgip_PULL_DISABLE);
			Set_PinPullUD(v_pGPIOregs, KBR3, sgip_PULL_DISABLE);
        }
    }
#endif


	
}

/**
    [iClass] 0: Column, 1: Row
    [iLevel] 0: INPUT, 1 : OUTPUT, 2 : Aux. Function, 3 : Reserved
*/

static void GPIO_CtrlHandler(ENUM_COL_ROW iClass, ENUM_GPIO_FUNC iLevel)
{
#if ((MATRIX_LAYOUT == LAYOUT0)||(MATRIX_LAYOUT == LAYOUT2))
    if(iClass == ENUM_COL)    // Column setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH20_Input);
			Set_PinFunction(v_pGPIOregs, GPH21_Input);
			Set_PinFunction(v_pGPIOregs, GPH22_Input);
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
			Set_PinFunction(v_pGPIOregs, GPH24_Input);
			Set_PinFunction(v_pGPIOregs, GPH25_Input);
			Set_PinFunction(v_pGPIOregs, GPH26_Input);
			Set_PinFunction(v_pGPIOregs, GPH27_Input);
            break;
			
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH20_Output);
			Set_PinFunction(v_pGPIOregs, GPH21_Output);
			Set_PinFunction(v_pGPIOregs, GPH22_Output);
			Set_PinFunction(v_pGPIOregs, GPH23_Output);
			Set_PinFunction(v_pGPIOregs, GPH24_Output);
			Set_PinFunction(v_pGPIOregs, GPH25_Output);
			Set_PinFunction(v_pGPIOregs, GPH26_Output);
			Set_PinFunction(v_pGPIOregs, GPH27_Output);
            break;
			
        case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KEYIF_COL0);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL1);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL2);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL3);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL4);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL5);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL6);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL7);
            break;

		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH20_EXT_INT_16);
			Set_PinFunction(v_pGPIOregs, GPH21_EXT_INT_17);
			Set_PinFunction(v_pGPIOregs, GPH22_EXT_INT_18);
			Set_PinFunction(v_pGPIOregs, GPH23_EXT_INT_19);
			Set_PinFunction(v_pGPIOregs, GPH24_EXT_INT_20);
			Set_PinFunction(v_pGPIOregs, GPH25_EXT_INT_21);
			Set_PinFunction(v_pGPIOregs, GPH26_EXT_INT_22);
			Set_PinFunction(v_pGPIOregs, GPH27_EXT_INT_23);
            break;
            
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH20_Input);
			Set_PinFunction(v_pGPIOregs, GPH21_Input);
			Set_PinFunction(v_pGPIOregs, GPH22_Input);
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
			Set_PinFunction(v_pGPIOregs, GPH24_Input);
			Set_PinFunction(v_pGPIOregs, GPH25_Input);
			Set_PinFunction(v_pGPIOregs, GPH26_Input);
			Set_PinFunction(v_pGPIOregs, GPH27_Input);
            break;
        }
    }
    else if(iClass == ENUM_ROW)        // Row Setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
			Set_PinFunction(v_pGPIOregs, GPH32_Input);
			Set_PinFunction(v_pGPIOregs, GPH33_Input);
			Set_PinFunction(v_pGPIOregs, GPH34_Input);
			Set_PinFunction(v_pGPIOregs, GPH35_Input);
			Set_PinFunction(v_pGPIOregs, GPH36_Input);
			Set_PinFunction(v_pGPIOregs, GPH37_Input);
            break;
			
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Output);
			Set_PinFunction(v_pGPIOregs, GPH31_Output);
			Set_PinFunction(v_pGPIOregs, GPH32_Output);
			Set_PinFunction(v_pGPIOregs, GPH33_Output);
			Set_PinFunction(v_pGPIOregs, GPH34_Output);
			Set_PinFunction(v_pGPIOregs, GPH35_Output);
			Set_PinFunction(v_pGPIOregs, GPH36_Output);
			Set_PinFunction(v_pGPIOregs, GPH37_Output);
            break;
			
        case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW0);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW1);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW2);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW3);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW4);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW5);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW6);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW7);
            break;

		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH30_EXT_INT_24);
			Set_PinFunction(v_pGPIOregs, GPH31_EXT_INT_25);
			Set_PinFunction(v_pGPIOregs, GPH32_EXT_INT_26);
			Set_PinFunction(v_pGPIOregs, GPH33_EXT_INT_27);
			Set_PinFunction(v_pGPIOregs, GPH34_EXT_INT_28);
			Set_PinFunction(v_pGPIOregs, GPH35_EXT_INT_29);
			Set_PinFunction(v_pGPIOregs, GPH36_EXT_INT_30);
			Set_PinFunction(v_pGPIOregs, GPH37_EXT_INT_31);
            break;
            
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
			Set_PinFunction(v_pGPIOregs, GPH32_Input);
			Set_PinFunction(v_pGPIOregs, GPH33_Input);
			Set_PinFunction(v_pGPIOregs, GPH34_Input);
			Set_PinFunction(v_pGPIOregs, GPH35_Input);
			Set_PinFunction(v_pGPIOregs, GPH36_Input);
			Set_PinFunction(v_pGPIOregs, GPH37_Input);
            break;
        }
    }
    else
    {
        KBDMSG(1,(TEXT("Invalid Parameter\r\n")));
    }
#elif (MATRIX_LAYOUT == LAYOUT1)
    if(iClass == ENUM_COL)    // Column setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
			Set_PinFunction(v_pGPIOregs, GPH24_Input);
			Set_PinFunction(v_pGPIOregs, GPH25_Input);
			Set_PinFunction(v_pGPIOregs, GPH26_Input);
			Set_PinFunction(v_pGPIOregs, GPH27_Input);
            break;
			 
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH23_Output);
			Set_PinFunction(v_pGPIOregs, GPH24_Output);
			Set_PinFunction(v_pGPIOregs, GPH25_Output);
			Set_PinFunction(v_pGPIOregs, GPH26_Output);
			Set_PinFunction(v_pGPIOregs, GPH27_Output);
			break;
			
          case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KEYIF_COL3);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL4);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL5);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL6);
			Set_PinFunction(v_pGPIOregs, KEYIF_COL7);
            break;
            
		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH23_EXT_INT_19);
			Set_PinFunction(v_pGPIOregs, GPH24_EXT_INT_20);
			Set_PinFunction(v_pGPIOregs, GPH25_EXT_INT_21);
			Set_PinFunction(v_pGPIOregs, GPH26_EXT_INT_22);
			Set_PinFunction(v_pGPIOregs, GPH27_EXT_INT_23);
            break;
			
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
			Set_PinFunction(v_pGPIOregs, GPH24_Input);
			Set_PinFunction(v_pGPIOregs, GPH25_Input);
			Set_PinFunction(v_pGPIOregs, GPH26_Input);
			Set_PinFunction(v_pGPIOregs, GPH27_Input);
            break;
        }
    }
    else if(iClass == ENUM_ROW)        // Row Setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
            break;
			
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Output);
			Set_PinFunction(v_pGPIOregs, GPH31_Output);
            break;
			
        case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW0);
			Set_PinFunction(v_pGPIOregs, KEYIF_ROW1);
            break;

		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH30_EXT_INT_24);
			Set_PinFunction(v_pGPIOregs, GPH31_EXT_INT_25);
            break;
            
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
            break;
        }
    }
    else
    {
        KBDMSG(1,(TEXT("Invalid Parameter\r\n")));
    }
#elif (MATRIX_LAYOUT == LAYOUT3)
    if(iClass == ENUM_COL)    // Column setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH20_Input);
			Set_PinFunction(v_pGPIOregs, GPH21_Input);
			Set_PinFunction(v_pGPIOregs, GPH22_Input);
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
            break;
			 
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH20_Output);
			Set_PinFunction(v_pGPIOregs, GPH21_Output);
			Set_PinFunction(v_pGPIOregs, GPH22_Output);
			Set_PinFunction(v_pGPIOregs, GPH23_Output);
			break;
			
		case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KBC0);
			Set_PinFunction(v_pGPIOregs, KBC1);
			Set_PinFunction(v_pGPIOregs, KBC2);
			Set_PinFunction(v_pGPIOregs, KBC3);
            break;

		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH20_EXT_INT_16);
			Set_PinFunction(v_pGPIOregs, GPH21_EXT_INT_17);
			Set_PinFunction(v_pGPIOregs, GPH22_EXT_INT_18);
			Set_PinFunction(v_pGPIOregs, GPH23_EXT_INT_19);
            break;
			
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH20_Input);
			Set_PinFunction(v_pGPIOregs, GPH21_Input);
			Set_PinFunction(v_pGPIOregs, GPH22_Input);
			Set_PinFunction(v_pGPIOregs, GPH23_Input);
            break;
        }
    }
    else if(iClass == ENUM_ROW)        // Row Setting
    {
        switch(iLevel)
        {
        case ENUM_INPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
			Set_PinFunction(v_pGPIOregs, GPH32_Input);
			Set_PinFunction(v_pGPIOregs, GPH33_Input);
            break;
			
        case ENUM_OUTPUT :
			Set_PinFunction(v_pGPIOregs, GPH30_Output);
			Set_PinFunction(v_pGPIOregs, GPH31_Output);
			Set_PinFunction(v_pGPIOregs, GPH32_Output);
			Set_PinFunction(v_pGPIOregs, GPH33_Output);
            break;
			
        case ENUM_AUXFUNC :
			Set_PinFunction(v_pGPIOregs, KBR0);
			Set_PinFunction(v_pGPIOregs, KBR1);
			Set_PinFunction(v_pGPIOregs, KBR2);
			Set_PinFunction(v_pGPIOregs, KBR3);
            break;

		case ENUM_EXTINT:
			Set_PinFunction(v_pGPIOregs, GPH30_EXT_INT_24);
			Set_PinFunction(v_pGPIOregs, GPH31_EXT_INT_25);
            break;
            
        default :    //ENUM_RESERVED
			Set_PinFunction(v_pGPIOregs, GPH30_Input);
			Set_PinFunction(v_pGPIOregs, GPH31_Input);
			Set_PinFunction(v_pGPIOregs, GPH32_Input);
			Set_PinFunction(v_pGPIOregs, GPH33_Input);
            break;
        }
    }
    else
    {
        KBDMSG(1,(TEXT("Invalid Parameter\r\n")));
    }
#endif
}

/**
    [dVal] Value of KBC
*/
static void KEYIF_Column_Set(DWORD dVal)
{
    v_pKEYIFregs->KEYIFCOL = (dVal & 0xff);
}

static void KEYIF_Column_Bitset(bool bVal, int cIdx)
{
#if ((MATRIX_LAYOUT == LAYOUT0)||(MATRIX_LAYOUT == LAYOUT2)||(MATRIX_LAYOUT == LAYOUT3))
    if(bVal)
    {
 		v_pKEYIFregs->KEYIFCOL = ((0xFF & ~(1 << cIdx)) << 8) | (0x1 << cIdx);
    }
    else
    {
 		v_pKEYIFregs->KEYIFCOL = ((0xFF & ~(1 << cIdx)) << 8);
    }
#elif (MATRIX_LAYOUT == LAYOUT1)
    if(bVal)
    {
 		v_pKEYIFregs->KEYIFCOL = ((0xFF & ~(1 << (cIdx + 3))) << 8) | (0x1 << (cIdx + 3));
    }
    else
    {
 		v_pKEYIFregs->KEYIFCOL = ((0xFF & ~(1 << (cIdx + 3))) << 8);
    }
#endif

}

static DWORD KEYIF_Row_Read(void)
{
	return v_pKEYIFregs->KEYIFROW | ~((1 << SIZE_ROWS) - 1);
}

static void KEYIF_Status_Clear(void)
{
    v_pKEYIFregs->KEYIFSTSCLR = CLEAR_P_INT|CLEAR_R_INT;    // Clear Pressed/Released Interrupt
}

