//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this sample source code is subject to the terms of the Microsoft
// license agreement under which you licensed this sample source code. If
// you did not accept the terms of the license agreement, you are not
// authorized to use this sample source code. For the terms of the license,
// please see the license agreement between you and Microsoft or, if applicable,
// see the LICENSE.RTF on your install media or the root of your tools installation.
// THE SAMPLE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
//
//
// Copyright (c) Samsung Electronics. Co. LTD.  All rights reserved.
//
/*++
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.

Module Name:    stda_hdmi.c

Abstract:       Implementation of HDMI Middle Level S/W
                This module implements Middle Level HDMI control

Functions:


Notes:


--*/

#include <windows.h>
#include <bsp_cfg.h>    // for reference HCLK, ECLK
#include <register_map.h>
#include "tvout_global.h"
#include "stda_common.h"
#include "stda_context.h"
#include "stda_resource.h"
#include "stda_interrupt.h"
#include "stda_hdmi.h"
#include "Video.h"
#include "audio.h"
#include "Libhdmi.h"
#include "Libedid.h"
#include "Libi2s.h"
#include "hdmi_iic.h"
#include "WaveDevMsg.h"

#define HDMI_DEFAULT_WAIT_MSEC 1000

/*============================================================================*/
// Pre-defined functions
/*============================================================================*/

static BOOL STDA_HDMI_spd_infoframe(PBYTE pBufIn);
static BOOL STDA_HDMI_init_HDCP_en(PBYTE pBufIn);
static BOOL STDA_HDMI_Audeo_en(PBYTE pBufIn);
static BOOL STDA_HDMI_init_audio(PBYTE pBufIn);
static BOOL STDA_HDMI_get_hpd_status(PBYTE pBufOut);
static BOOL STDA_HDMI_wait_hpd_status_change(PBYTE pBufIn, PBYTE pBufOut);
static BOOL STDA_HDMI_get_available_mode(PBYTE pBufOut);
static BOOL STDA_HDMI_get_edid_info(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo);
static BOOL STDA_HDMI_set_get_edid_info(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo, BOOL bSet);


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

void PrintHdmiAvaliableMode()
{

	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo;

	pInfo = &(pPMCtxt->tHdmiAvailableMode);

	if(pInfo->bHDMI_480P_16_9)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_480P_16_9 \n\r")));
	}
	if(pInfo->bHDMI_480P_4_3)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_480P_4_3 \n\r")));
	}
	if(pInfo->bHDMI_576P_16_9)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_576P_16_9 \n\r")));
	}
	if(pInfo->bHDMI_576P_4_3)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_576P_4_3 \n\r")));
	}
	if(pInfo->bHDMI_720P_60_16_9)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_720P_60_16_9 \n\r")));
	}
	if(pInfo->bHDMI_1080P_60_16_9)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_1080P_60_16_9 \n\r")));
	}
	if(pInfo->bHDMI_1080I_60_16_9)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_1080I_60_16_9 \n\r")));
	}
	if(pInfo->bLPCM2CH)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bLPCM2CH \n\r")));
	}
	if(pInfo->bHDMI_CS_RGB)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CS_RGB \n\r")));
	}
	if(pInfo->bHDMI_CS_YCBCR444)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CS_YCBCR444 \n\r")));
	}
	if(pInfo->bHDMI_CS_YCBCR422)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CS_YCBCR422 \n\r")));
	}
	if(pInfo->bHDMI_COLORIMETRY_EXTENDED_xvYCC601)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_COLORIMETRY_EXTENDED_xvYCC601 \n\r")));
	}
	if(pInfo->bHDMI_COLORIMETRY_EXTENDED_xvYCC709)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_COLORIMETRY_EXTENDED_xvYCC709 \n\r")));
	}
	if(pInfo->bHDMI_CD_36_HDMI_CS_RGB)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_36_HDMI_CS_RGB \n\r")));
	}
	if(pInfo->bHDMI_CD_36_HDMI_CS_YCBCR444)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_36_HDMI_CS_YCBCR444 \n\r")));
	}
	if(pInfo->bHDMI_CD_36_HDMI_CS_YCBCR422)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_36_HDMI_CS_YCBCR444 \n\r")));
	}
	if(pInfo->bHDMI_CD_30_HDMI_CS_RGB)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_30_HDMI_CS_RGB \n\r")));
	}
	if(pInfo->bHDMI_CD_30_HDMI_CS_YCBCR444)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_30_HDMI_CS_YCBCR444 \n\r")));
	}
	if(pInfo->bHDMI_CD_30_HDMI_CS_YCBCR422)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_30_HDMI_CS_YCBCR422 \n\r")));
	}
	if(pInfo->bHDMI_CD_24_HDMI_CS_RGB)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_24_HDMI_CS_RGB \n\r")));
	}
	if(pInfo->bHDMI_CD_24_HDMI_CS_YCBCR444)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_24_HDMI_CS_YCBCR444 \n\r")));
	}
	if(pInfo->bHDMI_CD_24_HDMI_CS_YCBCR422)
	{
		DBGMSG(TV_USR2,(_T("[TV_MODE] bHDMI_CD_24_HDMI_CS_YCBCR422 \n\r")));
	}

}

