//
// 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.
//
/*++
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:

    Platform dependent TOUCH initialization functions

rev:
Notes:
--*/

#include "tsp.h"

#ifdef TSP_QT602240
#include "qt602240.h"
#endif


#define PUBLIC
#define PRIVATE static

#ifndef OAL_INTR_FORCE_STATIC
#define OAL_INTR_FORCE_STATIC   (1 << 2)
#endif

DWORD gIntrTouch = SYSINTR_NOP;
DWORD gIntrTouchChanged = SYSINTR_NOP;

extern "C" const int MIN_CAL_COUNT = 1;

// for Sleep/WakeUp
static BOOL bSlept;


extern INT g_TSPCurSampleRateSetting;
extern BOOL g_bTSPInitialized;
extern BOOL g_bTSPTouchDown;

extern volatile PMU_MISC_REG		*v_pPMUMISCregs;
extern volatile GPIO_REG			*v_pGPIOregs;
extern volatile TSADC_REG 			*v_pTSADC0regs;
extern volatile TSADC_REG			*v_pTSADC1regs;
extern volatile VIC_REG				*v_pVIC0regs;
extern volatile VIC_REG				*v_pVIC2regs;
extern volatile VIC_REG				*v_pVIC3regs;
extern volatile PWM_REG				*v_pPWMregs;
extern volatile CMU_CLK_REG			*v_pCMUCLKregs;


// TODO : temp
#ifdef TSP_QT602240
extern QT602240_TouchMessage_t		g_TouchMessage;
#endif


PRIVATE BOOL TSP_CalibrationPointGet(TPDC_CALIBRATION_POINT *pTCP);


// DdsiTouchPanelGetDeviceCaps()
// This function queries capabilities of the touch screen device.
//
PUBLIC BOOL
DdsiTouchPanelGetDeviceCaps(
    INT    iIndex,         // [in]  Capability to query
    LPVOID lpOutput     // [out] Pointer to one or more memory locations to place the queried information.
    )
{
    BOOL bReturn = TRUE;

    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

    if (!lpOutput)
    {
        TSPERR(TRUE, (TEXT("[TSP:ERR] TouchPanelGetDeviceCaps: ERROR_INVALID_PARAMETER\r\n")));
        SetLastError(ERROR_INVALID_PARAMETER);
        bReturn = FALSE;
    }

    if ( bReturn )
    {
        switch( iIndex )
        {
            case TPDC_SAMPLE_RATE_ID:
            // Returns the sample rate.
            {
                TPDC_SAMPLE_RATE *pTSR = (TPDC_SAMPLE_RATE *)lpOutput;
                TSPMSG(TCH_DBG, (TEXT("TouchPanelGetDeviceCaps::TPDC_SAMPLE_RATE_ID\r\n")));

                pTSR->SamplesPerSecondLow      = TSP_SAMPLE_RATE_LOW;
                pTSR->SamplesPerSecondHigh     = TSP_SAMPLE_RATE_HIGH;
                pTSR->CurrentSampleRateSetting = g_TSPCurSampleRateSetting;

                break;
            }
            case TPDC_CALIBRATION_POINT_ID:
            // Returns the x and y coordinates of the required calibration point.
            {
                TSPMSG(TCH_DBG, (TEXT("TouchPanelGetDeviceCaps::TPDC_CALIBRATION_POINT_ID\r\n")));
                return(TSP_CalibrationPointGet((TPDC_CALIBRATION_POINT*)lpOutput));

                break;
            }
            case TPDC_CALIBRATION_POINT_COUNT_ID:
            // Returns the number of calibration points used to calibrate the touch screen.
            {
                TPDC_CALIBRATION_POINT_COUNT *pTCPC = (TPDC_CALIBRATION_POINT_COUNT*)lpOutput;
                TSPMSG(TCH_DBG, (TEXT("TouchPanelGetDeviceCaps::TPDC_CALIBRATION_POINT_COUNT_ID\r\n")));

                pTCPC->flags              = 0;
                pTCPC->cCalibrationPoints = 5;

                break;
            }
            default:
            {
                TSPERR(TRUE, (TEXT("[TSP:ERR] TouchPanelGetDeviceCaps: ERROR_INVALID_PARAMETER\r\n")));
                SetLastError(ERROR_INVALID_PARAMETER);
                bReturn = FALSE;

                break;
            }
        }    // switch    ( iIndex )
    }

    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return bReturn;
}