BOOL
STDA_HDMI_API_Proc
(DWORD hOpenContext,
 DWORD dwCode,
 PBYTE pBufIn,
 DWORD dwLenIn,
 PBYTE pBufOut,
 DWORD dwLenOut,
 PDWORD pdwActualOut)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();

    DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_API_Proc(0x%x)\n\r"),dwCode));

    if(dwCode == STDA_HDMI_GET_HPD_STATUS)
    {
        return STDA_HDMI_get_hpd_status(pBufOut);
    }
    else if(dwCode == STDA_HDMI_AVAILABLE_MODE)
    {
        return STDA_HDMI_get_available_mode(pBufOut);
    }

    if(!STDA_resource_compare_TVout_interface(hOpenContext))
    {
        return FALSE;
    }

    switch(dwCode)
    {
    case STDA_HDMI_INIT_SPD_INFOFRAME:
        if(pPMCtxt->bTVoutOutputEnable)
        {
            DBGMSG(TV_USR1,(_T("[TVOUT:ERR] STDA_HDMI_API_Proc() : must not start TVoutIF before initializing TVoutIF parameters\n\r")));
            return FALSE;
        }
        return STDA_HDMI_spd_infoframe(pBufIn);
        break;
    case STDA_HDMI_INIT_HDCP_EN:
        if(pPMCtxt->bTVoutOutputEnable)
        {
            DBGMSG(TV_USR1,(_T("[TVOUT:ERR] STDA_HDMI_API_Proc() : must not start TVoutIF before initializing TVoutIF parameters\n\r")));
            return FALSE;
        }
        return STDA_HDMI_init_HDCP_en(pBufIn);
        break;
	case STDA_HDMI_AUDIO_EN:
        if(pPMCtxt->bTVoutOutputEnable)
        {
            DBGMSG(TV_USR1,(_T("[TVOUT:ERR] STDA_HDMI_API_Proc() : must not start TVoutIF before initializing TVoutIF parameters\n\r")));
            return FALSE;
        }
        return STDA_HDMI_Audeo_en(pBufIn);
        break;
    case STDA_HDMI_INIT_AUDIO:
        if(pPMCtxt->bTVoutOutputEnable)
        {
            DBGMSG(TV_USR1,(_T("[TVOUT:ERR] STDA_HDMI_API_Proc() : must not start TVoutIF before initializing TVoutIF parameters\n\r")));
            return FALSE;
        }
        return STDA_HDMI_init_audio(pBufIn);
        break;
//    case STDA_HDMI_GET_HPD_STATUS:
//        break;
    case STDA_HDMI_WAIT_HPD_STATUS_CHANGE:
        return STDA_HDMI_wait_hpd_status_change(pBufIn, pBufOut);
        break;
//    case STDA_HDMI_AVAILABLE_MODE:
//        return STDA_HDMI_get_available_mode(pBufOut);
//        break;
    default:
        DBGMSG(TV_USR1,(_T("[TVOUT:ERR] STDA_HDMI_API_Proc() : invalid dwCode parameter(%d)\n\r"),dwCode));
        return FALSE;
        break;
    }

    DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_API_Proc(0x%08x)\n\r"),dwCode));

    return TRUE;
}

static BOOL
STDA_HDMI_spd_infoframe
(PBYTE pBufIn)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_spd_infoframe(0x%x)\n\r"),pBufIn));
	
	//RETAILMSG(1,(_T("[TVOUT] ++STDA_HDMI_spd_infoframe(0x%x)\n\r"),pBufIn));
	DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_spd_infoframe(0x%x)\n\r"),pBufIn));

	
    if(!pBufIn)
    {
        DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_spd_infoframe() pBufIn is NULL\n\r")));
			//RETAILMSG(1,(_T("[TVOUT] --STDA_HDMI_spd_infoframe() pBufIn is NULL\n\r")));
        return FALSE;
    }

    memcpy((void *)(&(pPMCtxt->tHdmiSpdInfoFrame)), (const void *)pBufIn,
            sizeof(STDA_ARG_HDMI_SPD_INFOFRAME));

    memcpy((void *)(pPMCtxt->ucSpdHeader),
             (const void *)(pPMCtxt->tHdmiSpdInfoFrame.pucSpdHeader), 3);
    pPMCtxt->tHdmiSpdInfoFrame.pucSpdHeader = pPMCtxt->ucSpdHeader;

    memcpy((void *)(pPMCtxt->ucSpdData),
            (const void *)(pPMCtxt->tHdmiSpdInfoFrame.pucSpdData), 28);
    pPMCtxt->tHdmiSpdInfoFrame.pucSpdData = pPMCtxt->ucSpdData;

    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_spd_infoframe(0x%08x)\n\r"),pPMCtxt->tHdmiSpdInfoFrame));

    return TRUE;
}

static BOOL
STDA_HDMI_init_HDCP_en
(PBYTE pBufIn)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_init_HDCP_en(%d)\n\r"),(BOOL)(*pBufIn)));

    if(!pBufIn)
    {
        DBGMSG(TV_INFO,(_T("[TVOUT] --STDA_HDMI_init_HDCP_en() pBufIn is NULL\n\r")));
        return FALSE;
    }

    pPMCtxt->bHDCPEn = (BOOL)(*pBufIn);

    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_init_HDCP_en(%d)\n\r"),pPMCtxt->bHDCPEn));

    return TRUE;
}

static BOOL
STDA_HDMI_Audeo_en
(PBYTE pBufIn)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_Audeo_en(%d)\n\r"),(BOOL)(*pBufIn)));

    if(!pBufIn)
    {
        DBGMSG(TV_INFO,(_T("[TVOUT] --STDA_HDMI_Audeo_en() pBufIn is NULL\n\r")));
        return FALSE;
    }

    pPMCtxt->bAudioEn = (BOOL)(*pBufIn);
	
	if(!HDMIAudioEnable(pPMCtxt->bAudioEn))
	{
		return FALSE;
	}
	
    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_Audeo_en(%d)\n\r"),pPMCtxt->bAudioEn));

    return TRUE;
}