// DdsiTouchPanelSetMode()
// This function sets information about the touch screen device.
//
PUBLIC BOOL
DdsiTouchPanelSetMode(
    INT iIndex,         // [in] Mode to set
    LPVOID lpInput      // [out] Pointer to one or more memory locations where the update information resides.
    )
{
    BOOL bReturn = TRUE;

    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

    switch(iIndex)
    {
        case TPSM_SAMPLERATE_HIGH_ID:
        // Sets the rample rate to the high rate.
        {
            TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelSetMode::TPSM_SAMPLERATE_HIGH_ID\r\n")));

            g_TSPCurSampleRateSetting = TPDC_SAMPLE_RATE_HIGH;
            TSP_SetPollingRate(TSP_SAMPLE_RATE_HIGH);

            break;
        }
        case TPSM_SAMPLERATE_LOW_ID:
        // Sets the sample rate to the low rate.
        {
            TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelSetMode::TPSM_SAMPLERATE_LOW_ID\r\n")));

            g_TSPCurSampleRateSetting = TPDC_SAMPLE_RATE_LOW;
            TSP_SetPollingRate(TSP_SAMPLE_RATE_LOW);

            break;
        }
        default:
        {
            TSPERR(TRUE, (TEXT("[TSP:ERR] DdsiTouchPanelSetMode: ERROR_INVALID_PARAMETER\r\n")));
            SetLastError( ERROR_INVALID_PARAMETER );
            bReturn = FALSE;

            break;
        }
    }

    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return bReturn;
}


// DdsiTouchPanelEnable()
// This function applies power to the touch screen device and initializes it for operation.
//
PUBLIC BOOL
DdsiTouchPanelEnable(VOID)
{
    BOOL bReturn = TRUE;

    UINT32 Irq[3] = {-1, OAL_INTR_FORCE_STATIC, 0};

    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));


	if(TSP_VirtualAlloc() == FALSE)
	{
		bReturn = FALSE;
		goto ERROR_RETURN;
	}

    // Backup TSADC registers
    TSP_GetDefaultRegs();

	// Turn on TSADC
	TSP_PowerOn(FALSE);

    // Obtain sysintr values from the OAL for the touch and touch changed interrupts.
    TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelEnable: enable touch sysintr.\r\n")));

    bReturn = TSP_GetSysIntrVal(&gIntrTouch, &gIntrTouchChanged, Irq);

    TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelEnable: gIntrTouch [ %d | %x ]\r\n"), gIntrTouch, gIntrTouch));
    TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelEnable: gIntrTouchChanged [ %d | %x ]\r\n"), gIntrTouchChanged, gIntrTouchChanged));

    TSP_ClearInt(TOUCH_DEV);


ERROR_RETURN:

    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return bReturn;
}


// DdsiTouchPanelDisable()
// This function disables the touch screen device.
//
PUBLIC VOID
DdsiTouchPanelDisable(VOID)
{
    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));


#ifdef TSP_CH0
    if (v_pTSADC0regs)
    {
        TSP_PowerOff(FALSE);
    }
#endif

#ifdef TSP_CH1
    if (v_pTSADC1regs)
    {
        TSP_PowerOff(FALSE);
    }
#endif


#ifdef TSP_QT602240
    if (v_pGPIOregs)
    {
        TSP_PowerOff(FALSE);
    }
#endif

    TSP_VirtualFree();

    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
}


// DdsiTouchPanelAttach()
// This function excutes when the MDD's DLL entry point gets a DLL_PROCESS_ATTACH message.
//
LONG
DdsiTouchPanelAttach(VOID)
{
    return (1);
}