static BOOL
STDA_HDMI_init_audio
(PBYTE pBufIn)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();

	MEDIUM_INFO tMediaInfo;
	HANDLE hAudio = INVALID_HANDLE_VALUE;
	DWORD dwBytes;

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_init_audio(%d)\n\r"),(BOOL)(*pBufIn)));

    if(!pBufIn)
    {
        DBGMSG(TV_INFO,(_T("[TVOUT] --STDA_HDMI_init_audio() pBufIn is NULL\n\r")));
        return FALSE;
    }

    pPMCtxt->hdmiAudioType = (HDMI_AUDIO_TYPE)(*pBufIn);

	hAudio = CreateFile( WAVE_NAME, GENERIC_READ|GENERIC_WRITE, FILE_SHARE_READ|FILE_SHARE_WRITE, NULL, OPEN_EXISTING, 0, 0);

	memset(&tMediaInfo, '\0', sizeof(MEDIUM_INFO));

	// Request Audio Infomation
	if(!DeviceIoControl(hAudio, IOCTL_WAVE_MEDIUM_INFO_GET, NULL, 0, &tMediaInfo, sizeof(MEDIUM_INFO), &dwBytes, NULL))
	{
		DBGMSG(TV_USR1,(TEXT("[STDA:ERR] ++%s(): IOCTL_WAVE_MEDIUM_INFO_GET Failed on line %d\r\n"),_T(__FUNCTION__), __LINE__));
	}

	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.MediumClass = [%d] \n\r"),tMediaInfo.MediumClass));
	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.DataFormat = [%d] \n\r"),tMediaInfo.DataFormat));
	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.Polarity = [%d] \n\r"),tMediaInfo.Polarity));
	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.BitClk = [%d] \n\r"),tMediaInfo.BitClk));
	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.BitLength = [%d] \n\r"),tMediaInfo.BitLength));
	DBGMSG(TV_FUNC,(TEXT("  tMediaInfo.dwLRClk = [%d] \n\r"),tMediaInfo.dwLRClk));

	//Fixed Setting Values.
 	pPMCtxt->tHdmiAudioParameter.channelNum = CH_2;
	pPMCtxt->tHdmiAudioParameter.outPacket = HDMI_ASP;
 	pPMCtxt->tHdmiAudioParameter.formatCode = LPCM_FORMAT;
 	pPMCtxt->tHdmiAudioParameter.wordLength = WORD_16;


	
	if(tMediaInfo.MediumClass == MEDIUM_IIS)
	{
		pPMCtxt->tHdmiAudioParameter.inputPort  = I2S_PORT;

			if(tMediaInfo.DataFormat == DFORMAT_IIS)
			{
			 	pPMCtxt->tHdmiAudioParameter.I2SParam.format = I2S_BASIC;
			}
			else if(tMediaInfo.DataFormat == DFORMAT_MSB)
			{
			 	pPMCtxt->tHdmiAudioParameter.I2SParam.format = I2S_LEFT_JUSTIFIED;
			}
			else if(tMediaInfo.DataFormat == DFORMAT_LSB)
			{
			 	pPMCtxt->tHdmiAudioParameter.I2SParam.format = I2S_RIGHT_JUSTIFIED;
			}
			else
			{
				DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio DataFormat [ERROR]\n\r")));		
			}


		DBGMSG(TV_FUNC,(TEXT(" HDMI Audio is Set to IIS\n\r")));
	}
	else if(tMediaInfo.MediumClass == MEDIUM_SPDIF)
	{
		//Not Support SPDIF. It's dummy.
		pPMCtxt->tHdmiAudioParameter.inputPort  = SPDIF_PORT;
		
		DBGMSG(TV_FUNC,(TEXT(" HDMI Audio is Set to SPDIF. But It isn't working\n\r")));
	}
	else
	{
		pPMCtxt->tHdmiAudioParameter.inputPort  = I2S_PORT;

		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio [ERROR]\n\r")));
	}




	if(tMediaInfo.Polarity == LEFT_LOW)
	{
		//Default...
	}
	else if(tMediaInfo.Polarity == LEFT_HIGH)
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Polarity [ERROR]\n\r")));		
	}
	else
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio Polarity [ERROR]\n\r")));		
	}




	if(tMediaInfo.BitClk == BCLK_32)
	{
	 	pPMCtxt->tHdmiAudioParameter.I2SParam.clk = I2S_32FS;		
	}
	else if(tMediaInfo.BitClk == BCLK_48)
	{
	 	pPMCtxt->tHdmiAudioParameter.I2SParam.clk = I2S_48FS;				
	}
	else if(tMediaInfo.BitClk == BCLK_16)
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio BitClk [ERROR]\n\r")));
	}
	else if(tMediaInfo.BitClk == BCLK_24)
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio BitClk [ERROR]\n\r")));		
	}
	else
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio BitClk [ERROR]\n\r")));		
	}




	if(tMediaInfo.BitLength == BLENGTH_16)
	{
	 	pPMCtxt->tHdmiAudioParameter.I2SParam.bpc = I2S_BPC_16;
	}
	else if(tMediaInfo.BitLength == BLENGTH_8)
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio BitLength [ERROR]\n\r")));				
	}
	else if(tMediaInfo.BitLength == BLENGTH_24)
	{
	 	pPMCtxt->tHdmiAudioParameter.I2SParam.bpc = I2S_BPC_24;		
	}
	else
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio BitLength [ERROR]\n\r")));		
	}




	if(tMediaInfo.dwLRClk == 44100)
	{
	 	pPMCtxt->tHdmiAudioParameter.sampleFreq = SF_44KHZ;
	}
	else if(tMediaInfo.dwLRClk == 32440)
	{
	 	pPMCtxt->tHdmiAudioParameter.sampleFreq = SF_32KHZ;		
	}
	else if(tMediaInfo.dwLRClk == 48960)
	{
	 	pPMCtxt->tHdmiAudioParameter.sampleFreq = SF_48KHZ;		
	}
	else
	{
		DBGMSG((TV_FUNC|TV_USR2),(TEXT(" HDMI Audio Polarity [ERROR]\n\r")));		
	}

/*	
	pPMCtxt->tHdmiAudioParameter.inputPort  = I2S_PORT;
	pPMCtxt->tHdmiAudioParameter.outPacket = HDMI_ASP;
 	pPMCtxt->tHdmiAudioParameter.formatCode = LPCM_FORMAT;
 	pPMCtxt->tHdmiAudioParameter.channelNum = CH_2;
 	pPMCtxt->tHdmiAudioParameter.sampleFreq = SF_44KHZ;
 	pPMCtxt->tHdmiAudioParameter.wordLength = WORD_16;
 	pPMCtxt->tHdmiAudioParameter.I2SParam.bpc = I2S_BPC_16;
 	pPMCtxt->tHdmiAudioParameter.I2SParam.format = I2S_BASIC;
 	pPMCtxt->tHdmiAudioParameter.I2SParam.clk = I2S_32FS;
*/

	CloseHandle(hAudio);
	
    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_init_audio(%d)\n\r"),pPMCtxt->hdmiAudioType));

    return TRUE;
}

static BOOL
STDA_HDMI_get_hpd_status
(PBYTE pBufOut)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();
    BOOL *pOut;

    DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_get_hpd_status()\n\r")));

    if(!pBufOut)
    {
        DBGMSG(TV_INFO,(_T("[TVOUT] --STDA_HDMI_get_hpd_status() pBufOut is NULL\n\r")));
        return FALSE;
    }

    pOut = (BOOL*)pBufOut;

    *pOut = pPMCtxt->bHPDStatus;

	DBGMSG(TV_USR1,(_T("pPMCtxt->bHPDStatus = (%d)\n\r"),pPMCtxt->bHPDStatus));
	

    DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_get_hpd_status()\n\r")));

    return TRUE;
}