// DdsiTouchPanelDetach()
// This function excutes when the MDD's DLL entry point gets a DLL_PROCESS_DETACH message.
//
LONG
DdsiTouchPanelDetach(VOID)
{
    return (0);
}


// DdsiTouchPanelPowerHandler()
// This function indicates to the driver that the system is entering or leaving the suspend state.
//
PUBLIC VOID
DdsiTouchPanelPowerHandler(
    BOOL bOff       // TURE: the system is turning off.    FALSE: the system is turning on.
    )
{
    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));
    if (bOff)
    {
        //TSPMSG(TCH_DBG, (TEXT("Touch PowerOff+\r\n")));
        TSP_PowerOff(TRUE);
        //TSPMSG(TCH_DBG, (TEXT("Touch PowerOff-\r\n")));
    }
    else
    {
        //TSPMSG(TCH_DBG, (TEXT("Touch PowerUp+\r\n")));
        TSP_PowerOn(TRUE);
        TSP_EnableInt(TOUCH_DEV, TRUE);
        //TSPMSG(TCH_DBG, (TEXT("Touch PowerUp-\r\n")));
    }
    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
}


// DdsiTouchPanelGetPoint
// This function returns the most recently acquired point and its associated tip state information.
//
PUBLIC VOID
DdsiTouchPanelGetPoint(
    TOUCH_PANEL_SAMPLE_FLAGS *pTipStateFlags,   // Pointer to where to return the tip state information in TOUCH_PANEL_SAMPLE_FLAGS.
    int *pUncalX,                              // Pointer to where to return the x-coordinate.
    int *pUncalY                               // Pointer to where to return the y-coordinate.
    )
{
    static int x = 0;
    static int y = 0;

    int TmpX = 0;
    int TmpY = 0;

    int TSP_Intr = 0;

#ifdef TOUCH_PRESSURE_DETECTION
	int iTouchPressure;
#endif	

	TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

    if (!pTipStateFlags || !pUncalX || !pUncalY)
    {
        TSPERR(TRUE, (TEXT("DdsiTouchPanelGetPoint: ERROR_INVALID_PARAMETER\r\n")));
        SetLastError(ERROR_INVALID_PARAMETER);
        return;
    }


	*pTipStateFlags = 0;

	
#ifdef TSP_QT602240

	UINT8	ucReportID;
	static BOOL bPenDown = FALSE;
	
	if(QT602240_ReadMessage(&ucReportID, &g_TouchMessage) == FALSE)
	{
		TSPMSG(TCH_INFO, (TEXT("Read Message was failed\r\n")));
		*pTipStateFlags = TouchSampleIgnore;
	}
	else if(QT602240_ReportIDtoObjectType(ucReportID) == TOUCH_MULTITOUCHSCREEN_T9)
	{
		*pUncalX = (g_TouchMessage.ucXPOSMSB << 2) | ((g_TouchMessage.ucXYPOSLSB & 0xC0) >> 6);
		*pUncalY = (g_TouchMessage.ucYPOSMSB << 2) | ((g_TouchMessage.ucXYPOSLSB & 0x0C) >> 2);

		if(g_TouchMessage.ucSTATUS & PRESS)
		{
			// Pen down
			bPenDown = TRUE;
				
			*pTipStateFlags = (TouchSampleValidFlag | TouchSampleDownFlag);
		}
		else if(g_TouchMessage.ucSTATUS & RELEASE)
		{
			// Pen up
			bPenDown = FALSE;

			*pTipStateFlags = (TouchSampleValidFlag);
		}
		else if(g_TouchMessage.ucSTATUS & DETECT)
		{
			// Touch is present on the screen
			*pTipStateFlags = (TouchSampleValidFlag | TouchSampleDownFlag);
		}
		else
		{
			// Invalid touch
			*pTipStateFlags = TouchSampleIgnore;
			TSPMSG(TCH_DBG, (TEXT("Ignore Sample\r\n")));
		}

		if(g_TouchMessage.ucSTATUS & (PRESS | RELEASE | DETECT))
		{
			x = *pUncalX;
			y = *pUncalY;
			TSPMSG(TCH_XY, (TEXT("X : %04d   Y : %04d\r\n"), *pUncalX, *pUncalY));
		}
	}
	else
	{
		// Another type of message
		// We don't consider that.
		*pTipStateFlags = TouchSampleIgnore;

		if(bPenDown == TRUE)
		{
			*pTipStateFlags |= (TouchSampleValidFlag | TouchSampleDownFlag);
			*pUncalX = x;
			*pUncalY = y;				
		}

		TSPERR(1, (TEXT("Read Another Message 0x%X\r\n"), *pTipStateFlags));
	}

	TSP_ClearInt(TOUCH_DEV);
   	InterruptDone(gIntrTouch);

#else	// TSP_CH0 or TSP_CH1

	TSP_Intr = TSP_CheckInt();

    if (TSP_Intr == TOUCH_DEV)  // SYSINTR_TOUCH
	{
	    *pTipStateFlags = TouchSampleValidFlag; // Indicator for a valid reading.

        if (TSP_GetTSPState() == PEN_UP)
        {
            TSPMSG(TCH_DBG, (TEXT("PEN UP\r\n")));

            TSP_SampleStop();
        	InterruptDone(gIntrTouchChanged);			// There may be a pending timer interrupt.
        												// InterruptDone() is required to re-enable the timer interrupt.

            g_bTSPTouchDown = FALSE;

            *pUncalX = x;
            *pUncalY = y;

            TmpX = -1;
            TmpY = -1;

            TSP_Filtering(&TmpX, &TmpY);				// Clear S/W filter

            TSP_DetectPnDn();							// Wait for PEN_DOWN interrupt
        }
        else
        {

#ifdef TOUCH_PRESSURE_DETECTION
			// Pressure check
			iTouchPressure = TSP_GetPressure(PEN_UP);		// get the touch pressure

			TSP_ClearPenHistory(PEN_UP);							// clear PEN_UP interrupt history
			

			while(1)
			{
				TSPMSG(TCH_XY, (TEXT("Touch pressure = %04d\r\n"), iTouchPressure));
				RETAILMSG(1, (TEXT("Touch pressure = %04d\r\n"), iTouchPressure));
				
				if(iTouchPressure < 0)
				{
					// Invalid pressure value
					// Ignore this
				}
				else if(iTouchPressure < PEN_DOWN_PRESSURE_THRESHOLD)
				{
					// Touch pressure becomes enough to sample the X/Y position
					break;
				}

				if (TSP_GetPenHistory(PEN_UP) == TRUE)
				{
					// no valid touch between pen down and pen up.
					TSP_DetectPnDn();
					break;
				}

				iTouchPressure = TSP_GetPressure(PEN_UP);

				Sleep(1);			// Some delay is required to detect PEN UP
			}				
						
			if(iTouchPressure >= PEN_DOWN_PRESSURE_THRESHOLD)
			{
				TSPMSG(TCH_INFO, (TEXT("Pen down pressure is low. This sample is ignored.\r\n")));
				*pTipStateFlags = TouchSampleIgnore;    // Flag to ignore the sample.
			}
			else
#endif			
			{
	            g_bTSPTouchDown = TRUE;


	            if (!TSP_GetXY(&x, &y))
	            {
	                *pTipStateFlags = TouchSampleIgnore;    // Flag to ignore the sample.
	            }
	            else
	            {
	                if ( TSP_Filtering(&x, &y) )
	                {
	                    *pUncalX = x;
	                    *pUncalY = y;
	                }
	                else
	                {
	                    *pTipStateFlags |= TouchSampleIgnore;   // Flag to ignore the sample.
    	            }

	                *pTipStateFlags |= TouchSampleDownFlag;     // State of finger or stylus.

    	            TSPMSG(TCH_XY, (TEXT("X : %04d  Y : %04d\r\n"), x, y));
				}              

		        TSP_SampleStart();
			}
     
        }

        TSP_ClearInt(TOUCH_DEV);        // Clear Timer Interrupt
        InterruptDone(gIntrTouch);
	}
	else if(TSP_Intr == TIMER_DEV)  // SYSINTR_TOUCH_CHANGED
    {
        TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelGetPoint: SYSINTR_TOUCH_CHANGED Interrupt Case\r\n")));

        if (g_bTSPTouchDown)
        {
            if (!TSP_GetXY(&TmpX, &TmpY))
            {
                *pTipStateFlags = TouchSampleIgnore;
            }
            else
            {
                if(TSP_Filtering(&TmpX, &TmpY))
                {
                    TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelGetPoint: Valid Touch Pen\r\n")));
                    *pTipStateFlags = TouchSampleValidFlag | TouchSampleDownFlag;   // Indicator for a valid reading and State of finger or stylus.
                    *pTipStateFlags &= ~TouchSampleIgnore;  // ~(Flag to ignore the sample)
                }
                else // Invalid touch pen
                {
                    TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelGetPoint: Invalid touch pen\r\n")));
                    *pTipStateFlags = TouchSampleValidFlag; // Indicator for a valid reading.
                    *pTipStateFlags |= TouchSampleIgnore;   // Flag to ignore the sample
                }

                *pUncalX = x= TmpX;
                *pUncalY = y= TmpY;

				//DBGMSG(1, (TEXT("%04d %04d\r\n"), x, y));
				
                TSPMSG(TCH_DBG, (TEXT("DdsiTouchPanelGetPoint: *Final:*pUncalX=%d, *pUncalY=%d\r\n"), *pUncalX, *pUncalY));
            }
        }
        else
        {
            *pTipStateFlags = TouchSampleIgnore;

            TmpX = -1;
            TmpY = -1;

            TSP_Filtering(&TmpX, &TmpY);
            TSP_SampleStop();
        }

        TSP_ClearInt(TIMER_DEV);    // Clear Timer Interrupt
        InterruptDone(gIntrTouchChanged);
        
    }

#endif
	
	TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));
}