static BOOL
STDA_HDMI_wait_hpd_status_change
(PBYTE pBufIn,
 PBYTE pBufOut)
{
	PDWORD pdwWaitTime = (PDWORD)pBufIn;
	PDWORD pOut = (PDWORD)pBufOut;	

	DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpd_status_change(%d)\n\r"),*pdwWaitTime));
    if(!pBufOut)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] --STDA_HDMI_wait_hpd_status_change() pBufOut is NULL\n\r")));
        return FALSE;
    }

    *pOut = STDA_interrupt_wait_hpd_cmd_done(*pdwWaitTime);

    if(*pOut == WAIT_TIMEOUT)
    {
        DBGMSG(TV_USR4,(_T("[TVOUT] ++STDA_HDMI_wait_hpd_status_change() TIMEOUT~\n\r")));
    }
    else if(*pOut == WAIT_FAILED)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_wait_hpd_status_change() WAIT_FAILED\n\r")));
    }

    DBGMSG(TV_USR4,(_T("[TVOUT] --STDA_HDMI_wait_hpd_status_change() change hpd status\n\r")));

    return TRUE;
}

static BOOL
STDA_HDMI_get_available_mode
(PBYTE pBufOut)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();
    pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo = NULL;

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_get_available_mode()\n\r")));

    if(pBufOut == NULL)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] --STDA_HDMI_get_available_mode() pBufOut is NULL\n\r")));
        return FALSE;
    }

    pInfo = (pSTDA_ARG_HDMI_AVAILABLE_MODE)pBufOut;

    if(pPMCtxt->bHPDStatus == FALSE)
    {
        memset((void *)pInfo, 0, sizeof(STDA_ARG_HDMI_AVAILABLE_MODE));
    }

    if(!STDA_HDMI_get_edid_info(pInfo))
    {
        return FALSE;
    }

    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_get_available_mode()\n\r")));
	RETAILMSG(1,(_T("[TVOUT] --STDA_HDMI_get_available_mode()\n\r")));

    return TRUE;
}

BOOL
STDA_HDMI_set_edid_info
(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo)
{
    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_set_edid_info()\n\r")));

    if(pInfo == NULL)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] --STDA_HDMI_set_edid_info() pInfo is NULL\n\r")));
        return FALSE;
    }

    if(STDA_HDMI_set_get_edid_info(pInfo, TRUE))
    {
        DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_set_edid_info()\n\r")));
        return TRUE;
    }

    return FALSE;
}

static BOOL
STDA_HDMI_get_edid_info
(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo)
{
    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_get_edid_info()\n\r")));

    if(pInfo == NULL)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] --STDA_HDMI_get_edid_info() pInfo is NULL\n\r")));
        return FALSE;
    }

    if(STDA_HDMI_set_get_edid_info(pInfo, FALSE))
    {
        DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_get_edid_info()\n\r")));
        return TRUE;
    }

    return FALSE;
}

static BOOL
STDA_HDMI_set_get_edid_info
(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo,
 BOOL bSet)
{
    STDAPowerContext *pPMCtxt = STDA_get_power_context();
    STDAContext *pCtxt= STDA_get_context();

    DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_set_get_edid_info()\n\r")));

    if(pInfo == NULL)
    {
        DBGMSG(TV_USR1,(_T("[TVOUT] --STDA_HDMI_set_get_edid_info() pInfo is NULL\n\r")));
        return FALSE;
    }

    EnterCriticalSection(&pCtxt->csProcHPDInfo);

    if(bSet)
    {
        memcpy((void *)&(pPMCtxt->tHdmiAvailableMode), (const void *)pInfo,
                sizeof(STDA_ARG_HDMI_AVAILABLE_MODE));

    }
    else
    {
        memcpy((void *)pInfo, (const void *)&(pPMCtxt->tHdmiAvailableMode),
                sizeof(STDA_ARG_HDMI_AVAILABLE_MODE));
    }

    LeaveCriticalSection(&pCtxt->csProcHPDInfo);

//	PrintHdmiAvaliableMode();

    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_set_get_edid_info()\n\r")));

    return TRUE;
}

void STDA_HDMI_HpdSetMode(HDMI_PIN_STATUS hdmiPinStatus, BOOL updataStatus)
{
	
	STDAPowerContext *pPMCtxt = STDA_get_power_context();
	STDAContext *pCtxt= STDA_get_context();

	DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_HpdSetMode(hdmiPinStatus=%d, updateStatus=%d)\n\r"),hdmiPinStatus, updataStatus));

	if(hdmiPinStatus == HDMI_HPD_MODE)
	{
		pCtxt->pHDMICoreReg->HDMI_HPD_GEN = 0xff;


		Set_PinFunction(pCtxt->pGpioReg, HDMI_HPD_FUNC);
		Set_PinPullUD(pCtxt->pGpioReg, HDMI_HPD_FUNC,sgip_PULL_DISABLE);

		HPDStart();
		if(updataStatus)
		{
			pPMCtxt->pinStatus = HDMI_HPD_MODE;
		}
	}
	else if(hdmiPinStatus == HDMI_EINT_MODE)
	{
		HPDStop();
		Mask_EXTINT(pCtxt->pGpioReg, EINT_HPD);

		Set_PinFunction(pCtxt->pGpioReg, HDMI_HPD_EINT);
		Set_PinPullUD(pCtxt->pGpioReg, HDMI_HPD_EINT,sgip_PULL_DISABLE);

		//Check the HPD Status
		//pPMCtxt->bHPDStatus = (Get_PinData(pCtxt->pGpioReg, HDMI_HPD_EINT))? TRUE:FALSE;
		pPMCtxt->bHPDStatus = (Get_PinData(pCtxt->pGpioReg, HDMI_HPD_EINT))? FALSE:TRUE; // modified by terry for x210 


		RETAILMSG(1,(_T("[STDA_HDMI_HpdSetMode]  pPMCtxt->bHPDStatus = %d\n\r"),pPMCtxt->bHPDStatus));

		
		Set_EXTINT_TRLVL(pCtxt->pGpioReg, EINT_HPD, sgip_BOTH_EDGE);
		Set_EXTINT_FILTER(pCtxt->pGpioReg, EINT_HPD, sgip_DELAY_FLT, 0);
		Clear_EXTINT(pCtxt->pGpioReg, EINT_HPD);
		Unmask_EXTINT(pCtxt->pGpioReg, EINT_HPD);

		if(updataStatus)
		{
			pPMCtxt->pinStatus = HDMI_EINT_MODE;
		}
	}

	DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_HpdSetMode()\n\r")));
}