// TSP_CalibrationPointGet()
// Returns the x and y coordinates of the required calibration point.
//
PRIVATE BOOL
TSP_CalibrationPointGet(TPDC_CALIBRATION_POINT *pTCP)
{
    INT cDisplayWidth    = pTCP->cDisplayWidth;
    INT cDisplayHeight   = pTCP->cDisplayHeight;

    int    CalibrationRadiusX = cDisplayWidth  / 20;
    int    CalibrationRadiusY = cDisplayHeight / 20;

    TSPMSG(TCH_FUNC, (TEXT("+%s\r\n"), _T(__FUNCTION__)));

    switch( pTCP -> PointNumber )
    {
        case 0:
        {
            pTCP->CalibrationX = cDisplayWidth  / 2;
            pTCP->CalibrationY = cDisplayHeight / 2;
            break;
        }
        case 1:
        {
            pTCP->CalibrationX = CalibrationRadiusX * 2;
            pTCP->CalibrationY = CalibrationRadiusY * 2;
            break;
        }
        case 2:
        {
            pTCP->CalibrationX = CalibrationRadiusX * 2;
            pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
            break;
        }
        case 3:
        {
            pTCP->CalibrationX = cDisplayWidth  - CalibrationRadiusX * 2;
            pTCP->CalibrationY = cDisplayHeight - CalibrationRadiusY * 2;
            break;
        }
        case 4:
        {
            pTCP->CalibrationX = cDisplayWidth - CalibrationRadiusX * 2;
            pTCP->CalibrationY = CalibrationRadiusY * 2;
            break;
        }
        default:
        {
            pTCP->CalibrationX = cDisplayWidth  / 2;
            pTCP->CalibrationY = cDisplayHeight / 2;

            SetLastError(ERROR_INVALID_PARAMETER);
            return FALSE;
        }
    }

    TSPMSG(TCH_FUNC, (TEXT("-%s\r\n"), _T(__FUNCTION__)));

    return TRUE;
}