BOOL
STDA_HDMI_read_edid_info
(pSTDA_ARG_HDMI_AVAILABLE_MODE pInfo)
{

//DMIVideoParameter video;
	VideoFormat SupportVideoFormat;
	PixelAspectRatio SupportAspectRatio;
	HDMIAudioParameter SupportAudio;

	DBGMSG(TV_FUNC,(_T("[TVOUT] ++STDA_HDMI_read_edid_info()\n\r")));


	if(pInfo == NULL)
	{
		DBGMSG(TV_USR1,(_T("[TVOUT] ++STDA_HDMI_get_edid_info() pInfo is NULL\n\r")));
		return FALSE;
	}

	if(EDIDInit())
	{
		if(!EDIDRead())
		{
			EDIDReset();
			EDIDDeInit();

			return FALSE;
		}
	}
	else
	{
		EDIDDeInit();
		return FALSE;
	}

// check Video Resolution
	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v720x480p_60Hz;
	pInfo->bHDMI_480P_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_4_3;
	SupportVideoFormat = v720x480p_60Hz;
	pInfo->bHDMI_480P_4_3 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v720x576p_50Hz;
	pInfo->bHDMI_576P_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_4_3;
	SupportVideoFormat = v720x576p_50Hz;
	pInfo->bHDMI_576P_4_3 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v1280x720p_60Hz;
	pInfo->bHDMI_720P_60_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v1920x1080p_60Hz;
	pInfo->bHDMI_1080P_60_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v1920x1080p_30Hz;
	pInfo->bHDMI_1080P_30_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

	SupportAspectRatio = HDMI_PIXEL_RATIO_16_9;
	SupportVideoFormat = v1920x1080i_60Hz;
	pInfo->bHDMI_1080I_60_16_9 = (EDIDVideoResolutionSupport(SupportVideoFormat, SupportAspectRatio))? TRUE:FALSE;

//Get EDID Data about Audio
	SupportAudio.inputPort = I2S_PORT;
	SupportAudio.outPacket = HDMI_ASP;
	SupportAudio.formatCode = LPCM_FORMAT;
	SupportAudio.channelNum = CH_2;
	SupportAudio.sampleFreq = SF_44KHZ;
	SupportAudio.wordLength = WORD_16;

	pInfo->bLPCM2CH = (EDIDAudioModeSupport(&SupportAudio))? TRUE:FALSE;

//Get Color Space Data & Color Depth Data
	pInfo->bHDMI_CS_RGB = (EDIDColorSpaceSupport(HDMI_CS_RGB))? TRUE:FALSE;
	if(pInfo->bHDMI_CS_RGB)
	{
		pInfo->bHDMI_CD_36_HDMI_CS_RGB = (EDIDColorDepthSupport(HDMI_CD_36, HDMI_CS_RGB))? TRUE:FALSE;
		pInfo->bHDMI_CD_30_HDMI_CS_RGB = (EDIDColorDepthSupport(HDMI_CD_30, HDMI_CS_RGB))? TRUE:FALSE;
		pInfo->bHDMI_CD_24_HDMI_CS_RGB = (EDIDColorDepthSupport(HDMI_CD_24, HDMI_CS_RGB))? TRUE:FALSE;
	}
	
	pInfo->bHDMI_CS_YCBCR444 = (EDIDColorSpaceSupport(HDMI_CS_YCBCR444))? TRUE:FALSE;
	if(pInfo->bHDMI_CS_YCBCR444)
	{
		pInfo->bHDMI_CD_36_HDMI_CS_YCBCR444 = (EDIDColorDepthSupport(HDMI_CD_36, HDMI_CS_YCBCR444))? TRUE:FALSE;
		pInfo->bHDMI_CD_30_HDMI_CS_YCBCR444 = (EDIDColorDepthSupport(HDMI_CD_30, HDMI_CS_YCBCR444))? TRUE:FALSE;
		pInfo->bHDMI_CD_24_HDMI_CS_YCBCR444 = (EDIDColorDepthSupport(HDMI_CD_24, HDMI_CS_YCBCR444))? TRUE:FALSE;		
	}

	pInfo->bHDMI_CS_YCBCR422 = (EDIDColorSpaceSupport(HDMI_CS_YCBCR422))? TRUE:FALSE;
	if(pInfo->bHDMI_CS_YCBCR422)
	{
		pInfo->bHDMI_CD_36_HDMI_CS_YCBCR422 = (EDIDColorDepthSupport(HDMI_CD_36, HDMI_CS_YCBCR422))? TRUE:FALSE;
		pInfo->bHDMI_CD_30_HDMI_CS_YCBCR422 = (EDIDColorDepthSupport(HDMI_CD_30, HDMI_CS_YCBCR422))? TRUE:FALSE;
		pInfo->bHDMI_CD_24_HDMI_CS_YCBCR422 = (EDIDColorDepthSupport(HDMI_CD_24, HDMI_CS_YCBCR422))? TRUE:FALSE;
	}
	
//Get Colorimetry Data
	pInfo->bHDMI_COLORIMETRY_EXTENDED_xvYCC601 = (EDIDColorimetrySupport(HDMI_COLORIMETRY_EXTENDED_xvYCC601))? TRUE:FALSE;
	pInfo->bHDMI_COLORIMETRY_EXTENDED_xvYCC709 = (EDIDColorimetrySupport(HDMI_COLORIMETRY_EXTENDED_xvYCC709))? TRUE:FALSE;

	pInfo->bHDMI_DVI = EDIDHDMIModeSupport();

	EDIDReset();
	EDIDDeInit();

    DBGMSG(TV_FUNC,(_T("[TVOUT] --STDA_HDMI_read_edid_info()\n\r")));
    return TRUE;

    
}

