#include "cecd.h"
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
#include <sys/types.h>
#include <sys/shm.h>
#include <sys/prctl.h>
#include <drv_ir_def.h>
#include <sys/ioctl.h>
#include <umf_cec.h>
#include <umf_debug.h>
#include <msgqueue.h>
#include "gl_task.h"
#include "gl_queue.h"
#include "ap_extern.h"
#include "board_config.h"
#include "drv_kmf_interface.h"
#if defined (CONFIG_DTV_SUPPORT) || defined (CONFIG_ATV_SUPPORT)
#include "al_channel_search.h"
#endif
#include "audio_ioctl.h"
#include "drv_audio_interface.h"
#include "hdmi_ioctl.h"
#include <time.h>


#define UCCKEYTIMEINTERVAL 200
#define DEVICELISINTERVAL 5000

#define CEC_AUDIO_ARC_NEWFUNCTION 0

#define abs(a)  (((int)a<0)?0-(int)(a):(int)a)

#ifndef EVENT_CODE
#define EVENT_CODE(class,type) (((class) << 16) | (type))
#endif

/*******************************************************************************
 * Constant
 ******************************************************************************/
#define CECTV_DAEMON_DELAY         	60


typedef struct Event_LinkList_Node_s
{
    CECTV_MessageBody_t            stEvt;
    struct Event_LinkList_Node_s    *pstNext;
} Event_LinkList_Node_t;

typedef struct Frame_LinkList_Node_s
{
    //DRV_CECTV_Frame_t              stFrm;
    struct Frame_LinkList_Node_s    *pstNext;
} Frame_LinkList_Node_t;


typedef struct Ack_LinkList_Node_s
{
    CECTV_MessageBody_t            *pstEvt;
    CECTV_Ack_Stat_t               *peStat;
    struct Ack_LinkList_Node_s      *pstNext;
} Ack_LinkList_Node_t;

typedef struct
{
    CECTV_MessageBody_t         *pstCmd;
    //DRV_CECTV_Frame_t           *pstFrm;
    Ack_LinkList_Node_t         *pstAckList;
} CECTV_RcvBuffer_t;

typedef struct
{
    Event_LinkList_Node_t       *pstEvtList;
    //Frame_LinkList_Node_t       *pstFrmList;
} CECTV_SendBuffer_t;

//******************************************************************************//
//Global Variables
//******************************************************************************//
CEC_t	g_CEC;
DEVICEINFO_LIST	g_CECDeviceList;
BOOL CecHDMIcontrol;
BOOL CecDevAutoPwrOff;
BOOL CecTvAutoPwrOn;
BOOL CecAudioARC;
//UINT8	HPStatus;
//BOOLEAN 	bCHScanStop;

GL_Queue_t                          _hCECTVCmdQueue;
static CECTV_RcvBuffer_t            _stCECRcvBuf;
static CECTV_SendBuffer_t           _stCECSendBuf;
static CECTaskStatus_t gCECTaskStatus = CEC_TASK_IDLE;
static BOOL gfCECTVEnable = CECTV_ENABLE;
static BOOL gfCECTVSpeaker = 0; //0: TV ; 1: AMP
static Event_LinkList_Node_t        *_pstSendEvtListTail;
static CECTV_ModCbk_pf g_pfCECCallback = NULL;
static BOOL bPowerOnRefresh = TRUE;

BOOL bUpdateDevice = FALSE;
BOOL bUpdateState = FALSE;
BOOL bUpdateMenu = FALSE;
BOOL bUpdateDeck = FALSE;
BOOL bPlaying = FALSE;
BOOL bAudioModeOn = FALSE;//Add to divide audio and ARC function
//BOOLEAN bChannelScanning = FALSE;

UINT8 powerstatus;


UINT8 preARCStatus=0;
UINT8 preQueryARCStatus=0;

extern KMFShareData_t *g_pKMFShareData;
#ifdef CONFIG_HDMI_ALL_PORT_TERMINATION_ON
struct timespec time1 = {0, 0};
struct timespec time2 = {0, 0};
#endif
struct timespec timeArcActive= {0, 0};

struct timespec AmpPowerOffTime = {0, 0};
struct timespec checkIfAmpPowerOff = {0, 0};


/*
//In spec. device response audio vol status is option. So can't use this flag to block countine key. Add UCCQueueTimestamp for this
//BOOL VolInQueue=FALSE;
*/
UINT32 UCCQueueTimestamp=0;
UINT32 DeviceListTimestamp=0;//Add to avoid set too many query message
LOGADDR preLogAddr;
PHYADDR prePhyAddr;
UINT32 cecHdmiPortStatus=0xffff;
struct timespec g_quickplugdetect;

UINT8 gPlayBackDevice=PLAYBACK_DEVICE_1_LOGICAL_ADDR;
static Boolean gfDeviceDiscover=FALSE;
static UINT8 CEC_TASK_IDLE_CNT=0;
static int ToggleCount = 0;
static BOOL bcec_Atmos = FALSE;
static BOOL bcec_DDPlus = FALSE;

 //=======================================================
// Set and Get global variables
//=======================================================
 UINT32 CECTV_IsFirstPowerOn(void)
 {
 		 return bPowerOnRefresh;
 }

int  CECTV_GetPowerStatus(void)
{
	return powerstatus;
}

CECTaskStatus_t  CECTV_GetAtmosVal(void)
{
	return bcec_Atmos;
}
 CECTaskStatus_t  CECTV_GetDDPlusVal(void)
{
	return bcec_DDPlus;
}
CECTaskStatus_t  CECTV_GetCECTaskStatus(void)
{
	return gCECTaskStatus;
}

CECTV_Status_e CECTV_SetCECTaskStatus(CECTaskStatus_t eCECTaskStatus)
{
	gCECTaskStatus=eCECTaskStatus;
	return CECTV_SUCCESS;
}

CECTV_Status_e CECTV_SetCECEnable(CECTVEnableStatus_t fEn)
{
	gfCECTVEnable=fEn;

	return CECTV_SUCCESS;
}

CECTVEnableStatus_t CECTV_GetCECEnable(void)
{
	return (CECTVEnableStatus_t)gfCECTVEnable;
}

void CECTV_GetDeviceList(PDEVICEINFO_LIST pdeviceList)
{
	memcpy(pdeviceList, &g_CECDeviceList, SIZE_OF_CECDEVICE_LIST);
}

void CECTV_SetAudioARC(bool val)
{
	CecAudioARC = val;
}

BOOL CECTV_GetAudioARC(void)
{
	return CecAudioARC;
}

UINT8 CECTV_GetAutoPwrOnSrc(void)
{
	return g_pKMFShareData->CecPwrOnSrc;
}

CECTV_Status_e CECTV_SetSpeakerPreference(BOOL fEn)
{
	gfCECTVSpeaker=fEn;

	return CECTV_SUCCESS;
}

BOOL CECTV_GetSpeakerPreference(void)
{
	return gfCECTVSpeaker;
}

CEC_t *cec_GetHandle(void)
{
	return &g_CEC;
}

BOOL CECTV_CheckARCDevice(void)
{
	BOOL bfind=FALSE;
	DEVICEINFO_LIST *pdeviceList;
	UINT32 i;	
	UINT8 ARCPort = HDMI_ARC_PORT_INDEX;
    #if (HDMI_ARC_PORT_INDEX != -1)
    {
        ARCPort = (CONFIG_HDMI_PORT_MAP & (0xf<<HDMI_ARC_PORT_INDEX*4)) >> HDMI_ARC_PORT_INDEX*4;
    }
    #endif
	
	pdeviceList = &g_CECDeviceList;
	
	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM && pdeviceList->device[i].hdmi_source == ARCPort)
		{
			bfind = TRUE;				
			break;		
		}
	}	
	return bfind;
}

tv_source_t CECTV_CheckDeviceSoruce(LOGADDR logAddr)
{
	DEVICEINFO_LIST *pdeviceList;
	tv_source_t deviceSource = SRC_OTHERS;
	UINT32 i;	
	
	pdeviceList = &g_CECDeviceList;
	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		if (pdeviceList->device[i].logical_addr == logAddr)
		{
			deviceSource = pdeviceList->device[i].hdmi_source;
			break; 	
		}
	}	
	return deviceSource;
}

BOOL CECTV_CheckDeviceDiscover(void)
{
            return gfDeviceDiscover;
}

BOOL CECTV_GetHDMIAudioARCStatus(void)
{
	CEC_t *pcec = cec_GetHandle();
	BOOL retval=FALSE;
	
	if (pcec->systemAudio.ARCstatus == ARC_Active && CECTV_GetAudioARC() && CECTV_CheckARCDevice())
	{
		retval=TRUE;
	}
	
	return retval;
}

BOOL CECTV_GetHDMISystemAudioMode(void)
{
	CEC_t *pcec = cec_GetHandle();
	BOOL retval=FALSE;
#ifdef SUPPORT_HDMI_SYSTEM_AUDIO_WITHOUT_ARC
	if (pcec->systemAudio.state == AS_ON)
#else
	if (pcec->systemAudio.state == AS_ON && CECTV_GetAudioARC() && CECTV_CheckARCDevice())
#endif
	{
		retval=TRUE;
	}
	
	return retval;
}

void CECTV_SetCECSrcIdx(tv_source_t src)
{
	CEC_t *pcec = cec_GetHandle();

	pcec->inputSource = src;
	UMFDBG(0,"%s SrcIdx = %d\n", __FUNCTION__, pcec->inputSource);
}

//=======================================================
// Receive and send command to ap
//=======================================================

static CECTV_Status_e _SendEvt(CECTV_MessageBody_t stEvt)
{
    Event_LinkList_Node_t *pstNew;

    pstNew = (Event_LinkList_Node_t*)malloc(sizeof(Event_LinkList_Node_t));
	if(pstNew == NULL)
	{
		return CECTV_ERR_FAILURE;
	}
    pstNew->stEvt = stEvt;

    if (_stCECSendBuf.pstEvtList == NULL)
    {
        _stCECSendBuf.pstEvtList = pstNew;
        _pstSendEvtListTail = pstNew;
        _pstSendEvtListTail->pstNext = NULL;
    }
    else
    {
        if (_pstSendEvtListTail)
        {
            _pstSendEvtListTail->pstNext = pstNew;
            _pstSendEvtListTail = pstNew;
            _pstSendEvtListTail->pstNext = NULL;
        }
        else
        {
        	free(pstNew);
            return CECTV_ERR_FAILURE;
        }	
    }
	
    return CECTV_SUCCESS;
}

static void _RcvModule(void)
{
    //DEBF("<<%s:%d>>\n",__FUNCTION__,__LINE__);
    CECTV_MessageBody_t stRcvCmd, *pstNewCmd;
    GL_Status_t eQueueStat;

    //rcv App cmd
    memset(&stRcvCmd, 0, sizeof(CECTV_MessageBody_t));
    eQueueStat = GL_QueueReceive(_hCECTVCmdQueue, &stRcvCmd, sizeof(CECTV_MessageBody_t), 0);
    if (eQueueStat == GL_SUCCESS)
    {
        //CEC_DAEMON_DEBF(CEC_Daemon_Message_level_Detail,"rcv an app cmd\n");
        UMFDBG(0," %s rcv an app cmd\n", __FUNCTION__);
        pstNewCmd = (CECTV_MessageBody_t*)malloc(sizeof(CECTV_MessageBody_t));
		if(pstNewCmd == NULL)
		{
			return;
		}
        _stCECRcvBuf.pstCmd = pstNewCmd;
        *(_stCECRcvBuf.pstCmd) = stRcvCmd;
    }
}

static void _SendModule(void)
{
    //DEBF("<<%s:%d>>\n",__FUNCTION__,__LINE__);
    Event_LinkList_Node_t *pEHead, *pEDel;
    //Frame_LinkList_Node_t *pFHead, *pFDel;


    //send Event to App
    if (_stCECSendBuf.pstEvtList)
    {
        //CEC_DAEMON_DEBF(CEC_Daemon_Message_level_Detail,"send event to App\n");
        UMFDBG(0,"%s send event to App\n", __FUNCTION__);
        pEHead = _stCECSendBuf.pstEvtList;
        _stCECSendBuf.pstEvtList = NULL;
		while (pEHead)
		{
			if (g_pfCECCallback != NULL)
        	{
				g_pfCECCallback((CECTV_Message_t)(pEHead->stEvt.dMessage) , pEHead->stEvt.dParam);
			}
            pEDel = pEHead;
            pEHead = pEHead->pstNext;
            free(pEDel);
        }
    }
	else
	{
    	if(CECTV_GetCECTaskStatus()!=CEC_TASK_IDLE)
    	{
			CECTV_SetCECTaskStatus(CEC_TASK_IDLE);
			CEC_TASK_IDLE_CNT=0;
    	}
		else
		{
			CEC_TASK_IDLE_CNT++;
		}
		if ((gfDeviceDiscover==FALSE)&&(CEC_TASK_IDLE_CNT>20))
		{
			//cec_RefreshDeviceList();
		}
	}	

}

//=======================================================
// Handle command from ap
//=======================================================

void _AppCmdProcess(CECTV_Act_Cmd_t eCmd, UINT32 dParam)
{
    UINT8 i, bParam[4];

    for (i = 0; i < 4; i++)
        bParam[i] = (dParam >> (i*8)) & 0xff;
    //CEC_DAEMON_DEBF(CEC_Daemon_Message_level_Detail,"eCmd = %x, bParam[0] = %x, bParam[1] = %x, bParam[2] = %x, bParam[3] = %x\n", eCmd, bParam[0], bParam[1], bParam[2], bParam[3]);
	UMFDBG(0," %s eCmd = %x, bParam[0] = %x, bParam[1] = %x, bParam[2] = %x, bParam[3] = %x\n", __FUNCTION__, eCmd, bParam[0], bParam[1], bParam[2], bParam[3]);
    switch (eCmd)
    {
	    case CECTV_SINGLE_ACT_CMD_KEYPRESS:
			cec_RemoteControlPassThrough(bParam[1]);
	        break;

	   /*case CECTV_SINGLE_ACT_CMD_KEYRELEASE:
	        break;

	    case CECTV_SINGLE_ACT_CMD_KEYREPEAT:
	        break;
		*/
	    case CECTV_SINGLE_ACT_CMD_STANDBY:
			_Stop();
			CECTV_SetCECTaskStatus(CEC_TASK_Standby);
	        break;

	    //Set OSD language
	    case CECTV_SINGLE_ACT_CMD_SET_OSD_LANGUAGE:
			cec_NoticeMenuLanguage(bParam[0]);
	        break;

	    //Change source to HDMI
	    case CECTV_SINGLE_ACT_CMD_CHGSRC_TO_HDMI:
	    //Change source between HDMI
	    case CECTV_SINGLE_ACT_CMD_CHGSRC_BTW_HDMI:
		//Change source from HDMI to other
	    case CECTV_SINGLE_ACT_CMD_CHGSRC_OUT_HDMI:
			cec_ChangeSource((tv_source_t)(bParam[0]));
	        break;
	    case CECTV_SINGLE_ACT_ROUTING_INFO:
			cec_NoticeRoutingInfo(bParam[0]);
		break;

	    /*case CECTV_SINGLE_ACT_CMD_SYSAUD_MODE_REQ_ON:
	        break;

	    case CECTV_SINGLE_ACT_CMD_SYSAUD_MODE_REQ_OFF:
	        break;

	    case CECTV_SINGLE_ACT_CMD_GIVE_DECK_STATUS:
	        break;

	    case CECTV_SINGLE_ACT_CMD_PLAY:
	        break;

	    case CECTV_SINGLE_ACT_CMD_DECK_CONTROL:
	        break;
		*/
		case CECTV_SINGLE_ACT_CMD_SET_ARC_OPTION_DISABLE:
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
                Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
#endif
			break;
		case CECTV_SINGLE_ACT_CMD_REQUEST_ARC_INITIATION:
			cec_SetAudioARC(TRUE);
//            #ifdef CONFIG_SUPPORT_DOLBY_AUDIO
//                cec_RequestShortAudioDescriptor();
//            #endif
			break;
		case CECTV_SINGLE_ACT_CMD_REQUEST_ARC_TERMINATION:
			if(CECTV_GetCECEnable() && CECTV_GetAudioARC())
			{
				//cec_EnableARCfunctionTimer(FALSE);
				cec_SetAudioARC(FALSE);
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
				Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
#endif
			}
			break;
		case CECTV_SINGLE_ACT_CMD_REQUEST_SYSTEMAUDIOMODE_ON:
			cec_RequestAudioMode(TRUE);
			break;
		case CECTV_SINGLE_ACT_CMD_REQUEST_SYSTEMAUDIOMODE_OFF:
			cec_RequestAudioMode(FALSE);
			break;
		case CECTV_SINGLE_ACT_CMD_SET_DEVICENUM:
			CECTV_SetDeviceNum(bParam[0]);
			break;
	    case CECTV_SINGLE_ACT_CMD_SET_CECENABLE:
			cec_SetCECenable(bParam[0]);
			//cec_SetTvAutoPwrOn(CecTvAutoPwrOn);
			if(bParam[0]==CECTV_ENABLE && bPowerOnRefresh==TRUE)
			{
                bPowerOnRefresh = FALSE;
				cec_RefreshDeviceList();
			}
	        break;

		case CECTV_SINGLE_ACT_CMD_SET_AUTOPOWERON:
			cec_SetTvAutoPwrOn((BOOL)(bParam[0]));
			break;

		case CECTV_SINGLE_ACT_CMD_SET_DEVAUTOPOWEROFF:
			//cec_SetDevAutoPwrOff(bParam[0]);
			break;

		case CECTV_SINGLE_ACT_CMD_REQUEST_AUDIO_STATUS:
			cec_RequestAudioStatus();
			break;

		case CECTV_SINGLE_HDMI_ARC_SWITCH:
			cec_Hdmi_ARC_Switch(bParam[0]);
			break;

	    default:
	        break;
    }

}

static void _SingleActionModule(void)
{
    //printf("<<%s:%d>>\n",__FUNCTION__,__LINE__);
    CECTV_Act_Cmd_t eCmd;
    UINT32 dParam;

    //react the APP single action cmd
    if (_stCECRcvBuf.pstCmd)
    {
        if ((_stCECRcvBuf.pstCmd->dMessage & CECTV_SINGLE_ACT_CMD_TYPE) == CECTV_SINGLE_ACT_CMD_TYPE)
        {
            //CEC_DAEMON_DEBF(CEC_Daemon_Message_level_Detail,"rcv single act\n");
            UMFDBG(0," %s rcv single act\n", __FUNCTION__);
            eCmd = _stCECRcvBuf.pstCmd->dMessage & CECTV_CMD_MASK;
            dParam = _stCECRcvBuf.pstCmd->dParam;
            _AppCmdProcess(eCmd, dParam);
        }
        //else
            //printf("[%s] Error! Could not happen!\n", __FUNCTION__);

        free(_stCECRcvBuf.pstCmd);
        _stCECRcvBuf.pstCmd = NULL;
    }
}


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

HRESULT transferLang(UINT8 OsdLang, char *pLang)
{
	switch(OsdLang)
	{
		case APP_OSDLANG_ENGLISH:
			pLang[2] = 'g';
			pLang[1] = 'n';
			pLang[0] = 'e';
			break;			
		case APP_OSDLANG_FRENCH:
			pLang[2] = 'e';
			pLang[1] = 'r';
			pLang[0] = 'f';
			break;		
		case APP_OSDLANG_GERMAN:
			pLang[2] = 'r';
			pLang[1] = 'e';
			pLang[0] = 'g';
			break;
	    case APP_OSDLANG_ITALIAN:
			pLang[2] = 'a';
			pLang[1] = 't';
			pLang[0] = 'i';
			break;
		case APP_OSDLANG_SPAIN:
			pLang[2] = 'a';
			pLang[1] = 'p';
			pLang[0] = 's';
			break;
    	case APP_OSDLANG_POLISH:
			pLang[2] = 'l';
			pLang[1] = 'o';
			pLang[0] = 'p';
			break;
    	case APP_OSDLANG_NEDERLANDS:
			pLang[2] = 'd';
			pLang[1] = 'l';
			pLang[0] = 'n';
			break;
    	case APP_OSDLANG_PORTUGUESE:
			pLang[2] = 'r';
			pLang[1] = 'o';
			pLang[0] = 'p';
			break;
    	case APP_OSDLANG_SWEDISH:
			pLang[2] = 'e';
			pLang[1] = 'w';
			pLang[0] = 's';
			break;
    	case APP_OSDLANG_SUOMI:
			pLang[2] = 'n';
			pLang[1] = 'i';
			pLang[0] = 'f';
			break;
    	case APP_OSDLANG_GREEK:
			pLang[2] = 'e';
			pLang[1] = 'r';
			pLang[0] = 'g';
			break;
    	case APP_OSDLANG_RUSSIA:
			pLang[2] = 's';
			pLang[1] = 'u';
			pLang[0] = 'r';
			break;
    	case APP_OSDLANG_TURKISH:
			pLang[2] = 'r';
			pLang[1] = 'u';
			pLang[0] = 't';
			break;
    	case APP_OSDLANG_DANISH:
			pLang[2] = 'n';
			pLang[1] = 'a';
			pLang[0] = 'd';
			break;
    	case APP_OSDLANG_NORWEGIAN:
			pLang[2] = 'r';
			pLang[1] = 'o';
			pLang[0] = 'n';
			break;
		case APP_OSDLANG_HUNGARIAN:
			pLang[2] = 'n';
			pLang[1] = 'u';
			pLang[0] = 'h';
			break;
		case APP_OSDLANG_CZECH:
			pLang[2] = 'e';
			pLang[1] = 'z';
			pLang[0] = 'c';
			break;
		case APP_OSDLANG_SLOVAKIAN:
			pLang[2] = 'o';
			pLang[1] = 'l';
			pLang[0] = 's';
			break;
		case APP_OSDLANG_CROATIAN:
			pLang[2] = 'v';
			pLang[1] = 'r';
			pLang[0] = 'h';
			break;
		case APP_OSDLANG_SERBIAN:
			pLang[2] = 'p';
			pLang[1] = 'r';
			pLang[0] = 's';
			break;
		case APP_OSDLANG_ARABIC:
			pLang[2] = 'a';
			pLang[1] = 'r';
			pLang[0] = 'a';
			break;
		case APP_OSDLANG_PERSIAN:
			pLang[2] = 'r';
			pLang[1] = 'e';
			pLang[0] = 'p';
			break;
		case APP_OSDLANG_THAI:
			pLang[2] = 'a';
			pLang[1] = 'h';
			pLang[0] = 't';
			break;
		case APP_OSDLANG_TCHINESE:
			pLang[2] = 'i';
			pLang[1] = 'h';
			pLang[0] = 'c';
			break;
		case APP_OSDLANG_SCHINESE:
			pLang[2] = 'o';
			pLang[1] = 'h';
			pLang[0] = 'z';
			break;
		default:
			UMFDBG(0, "unknow language!!\n");
			break;
	}

	return S_OK;
}


HRESULT bDeviceIsExist(LOGADDR logAddr)	//2011/01/21 zoey
{
	PDEVICEINFO_LIST pdeviceList = &g_CECDeviceList;
	INT32 i = 0;

	for (i = 0; i < MAX_DEVICE_NUM; i++)
	{
		if (pdeviceList->device[i].logical_addr == logAddr)
		{
			return TRUE;
		}
	}

	return FALSE;
}


HRESULT waitUpdateCECMsg(UINT8 *pState, UINT8 waitTime)
{
	UINT8 counter = 0;

	while(!(*pState) && counter < waitTime)
	{
		//tm_CleanWatchDog();
		if(counter == 0)
		{
			UMFDBG(0,"Waiting update Msg");
		}
		else
		{
			UMFDBG2(0, ".");
		}
		umfsleep(0, 100000000); //wait 0.1s * waitTime
		counter++;
	}

	return counter;
}

//=======================================================
// UMF System Audio Control CEC
//=======================================================
HRESULT cec_RequestAudioMode(BOOL bEnable)
{
	CEC_t *pcec = cec_GetHandle();
	CECD_MSG cecdMsg;
	
	DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
	int i,j;
	int AMPFlag = 0;
	UINT32 devicePhyaddr=0x0;

	if(!CECTV_GetCECEnable() || !CECTV_GetAudioARC())
		return S_OK;

	/*if (!cec_GetAudioARC(FALSE))
		return S_OK;

	if (ptv->HPStatus)
	{
		//[Remove old menu command]
		//CTL_CecShowInfo(CecAudioNotAvailable);
		//~[Remove old menu command]
		//STB_ERSendEvent(FALSE,FALSE,EV_CLASS_UI,EV_CECAUDIONOTAVALIABLE);
		//[Marco] Need new OSD function
		//cec_SendOSDEvent(CecAudioNotAvailable);
		return S_OK;
	}*/

	for (i = 0 ;i < pdeviceList->deviceNum ;i++)
	{
		if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM)
		{
			if(pdeviceList->device[i].logical_addr !=0x5)
				return S_OK;
			AMPFlag = 1;
			if(pcec->inputSource == pdeviceList->device[i].hdmi_source)
			{
				for(j=0;j<pdeviceList->deviceNum;j++)
				{
					if(pdeviceList->device[j].hdmi_source ==pdeviceList->device[i].hdmi_source && pdeviceList->device[j].device_type==DEVICE_TYPE_DVD)
						devicePhyaddr = pdeviceList->device[j].physical_addr;
				}
			}
			else
				devicePhyaddr = 0x0;
		}
	}
	if(AMPFlag == 0)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestAudioMode;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;
	if (bEnable)
		cecdMsg.audio.phyAddr = devicePhyaddr;
	else
		cecdMsg.audio.phyAddr = 0xffff;

	UMFDBG(0,"%s %d logAddr=%d, phyAddr=0x%x, inputSrc=%d\n",__FUNCTION__, bEnable, cecdMsg.audio.logAddr, cecdMsg.audio.phyAddr, pcec->inputSource);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

HRESULT cec_RequestAudioModeStatus(CEC_t *pcec)
{
	CECD_MSG cecdMsg;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestAudioModeStatus;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;

	UMFDBG(0, "%s logAddr=%d\n",__FUNCTION__, cecdMsg.audio.logAddr);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

void cec_RequestAudioStatus(void)
{
	CECD_MSG cecdMsg;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestAudioStatus;
	cecdMsg.audio.logAddr = AUDIO_SYSTEM_LOGICAL_ADDR;

	UMFDBG(0, "%s logAddr=%d\n",__FUNCTION__, cecdMsg.audio.logAddr);
	cecd_UmfEventHandle(&cecdMsg);
}

HRESULT cec_RemoteControlAudioVolume(CEC_t *pcec, UINT8 CECTV_KEY)
{
	CECD_MSG cecdMsg;
	user_control_code_t userControl;

	/*if ((input != SRCID_PICVIEWER && input != SRCID_MUSICPLAYER && input != SRCID_MEDIA && ptv->inputStatus[MAIN] == STATUS_NOSIGNAL) ||
		(pcec->systemAudio.volMute && (CECTV_KEY == CECTV_KEY_VOLUME_UP ||CECTV_KEY == CECTV_KEY_VOLUME_DOWN)))
	{
		//[Remove old menu command
		//CTL_ShowNotAvailable();
		//~[Remove old menu command
		return S_OK;
	}*/

	switch(CECTV_KEY)
	{
		case CECTV_KEY_MUTE:
		case CECTV_KEY_MUTE_RELEASE:
			userControl = UCC_Mute;
			break;
		case CECTV_KEY_VOLUME_UP:
		case CECTV_KEY_VOLUME_UP_RELEASE:
			userControl = UCC_Volume_Up;
			break;
		case CECTV_KEY_VOLUME_DOWN:
		case CECTV_KEY_VOLUME_DOWN_RELEASE:
			userControl = UCC_Volume_Down;
			break;
		default:
			return S_OK;
	}

	//VolInQueue=TRUE;
	//UCCQueueTimestamp=tv_GetClockMilliseconds();
	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	if (CECTV_KEY == CECTV_KEY_VOLUME_UP_RELEASE || CECTV_KEY == CECTV_KEY_VOLUME_DOWN_RELEASE || CECTV_KEY == CECTV_KEY_MUTE_RELEASE)
		cecdMsg.CmdType = CMD_RemoteControlAudioVolumeRelease;
	else	
		cecdMsg.CmdType = CMD_RemoteControlAudioVolume;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;
	cecdMsg.audio.userControlCode = userControl;

	UMFDBG(0,"%s logAddr=%d, userControl=%d\n",__FUNCTION__, cecdMsg.audio.logAddr, userControl);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

INT32 cec_SetAudioARC(BOOL bEnable)
{
	UMFDBG(0,"%s = %d\n", __FUNCTION__, bEnable);

	CecAudioARC = bEnable;

	bAudioModeOn = CecAudioARC;

	if( CECTV_GetCECEnable())
	{
		cec_EnableARCfunctionTimer(bEnable);
	}

	if(bEnable)
		cec_RequestAudioStatus();

	return S_OK;
}
HRESULT cec_Hdmi_ARC_Switch(UINT8 ARCstatus)
{
	CECD_MSG cecdMsg;
	CEC_t *pcec = cec_GetHandle();
	PHYADDR sysAudioPhy = pcec->systemAudio.phyAddr;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_Hdmi_ARC_Switch;
	cecdMsg.audio.phyAddr = sysAudioPhy;
	cecdMsg.audio.audoTxSetARCActiveDeActive = ARCstatus;

	UMFDBG(0,"%s=%d\n",__FUNCTION__, ARCstatus);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

HRESULT cec_RequestARC(CEC_t *pcec, UINT8 ARCstatus)
{
	CECD_MSG cecdMsg;
	PHYADDR sysAudioPhy = pcec->systemAudio.phyAddr;
	UINT8 ARCPort = HDMI_ARC_PORT_INDEX;
    #if (HDMI_ARC_PORT_INDEX != -1)
    {
        ARCPort = ((CONFIG_HDMI_PORT_MAP & (0xf<<HDMI_ARC_PORT_INDEX*4)) >> HDMI_ARC_PORT_INDEX*4) - 1;
    }
    #endif
	
 	//First 8 bits(bit 7~ bit0) record HDMI if change. Following 8 bit(bit 15 ~ bit 8) record HMDI status
   	if((cecHdmiPortStatus & (0x1 << ARCPort)))
   	{
		if(!((cecHdmiPortStatus) & (0x1 <<(8+ARCPort))))
		{
			UMFDBG(0,"WARNING!!! ARC_Power5V_PIN=>Low\n");
			return E_FAIL;
		}
   	}


	if (sysAudioPhy != 0x1000 && sysAudioPhy != 0x2000 && sysAudioPhy != 0x3000 && sysAudioPhy != 0x4000 && sysAudioPhy != 0x5000)
	{
		cec_SendDeactivedARCTX(pcec);
		return E_FAIL;
	}	

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestARC;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;
	cecdMsg.audio.phyAddr = sysAudioPhy;
	cecdMsg.audio.audoTxSetARCActiveDeActive = ARCstatus;

	UMFDBG(0,"%s=%d, logAddr=%d, phyAddr=0x%x\n",__FUNCTION__, ARCstatus, cecdMsg.audio.logAddr, sysAudioPhy);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

HRESULT cec_SendDeactivedARCTX(CEC_t *pcec)
{
	CECD_MSG cecdMsg;
	PHYADDR sysAudioPhy = pcec->systemAudio.phyAddr;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestARCTerminated;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;
	cecdMsg.audio.phyAddr = sysAudioPhy;

	UMFDBG(0,"%s, logAddr=%d, phyAddr=0x%x\n",__FUNCTION__, cecdMsg.audio.logAddr, sysAudioPhy);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

HRESULT cec_QueryARCStatus(CEC_t * pcec, UINT8 ARCstatus, UINT8 waitSecs)
{
	CECD_MSG cecdMsg;
	UINT8 waitTime=waitSecs*10;
    struct timespec nowTime= {0, 0};

  if(!CECTV_GetCECEnable() || !CECTV_GetAudioARC())
	return S_OK;

    if (ARCstatus == ARC_Active)
    {
        clock_gettime(CLOCK_MONOTONIC, &nowTime);
	    UMFDBG(0,"timeArcActive = %d, nowTime = %d\n",(UINT32)timeArcActive.tv_sec, (UINT32)nowTime.tv_sec);
        if ((nowTime.tv_sec - timeArcActive.tv_sec) <= 1 && 
            (nowTime.tv_sec > 8))
        {
		    return E_FAIL;
        }
		memcpy(&timeArcActive,&nowTime,sizeof(timeArcActive));
    }
	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_QueryARC;
	cecdMsg.audio.logAddr = pcec->systemAudio.logAddr;
	cecdMsg.audio.audoTxSetARCActiveDeActive = (audio_ARCstatus_t)ARCstatus;

	UMFDBG(0,"%s=%d, logAddr=%d\n",__FUNCTION__, ARCstatus, cecdMsg.audio.logAddr);

	cecd_UmfEventHandle(&cecdMsg);
	preQueryARCStatus=ARCstatus;

	if(waitTime>0)
	{

	}

	return S_OK;
}

HRESULT cec_RequestShortAudioDescriptor(void)
{
	CEC_t *pcec = cec_GetHandle();
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_RequestShortAudioDescriptor;
	cecdMsg.audio.logAddr = AUDIO_SYSTEM_LOGICAL_ADDR;

	UMFDBG(0, "%s logAddr=%d\n",__FUNCTION__, cecdMsg.audio.logAddr);
	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

#if CEC_AUDIO_ARC_NEWFUNCTION
PTmClient_t pARCTimer = NULL;
BOOL bEnableARC=FALSE;

void setARCTimerThread()
{
	CEC_t *pcec = cec_GetHandle();
	if(bEnableARC && pcec->systemAudio.state==AS_OFF)
	{
		cec_RequestAudioMode(TRUE);
	}
	else if(bEnableARC==FALSE && pcec->systemAudio.state==AS_ON)
	{
		cec_RequestAudioMode(FALSE);
	}
	else if(pcec->systemAudio.ARCstatus == ARC_FeatureAbort)
	{
		if(bEnableARC)
		{
			cec_QueryARCStatus(pcec,ARC_Active,0);
		}
		else
		{
			cec_QueryARCStatus(pcec,ARC_DeActive,0);
		}
	}
	else if( pcec->systemAudio.ARCstatus == ARC_Active)
	{
		if(!bEnableARC)
		{
			cec_QueryARCStatus(pcec,ARC_DeActive,0);
		}
		else
		{
			//same status, do nothing.
		}
	}
	else if( pcec->systemAudio.ARCstatus == ARC_DeActive)
	{
		if(bEnableARC)
		{
			cec_QueryARCStatus(pcec,ARC_Active,0);
		}
		else
		{
			//same status, do nothing.
		}
	}
	tm_EZSettimer(pARCTimer, 0, 0);//Disable timer
}
#endif
void cec_EnableARCfunctionTimer(BOOL enableARC)
{
#if CEC_AUDIO_ARC_NEWFUNCTION
	bEnableARC=enableARC;
	if (pARCTimer == NULL)
	{
		pARCTimer = tm_Create(DEFAULTTMSVR, (void *)setARCTimerThread, NULL);

		if (pARCTimer == NULL)
		{
			perror("nkh_Create faill to create timer\n");
			free(pARCTimer);
			return;
		}
	}
	tm_EZSettimer(pARCTimer, 1, 0);

#else
	CEC_t *pcec = cec_GetHandle();

	UMFDBG(0, " %s systemAudio = %d, ARCstatus=%d\n", __FUNCTION__, pcec->systemAudio.state, pcec->systemAudio.ARCstatus);
	//if(enableARC && pcec->systemAudio.state==AS_OFF)
	if(enableARC)
	{
		cec_RequestAudioMode(TRUE);
	}

	if(pcec->systemAudio.ARCstatus == ARC_FeatureAbort)
	{
		if(enableARC)
		{
			cec_QueryARCStatus(pcec,ARC_Active,2);
		}
		else
		{
			cec_QueryARCStatus(pcec,ARC_DeActive,1);
		}
	}
	else if( pcec->systemAudio.ARCstatus == ARC_Active)
	{
		if(!enableARC)
		{
			cec_QueryARCStatus(pcec,ARC_DeActive,1);
		}
		else
		{
			//same status, do nothing.
		}
	}
	else if( pcec->systemAudio.ARCstatus == ARC_DeActive)
	{
		if(enableARC)
		{
			cec_QueryARCStatus(pcec,ARC_Active,2);
		}
		else
		{
			//same status, do nothing.
		}
	}
#endif
}

//=========================================================
// UMF Notice CEC
//=========================================================

void cec_SetCECenable(UINT32 status)
{
	CEC_t *pcec = cec_GetHandle();

	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return;

	if (!status)
		cec_SetTvAutoPwrOn(FALSE);
	
	cecdMsg.MsgType = CECDMSG_SET_CECENABLE;
	cecdMsg.CmdType = CMD_SetCECEnable;
	cecdMsg.param = status;
	cecd_UmfEventHandle(&cecdMsg);
}

void cec_ReToggelHPD(void)
{
	CEC_t *pcec = cec_GetHandle();

	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return;
	
	cecdMsg.MsgType = CECDMSG_PORT_HPD_TOGGLE;
	cecdMsg.CmdType = CMD_NULL;
	cecdMsg.param = 0;
	cecd_UmfEventHandle(&cecdMsg);
}

HRESULT cec_NoticeStandby(CEC_t *pcec, BOOL status)
{
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticeStandby;	
	//if (!status)
	{
		DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
		UINT8 i = 0;
		
		for (i = 0; i < pdeviceList->deviceNum; i++)
		{
			cecdMsg.notice.logAddr = pdeviceList->device[i].logical_addr;
			UMFDBG(0,"%s cmdType=%d, logAddr=%d\n",__FUNCTION__, cecdMsg.CmdType, cecdMsg.notice.logAddr);
			cecd_UmfEventHandle(&cecdMsg);			
		}		
	}

	cecdMsg.notice.logAddr = BROADCAST_LOGICAL_ADDR;
	cecd_UmfEventHandle(&cecdMsg);
	
	UMFDBG(0,"%s cmdType=%d, logAddr=%d\n",__FUNCTION__, cecdMsg.CmdType, cecdMsg.notice.logAddr);

	return S_OK;
}

HRESULT cec_NoticeRoutingInfo(tv_source_t tvsource)
{
	CECD_MSG cecdMsg;
	CEC_t *pcec = cec_GetHandle();
	
	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticeRoutingInfo;
	if(tvsource == 0x0)
	{
		cecdMsg.notice.toSrc= 0x0;
		cecdMsg.notice.phyAddr = 0x0;
	}
	else
	{
		cecdMsg.notice.toSrc= tvsource;
		cecdMsg.notice.phyAddr = pcec->PhyAddr?pcec->PhyAddr:  cec_QueryPlayBackDevicePhyaddr(tvsource);
	}

	UMFDBG(0,"%s toSrc=%d, phyAddr = 0x%x\n",__FUNCTION__, cecdMsg.notice.toSrc, cecdMsg.notice.phyAddr);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}


HRESULT cec_NoticeSourceChange(CEC_t *pcec)
{
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticeSourceChange;
	cecdMsg.notice.target_src = pcec->inputSource;
	cecdMsg.notice.phyAddr = cec_QueryPlayBackDevicePhyaddr(pcec->inputSource);

	UMFDBG(0,"%s target_src=%d, target_phyaddr = 0x%x\n",__FUNCTION__, cecdMsg.notice.target_src, cecdMsg.notice.phyAddr);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

/*
HRESULT cec_NoticeMenuLanguage(CEC_t *pcec, UINT8 OsdLang)
{
	CECD_MSG cecdMsg;
	char lang[3] = {0};

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticeMenuLanguage;
	transferLang(OsdLang, lang);
	memcpy(cecdMsg.notice.lng_str, lang, 3);

	UMFDBG(0, "%s language=%c%c%c\n",__FUNCTION__, lang[0], lang[1], lang[2]);
	msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);

	return S_OK;
}
*/

void cec_NoticeMenuLanguage(UINT8 OsdLang)
{
	if(CECTV_GetCECEnable()== CECTV_DISABLE)
	{
		return;
	}
	UMFDBG(0,"%s OsdLang=%d\n",__FUNCTION__, OsdLang);
	CECD_MSG cecdMsg;
	char lang[3] = {0};

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticeMenuLanguage;
	transferLang(OsdLang, lang);

	memcpy(cecdMsg.notice.lng_str, lang, 3);
	//memcpy(cecOsdlang, lang, 3);

	UMFDBG(0,"%s language=%c%c%c\n",__FUNCTION__, lang[0], lang[1], lang[2]);
	//msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);
	cecd_UmfEventHandle(&cecdMsg);

}
HRESULT cec_NoticePowerStatus(CEC_t *pcec)
{
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_NoticePowerStatus;
	//cecdMsg.notice.power_state = pcec->powerState;

	UMFDBG(0, "%s power_state=%d\n",__FUNCTION__, cecdMsg.notice.power_state);
	//msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);
	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

//=======================================================
// UMF Network Control CEC
//=======================================================
void cec_RefreshDeviceList(void)
{

	CECD_MSG cecdMsg;
	CEC_t *pcec = cec_GetHandle();

	DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
	
	memset(pdeviceList, 0, SIZE_OF_CECDEVICE_LIST);

	if (!pcec->bCECExecuted)
		return;

	cecdMsg.MsgType = CECDMSG_NETWORK_CONTROL;
	cecdMsg.CmdType = CMD_RefreshDeviceList;

	UMFDBG(0, "%s\n",__FUNCTION__);

	cecd_UmfEventHandle(&cecdMsg);
	gfDeviceDiscover = TRUE;
	//DeviceListTimestamp=tv_GetClockMilliseconds();
}


void cec_RemoveDevice(LOGADDR logAddr)
{
    CECD_MSG cecdMsg;
	cecdMsg.MsgType = CECDMSG_NETWORK_CONTROL;
	cecdMsg.CmdType = CMD_RemoveDevice;
    cecdMsg.network.logAddr = logAddr;

    UMFDBG(0, "%s  LogAddr=%d\n",__FUNCTION__, logAddr);

    cecd_UmfEventHandle(&cecdMsg);
}

HRESULT cec_AssignDisplayDevice(CEC_t *pcec, PHYADDR phyAddr, LOGADDR logAddr)
{
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_NETWORK_CONTROL;
	cecdMsg.CmdType = CMD_AssignDisplayDevice;
	cecdMsg.network.phyAddr = phyAddr;
	cecdMsg.network.logAddr = logAddr;

	UMFDBG(0, "%s PhyAddr=0x%x, LogAddr=%d\n",__FUNCTION__, phyAddr, logAddr);

	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

HRESULT cec_Report_Features(CEC_t *pcec)
{
	CECD_MSG cecdMsg;
	
	if (!pcec->bCECExecuted)
		return S_OK;
		
	cecdMsg.MsgType = CECDMSG_NOTICE_CECD;
	cecdMsg.CmdType = CMD_ReportFeatures;
	cecdMsg.notice.cec_version = Version20;
	cecdMsg.notice.all_device_type = ADT_TV;
	cecdMsg.notice.rc_profile = 0x1;
	cecdMsg.notice.device_features = 0x1;

	UMFDBG(0, "%s cec_version=%d, all_device_type=%d, rc_profile= %d, device_features = %d\n",
		__FUNCTION__, cecdMsg.notice.cec_version, cecdMsg.notice.all_device_type,cecdMsg.notice.rc_profile,cecdMsg.notice.device_features);
	
	cecd_UmfEventHandle(&cecdMsg);
	return S_OK;
}


//=========================================================
// CEC send MSQ to UMF
//=========================================================
HRESULT cec_Recevice_Report_Features(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice)
{
	UMFDBG(0, "Receive %s \n",__FUNCTION__);

	UMFDBG(0, " cec_version %d, all_device_type %d, rc_profile %d,  device_features %d \n", pnotice->cec_version, pnotice->all_device_type, pnotice->rc_profile, pnotice->device_features);
	return S_OK;
}


HRESULT cec_Recevice_Give_Features(void)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	CEC_t *pcec = cec_GetHandle();

	cec_Report_Features(pcec);//need report features by broadcast
	return S_OK;
}


HRESULT cec_ReportTVPowerOff(void)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);

	//[Marco] Need new shutdown function
	/*PUMFDev_t pumfdev = &g_umfdev;

	if (cec_GetHDMIControl(FALSE) || bChannelScanning == FALSE)
	{
		ir_InsertKey(&pumfdev->irdev, KEYCODE_Power, KEYSTATUS_NORMAL);
	}*/
	CECTV_MessageBody_t stEvt;

	if (CECTV_GetCECEnable()== CECTV_ENABLE
#if defined (CONFIG_DTV_SUPPORT) || defined (CONFIG_ATV_SUPPORT)
	&& AL_CS_IsStop() == al_true
#endif
	)
	{
		UMFDBG(0, "Notice TV PowerOff\n");
		stEvt.dMessage = CECTV_MESSAGE_STANDBY;
		stEvt.dParam = 0xff;
		_SendEvt(stEvt);
	}
	return S_OK;
}

HRESULT cec_ReportCecdStatus(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	pcec->cecState = pnotice->state;
	bUpdateState = TRUE;

	if (pcec->cecState == CS_INIT_OK)
	{
		//cec_NoticeMenuLanguage(APP_OSDLANG_ENGLISH); //Don't set language at cec, set by app
		if(CECTV_GetCECEnable())
		{//21/01/2013 Modify by Ian, block NoticeSourceChange to HDMI to avoid power on CEC device
			cec_NoticeSourceChange(pcec);
		}
		else
		{//21/01/2013 Modify by Ian,If cec control is OFF, notice CEC active source to other source
			CEC_t tempCEC={0};
			tempCEC.inputSource=SRC_OTHERS;
			cec_NoticeSourceChange(&tempCEC);
		}
		//if(abs(tv_GetClockDiff(DeviceListTimestamp))>DEVICELISINTERVAL)
		{
			cec_RefreshDeviceList();
		}
	}

	return S_OK;
}

HRESULT cec_ReportActiveSource(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice) //SRC_HDMI_1 <-> SRC_HDMI_2
{
	CECTV_MessageBody_t stEvt;

	UMFDBG(0,"Receive %s, toSrc=%d, inputSrc=%d, LogAddr=%d, viewonState=%d\n",__FUNCTION__, pnotice->toSrc,
		pcec->inputSource, pnotice->active_logAddr, pnotice->viewon_state);
	pcec->menuState = MS_DEACTIVATED;

	if (CECTV_GetCECEnable() == CECTV_DISABLE)// || bChannelScanning == TRUE)
		return S_OK;

#if defined (CONFIG_DTV_SUPPORT) || defined (CONFIG_ATV_SUPPORT)
	if(AL_CS_IsStop() == al_false)
	{		
		cec_ChangeSource(SRC_OTHERS);
		return S_OK;
	}
#endif
	if (pcec->inputSource != pnotice->toSrc)
	{
		//if (ptv->bCHScanStop)//Remark this line temporarily
		{
#ifdef CONFIG_HDMI_ALL_PORT_TERMINATION_ON
			clock_gettime(CLOCK_MONOTONIC, &time2);
			UMFDBG(0,"time1 = %d, time2 = %d\n",(UINT32)time1.tv_sec, (UINT32)time2.tv_sec);
			if ((time2.tv_sec - time1.tv_sec) <= 5) // For specific Philips player send active source immediately after set to other hdmi source, and set source back to Philips source.		
			{	
				memcpy(&time1,&time2,sizeof(time1));
				return S_OK;		
			}
			memcpy(&time1,&time2,sizeof(time1));
#endif
			
			pcec->inputSource = pnotice->toSrc;
			#if 0
			pthread_mutex_lock(&pumfdev->irdev.signalmut);
			if(Input != 0xffffffff)
			{
				requestSource = Menu_GetSourceIDEntry(Input);
				//BaseScrReturnScreen(HS_EVENT_SOURCE);
				{
					STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CUSTOMIZE, EV_TYPE_CEC_SETSOURCE);
				}
			}
			pthread_mutex_unlock(&pumfdev->irdev.signalmut);
			#endif

			stEvt.dMessage = CECTV_MESSAGE_CHANGE_SOURCE;
        	stEvt.dParam = pnotice->toSrc;
			if(stEvt.dParam !=0)
        		_SendEvt(stEvt);

		}
	}
	//if (ptv->bCHScanStop)//Remark this line temporarily
	{
		pcec->PhyAddr = pnotice->phyAddr;
		pcec->LogAddr = pnotice->active_logAddr;
		//[Remove old menu command]
		//if (pnotice->viewon_state == VS_TEXT && CTL_GetMenuState()) //if TV Menu is opened in text view on, TV need to close it
		//~[Remove old menu command]
		//if (pnotice->viewon_state == VS_TEXT) //if TV Menu is opened in text view on, TV need to close it
		//{
			//keycode.key = KEYCODE_Menu;
			//umf_MsgHandle(pumfdev, keycode);
		//}
	}
	//printf("cec_ReportActiveSource End\n");
	if((pnotice->active_logAddr == PLAYBACK_DEVICE_1_LOGICAL_ADDR)||(pnotice->active_logAddr == PLAYBACK_DEVICE_2_LOGICAL_ADDR)||(pnotice->active_logAddr == PLAYBACK_DEVICE_3_LOGICAL_ADDR))//Check if this message coming from playback device at gActivePort
	{
		gPlayBackDevice = pnotice->active_logAddr;
	}
	
	// Refresh CEC Device
	//if (pcec->inputSource != CECTV_CheckDeviceSoruce(pcec->LogAddr))	//Device List maybe wrong
	//{
		//cec_RefreshDeviceList();
	//}
	return S_OK;
}

HRESULT cec_ReportInactiveSource(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice)
{
	UMFDBG(0, "Receive %s PhyAddr=%d, LogAddr=%d\n",__FUNCTION__, pnotice->phyAddr, pnotice->active_logAddr);

	if (CECTV_GetCECEnable() == CECTV_DISABLE)// || bChannelScanning == TRUE)
	{
		return S_NOTHANDLE;
	}

	//if (bCHScanStop)
	{
		//pthread_mutex_lock(&pumfdev->irdev.signalmut);//sset source by event, don't need this
/*
		requestSource = Menu_GetSourceIDEntry(SRCID_DTV);
*/
		//cec_SetInputSrc(ptv->lastSource);
		#if 0
		UINT32 lastSrcID=ptv->lastSource;
		requestSource = Menu_GetSourceIDEntry(lastSrcID);
		//BaseScrReturnScreen(HS_EVENT_SOURCE);
		{
			STB_ERSendEvent(FALSE, FALSE, EV_CLASS_CUSTOMIZE, EV_TYPE_CEC_SETSOURCE);
		}
		//pthread_mutex_unlock(&pumfdev->irdev.signalmut);
		#endif
	}

	return S_OK;
}

HRESULT cec_ReportDeviceList(CEC_t *pcec, CECDMSG_NETWORK *pnetwork)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	DEVICEINFO_LIST *pdeviceList;
	INT32 i;
	UINT32 AmpPowerTimeDiff;
	BOOL bFindAudioDevice = FALSE;
	void* shared_memory = shmat(pnetwork->shmId, (void*) 0, 0);
	pdeviceList = &g_CECDeviceList;
	DEVICEINFO_LIST tempDeviceList;
	CECTV_MessageBody_t stEvt;

	clock_gettime(CLOCK_MONOTONIC, &checkIfAmpPowerOff);
	AmpPowerTimeDiff = (UINT32)(checkIfAmpPowerOff.tv_sec - AmpPowerOffTime.tv_sec);
	UMFDBG(0,"checkIfAmpPowerOff = %d,    AmpPowerTimeDiff = %d\n",(UINT32)checkIfAmpPowerOff.tv_sec, AmpPowerTimeDiff);	
	if(AmpPowerTimeDiff < 3  && AmpPowerOffTime.tv_sec  !=0)
		return S_NOTHANDLE;

	if (shared_memory != (void*) (-1))
	{
		memset(pdeviceList, 0, SIZE_OF_CECDEVICE_LIST);
		memset(&tempDeviceList, 0, SIZE_OF_CECDEVICE_LIST);
		memcpy(&tempDeviceList, shared_memory, SIZE_OF_CECDEVICE_LIST);
		if(tempDeviceList.deviceNum==0)
		{
			shmdt(shared_memory);
                            gfDeviceDiscover = FALSE;
		}
		else
		{
			memcpy(pdeviceList, shared_memory, SIZE_OF_CECDEVICE_LIST);
			shmdt(shared_memory);
			bUpdateDevice = TRUE;
                           
			for (i = 0 ;i < pdeviceList->deviceNum ;i++)
			{
				UMFDBG(0,"%s shmId=%d, Index=%d, PhyAddr=0x%x, LogAddr=%d, hdmi_source=%d, device_type=%d, pcec->inputsource=%d, OSD name=%s\n",__FUNCTION__, pnetwork->shmId, i,
					pdeviceList->device[i].physical_addr, pdeviceList->device[i].logical_addr, pdeviceList->device[i].hdmi_source, pdeviceList->device[i].device_type,  pcec->inputSource,pdeviceList->device[i].OSDNAME);

				if((ToggleCount == 0) && (pdeviceList->device[i].physical_addr == 0x0))//device info err, need to toggle one time.
				{
					cec_ReToggelHPD();
					ToggleCount += 1;
					return S_OK;
				}
                
				if (pcec->inputSource == pdeviceList->device[i].hdmi_source)//2011/01/21 zoey
				{
					pcec->LogAddr = pdeviceList->device[i].logical_addr;
					if(pcec->PhyAddr == pdeviceList->device[i].physical_addr || pcec->PhyAddr == CECTV_PHYSICAL_ADDR)
					{
						if((pcec->LogAddr  == PLAYBACK_DEVICE_1_LOGICAL_ADDR)||(pcec->LogAddr  == PLAYBACK_DEVICE_2_LOGICAL_ADDR)||(pcec->LogAddr  == PLAYBACK_DEVICE_3_LOGICAL_ADDR))//Check if this message coming from playback device at gActivePort
					gPlayBackDevice = pdeviceList->device[i].logical_addr;
					}
						//cec_KeyProcess(CECTV_KEY_PLAY);
					UMFDBG(0," LogAddr=0x%x\n", pcec->LogAddr);
				}
				if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM)
				{
					if((cecHdmiPortStatus & (0x1 << (pdeviceList->device[i].hdmi_source-1))) &&
						!((cecHdmiPortStatus) & (0x1 <<(8+(pdeviceList->device[i].hdmi_source-1)))))
				   	{					
						UMFDBG(0,"WARNING!!! ARC_Power5V_PIN=>Low\n");
						bFindAudioDevice = FALSE;
						memset(&pdeviceList->device[i], 0, SIZE_OF_CECDDEVICEINFO);
						pdeviceList->deviceNum--;						
					}
					else
					{
						pcec->systemAudio.logAddr = pdeviceList->device[i].logical_addr;
						pcec->systemAudio.phyAddr = pdeviceList->device[i].physical_addr;
						bFindAudioDevice = TRUE;
						//if(CECTV_GetAudioARC())
						{
							stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
							if (pcec->systemAudio.state == AS_ON && CECTV_GetAudioARC() && preARCStatus == ARC_Active)
								stEvt.dParam = (AMP|AMP_ON|AMP_ARC|ARC_ON);//AMP ARC On
							else
								stEvt.dParam = (AMP|AMP_ON);//AMP ON
							_SendEvt(stEvt);
						}
						//cec_RequestAudioStatus();
					#if 0
						INT8 cmpAMPName[MAX_OSDNAME_LENGTH] = "LT301s";
						if(!strcmp(pdeviceList->device[i].OSDNAME,cmpAMPName) )
						{
						#ifdef CONFIG_SUPPORT_DOLBY_AUDIO							
							Cmd_Hdmi_SetHDMIEDIDAtmosCmd(TRUE);//for some AMP, ask audio format will cause AMP die.
						#endif							
						}
						else 
					#endif
						//cec_RequestShortAudioDescriptor(); // for dd/ dd+ Amp switch hot plug, need to ask again
						
					}
				}

			}
			
		}

		if (!bFindAudioDevice)
		{
			pcec->systemAudio.ARCstatus = ARC_FeatureAbort;
			preARCStatus=0;
			preLogAddr=0;
			prePhyAddr=0;	
		}
		else if( CECTV_GetCECEnable() == CECTV_DISABLE)
		{
			pcec->systemAudio.ARCstatus = ARC_FeatureAbort;
			preARCStatus=0;
			preLogAddr=0;
			prePhyAddr=0;
			cec_Hdmi_ARC_Switch(ARC_DeActive);
			cec_RequestAudioMode(FALSE);
			cec_QueryARCStatus(pcec, ARC_DeActive,2);
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
			Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
#endif
		}
		else
		{

			/*UINT8 audioPort = ((pcec->systemAudio.phyAddr) >> 12);
			if(!(cecHdmiPortStatus & (0x100 << (audioPort-1))))
		   	{
		   		//Add for some device will report audio when device power off.
		   		//So need check HDMI power status to avoid some CEC control open the devices.
				printf("WARNING!!! HDMI PORT low %x--%x--%x\n",
					cecHdmiPortStatus,pcec->systemAudio.phyAddr,audioPort);
				//Disable HDMI HW 5V
				pcec->systemAudio.ARCstatus = ARC_FeatureAbort;
				preARCStatus=0;
				preLogAddr=0;
				prePhyAddr=0;
				return S_OK;
			}*/

			if(preARCStatus==0)
			{
				if(CECTV_GetCECEnable() && CECTV_GetSpeakerPreference())
				{
					if(pcec->systemAudio.state == AS_OFF)
						cec_RequestAudioMode(TRUE);
					cec_QueryARCStatus(pcec, ARC_Active,2);
				}
				else
				{
					cec_Hdmi_ARC_Switch(ARC_DeActive);
					cec_RequestAudioMode(FALSE);
					cec_QueryARCStatus(pcec, ARC_DeActive,2);
				}
			}
			else if(preLogAddr != pcec->systemAudio.logAddr || prePhyAddr != pcec->systemAudio.phyAddr)
			{
				preARCStatus=0;
				if(CECTV_GetCECEnable() && CECTV_GetSpeakerPreference())
				{
					if(pcec->systemAudio.state == AS_OFF)
						cec_RequestAudioMode(TRUE);
					cec_QueryARCStatus(pcec, ARC_Active,2);
				}
				else
				{
					cec_Hdmi_ARC_Switch(ARC_DeActive);
					cec_RequestAudioMode(FALSE);
					cec_QueryARCStatus(pcec, ARC_DeActive,2);
				}
			}
			preLogAddr=pcec->systemAudio.logAddr;
			prePhyAddr=pcec->systemAudio.phyAddr;
		}

	}
	
	gfDeviceDiscover = FALSE;

	//DeviceListTimestamp=tv_GetClockMilliseconds();

	return S_OK;
}

HRESULT cec_ReportPowerStatus(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	
	powerstatus =pnotice->power_state;
	UMFDBG(0," powerstatus = %d\n", powerstatus);

	return S_OK;
}

HRESULT cec_ReportAddDevice(CEC_t *pcec, CECDMSG_NETWORK *pnetwork)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	INT32 i;
	UINT8 Index = 0xff;
	DEVICEINFO_LIST *pdeviceList;
	DEVICEINFO deviceInfo;

	if (CopyFromSharedMemory(pnetwork->shmId, &deviceInfo, SIZE_OF_CECDDEVICEINFO))
	{
		pdeviceList = &g_CECDeviceList;
		for (i = 0; i < pdeviceList->deviceNum; i++)
		{
			if (pdeviceList->device[i].logical_addr == deviceInfo.logical_addr)
			{
				Index = i;
				break;
			}
		}
		if (Index == 0xff)
		{
			memcpy(&pdeviceList->device[pdeviceList->deviceNum], &deviceInfo, SIZE_OF_CECDDEVICEINFO);
			pdeviceList->deviceNum++;
		}
		else
		{
			memcpy(&pdeviceList->device[Index], &deviceInfo, SIZE_OF_CECDDEVICEINFO);
		}
		//[Remove old menu command]
		//CTL_CECinfoUpdate();
		//~[Remove old menu command]
		UMFDBG(0, "%s Index=%d, deviceNum=%d, PhyAddr=0x%x, LogAddr=%d\n",__FUNCTION__,Index,
			pdeviceList->deviceNum, deviceInfo.physical_addr,deviceInfo.logical_addr);
	}

	return S_OK;
}

HRESULT cec_ReportPhysicalAddress(CEC_t *pcec, CECDMSG_NOTICECECD *pnotice)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);
	pcec->PhyAddr = pnotice->phyAddr;
	return S_OK;
}


HRESULT cec_ReportOSDString(CEC_t *pcec, CECDMSG_NETWORK *pnetwork)
{
	UMFDBG(0, "Receive %s\n",__FUNCTION__);

	if (CopyFromSharedMemory(pnetwork->OSDStringshmId, &pcec->osdString, SIZE_OF_OSD_STRING))
	{
		UMFDBG(0, "OSD string=%s, status=%d\n", pcec->osdString.osd_string, pcec->osdString.display_control);
		//[Remove old menu command]
		//CTL_CecShowInfoSpecial(&pcec->osdString);
		//~[Remove old menu command]
	}

	return S_OK;
}

HRESULT cec_ReportDeckStatus(CEC_t *pcec, CECDMSG_DECK *pdeck)
{
	UMFDBG(0, "Receive %s deck state=%d, logAddr=%d\n",__FUNCTION__, pdeck->deckInfo, pdeck->logAddr);
	if (pcec->LogAddr != pdeck->logAddr)
		return S_OK;

	pcec->deckState =  pdeck->deckInfo;
	bUpdateDeck = TRUE;

	return S_OK;
}

HRESULT cec_ReportDeviceMenuStatus(CEC_t *pcec, CECDMSG_MENU *pmenu)
{
	UMFDBG(0, "Receive %s menu state=%d, logAddr=%d\n",__FUNCTION__, pmenu->menuState, pmenu->logAddr);
	if (pcec->LogAddr != pmenu->logAddr)
		return S_OK;

	if (pmenu->menuState == MS_KEYNOTSUPPORTED)
	{
		pcec->uccState = pmenu->menuState;
		if( CECTV_GetCECEnable() )
		{//Add set CEC command if only if CEC on
			//[Marco] Need new OSD function
			//cec_SendOSDEvent(Not_Support);
		}
	}
	else
	{
		pcec->menuState = pmenu->menuState;
	}
	bUpdateMenu = TRUE;

	return S_OK;
}

HRESULT cec_ReportAudioMode(CEC_t *pcec, CECDMSG_AUDIO *paudio)
{
	CECTV_MessageBody_t stEvt;

	UMFDBG(0,"Receive %s audio state=%d\n",__FUNCTION__, paudio->audioModeStatus);

	if (!bDeviceIsExist(paudio->logAddr))	//2011/01/21 zoey
	{
		preARCStatus=0;
		stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
		stEvt.dParam = (AMP|AMP_5V_OFF|AMP_ARC|ARC_OFF);//AMP OFF
		_SendEvt(stEvt);
		
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
		Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
#endif
		return S_OK;
	}

	if (((CECTV_GetCECEnable()== CECTV_DISABLE) ||(!CECTV_GetSpeakerPreference())) && paudio->audioModeStatus==AS_ON)
	{//Ian, 20130204: Let audioModeStatus==AS_OFF pass to store status and do some thing
		cec_Hdmi_ARC_Switch(ARC_DeActive);
		cec_RequestAudioMode(FALSE);
		cec_QueryARCStatus(pcec, ARC_DeActive,2);
		return S_NOTHANDLE;
	}

	/*if(bAudioModeOn==FALSE && paudio->audioModeStatus==AS_ON)
	{//Ian, 20130204: Let audioModeStatus==AS_OFF pass to store status and do some thing
		pcec->systemAudio.state = paudio->audioModeStatus;
		pcec->LogAddr = paudio->logAddr;
		return S_OK;
	}*/

	pcec->systemAudio.logAddr = paudio->logAddr;
	//if (pcec->systemAudio.state != paudio->audioModeStatus)
	{
		pcec->systemAudio.state = paudio->audioModeStatus;
		if (pcec->systemAudio.state == AS_ON)
		{
			/*if (HPStatus)
			{
				pcec->systemAudio.state = AS_OFF;
			}
			else*/
			{
				if (CECTV_GetSpeakerPreference() )
				{
                        
		            if (preARCStatus!=ARC_Active)
                    {
					cec_QueryARCStatus(pcec, ARC_Active,2);
				
                    }
                    else
                    {
			            UMFDBG(0,"ignore cec_QueryARCStatus()\n");
                    }
					stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
					stEvt.dParam = (AMP|AMP_ON|AMP_ARC|ARC_ON);//AMP ARC On
					_SendEvt(stEvt);

				}
				else
				{
					cec_QueryARCStatus(pcec, ARC_DeActive,2);
				}
				
			}
		}
		else// if (!HPStatus)
		{	
			preARCStatus=0;
			stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
			stEvt.dParam = (AMP|AMP_OFF|AMP_ARC|ARC_OFF);//AMP OFF
			_SendEvt(stEvt);

			clock_gettime(CLOCK_MONOTONIC, &AmpPowerOffTime);
			UMFDBG(0,"AmpPowerOffTime = %d\n",(UINT32)AmpPowerOffTime.tv_sec);
			
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
			Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
#endif
		}
	}
	return S_OK;
}

HRESULT cec_ReportAudioVolume(CEC_t *pcec, CECDMSG_AUDIO *paudio)
{
	CECTV_MessageBody_t stEvt;
	UMFDBG(0,"Receive %s audio volume=0x%x\n",__FUNCTION__, paudio->audioVol);

	if (!bDeviceIsExist(paudio->logAddr))	//2011/01/21 zoey
		return S_OK;
	if(powerstatus!=0) // amp off
		return S_OK;

	if (CECTV_GetCECEnable() == CECTV_DISABLE)// || bChannelScanning == TRUE)
	{
		return S_NOTHANDLE;
	}

	pcec->systemAudio.logAddr = paudio->logAddr;
	if (pcec->systemAudio.state == AS_ON)
	{
		if((pcec->systemAudio.volMute != ((paudio->audioVol>>7) & 1)) || (pcec->systemAudio.volLevel != (paudio->audioVol & 0x7f)))
		{
			if (pcec->systemAudio.volMute != ((paudio->audioVol>>7) & 1))
			{
				pcec->systemAudio.volMute = (paudio->audioVol>>7) & 1;
				//[Remove old menu command]
				//CTL_CecMute(pcec->systemAudio.volMute);
				//~[Remove old menu command]
			}
			
			if (pcec->systemAudio.volLevel != (paudio->audioVol & 0x7f))
			{
				pcec->systemAudio.volLevel = paudio->audioVol & 0x7f; //0% ~ 100%
				//[Marco] Need new OSD function
				//cec_SendOSDEvent(CecVolume);
			}
			
			//VolInQueue=FALSE;
			//UCCQueueTimestamp=tv_GetClockMilliseconds();
	    	stEvt.dMessage = CECTV_MESSAGE_SET_MUTE_STATUS;
	    	stEvt.dParam = paudio->audioVol;
	       	_SendEvt(stEvt);
	
			UMFDBG(0, "%s audio volLevel=%d, volMute=%d\n",__FUNCTION__, pcec->systemAudio.volLevel,pcec->systemAudio.volMute);
		}
	}

	if(CECTV_GetSpeakerPreference() && CECTV_GetAudioARC())
	{
		if(pcec->systemAudio.state != AS_ON)
		{
			UMFDBG(0, " %s Set AudioMode Again!!!\n", __FUNCTION__);		
			cec_RequestAudioMode(TRUE);	
		}	
		
		if(CECTV_GetAudioARC() && pcec->systemAudio.ARCstatus != ARC_Active && preQueryARCStatus == ARC_Active)
		{
			UMFDBG(0, " %s Query ARC Again!!!\n", __FUNCTION__);		
			cec_QueryARCStatus(pcec, ARC_Active,2);		
		}	
	}	

	return S_OK;
}

HRESULT cec_ReportAudioARCStatus(CEC_t *pcec, CECDMSG_AUDIO *paudio)
{
	CECTV_MessageBody_t stEvt;
	DEVICEINFO_LIST *pdeviceList;
	pdeviceList = &g_CECDeviceList;
	int i;

	UMFDBG(0,"Receive %s=%d, logAddr=%d\n",__FUNCTION__, paudio->audioRxARCstatus, paudio->logAddr);
	UINT8 ARCStatus = ARC_FeatureAbort;
	//UINT8 audioPort=( (pcec->systemAudio.phyAddr)>>12);

	/*if(!(cecHdmiPortStatus & (0x100 << (audioPort-1))))
   	{
		printf("WARNING!!! HDMI PORT low %x--%x--%x\n",
			cecHdmiPortStatus,pcec->systemAudio.phyAddr,audioPort);
		//Disable HDMI HW 5V
		return E_FAIL;
	}*/

	/*The BAUHN AMP need to turn on ARC first, and then turn on Audio mode.*/
	INT8 cmpAMPName[MAX_OSDNAME_LENGTH] = "ASBB-114";
	for (i = 0 ;i < pdeviceList->deviceNum ;i++)
	{
		if(CECTV_GetCECEnable() && CECTV_GetAudioARC() && paudio->audioRxARCstatus == 1 
			&& !strcmp(pdeviceList->device[i].OSDNAME,cmpAMPName) 
			&& pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM)
		{
			UMFDBG(0,"Special AMP: %s, need to turn on ARC first!!\n",pdeviceList->device[i].OSDNAME);
			
			ARCStatus = ARC_Active;
        	pcec->systemAudio.ARCstatus = paudio->audioRxARCstatus;
			cec_RequestARC(pcec, ARC_Active);
			cec_RequestAudioMode(TRUE);
			preARCStatus=ARCStatus;
			return S_OK;
		}
	}

	if( !(CECTV_GetCECEnable()))//Fix conditin incorrect form rev.1475
	{
		//Add set CEC command if only if CEC on
		UMFDBG(0,"WARNING!!! CONTROL =%d\n",CECTV_GetCECEnable());
		//if(preARCStatus == ARC_Active)
		{	
			stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
			stEvt.dParam = (AMP_ARC|ARC_OFF);//AMP ARC OFF
			_SendEvt(stEvt);
			cec_RequestARC(pcec, ARC_DeActive);
#ifndef SUPPORT_HDMI_ARC			
			cec_Hdmi_ARC_Switch(ARC_DeActive);
#endif
			pcec->systemAudio.ARCstatus = ARC_DeActive;
			ARCStatus = pcec->systemAudio.ARCstatus;
		}
		preARCStatus=ARCStatus;
		
		return S_NOTHANDLE;
	}

	if((!CECTV_GetAudioARC() || !CECTV_GetSpeakerPreference())&& paudio->audioRxARCstatus==ARC_Active)
	{
		UMFDBG(0,"WARNING!!! cec_GetAudioARC =%d\n",CECTV_GetAudioARC());
		cec_RequestARC(pcec, ARC_DeActive);
#ifndef SUPPORT_HDMI_ARC		
		cec_Hdmi_ARC_Switch(ARC_DeActive);
#endif
		pcec->systemAudio.ARCstatus = ARC_DeActive;
		preARCStatus = pcec->systemAudio.ARCstatus;
		return S_NOTHANDLE;
	}

	if(preQueryARCStatus!=paudio->audioRxARCstatus && (preQueryARCStatus!=ARC_FeatureAbort && paudio->audioRxARCstatus != ARC_FeatureAbort ))
	{
		//means current report status is not last status
		UMFDBG(0,"WARNING!!! QUERY %d =?= report %d \n",
			preQueryARCStatus,paudio->audioRxARCstatus);
		return E_FAIL;
	}

	//pcec->systemAudio.ARCstatus = paudio->audioRxARCstatus;
	if (paudio->audioRxARCstatus == ARC_Active && CECTV_GetAudioARC())
	{
		pcec->systemAudio.state = AS_ON ;
		
		//In this, mean ARC function can work.
		ARCStatus = ARC_Active;

        pcec->systemAudio.ARCstatus = paudio->audioRxARCstatus;

        //if(preARCStatus!=ARCStatus)
		{

			stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
			stEvt.dParam = (AMP|AMP_ON|AMP_ARC|ARC_ON);//AMP ARC On
			_SendEvt(stEvt);
			cec_RequestARC(pcec, ARCStatus);
			/*ap will set, and protect by mutex*/
//#ifndef SUPPORT_HDMI_ARC			
//			cec_Hdmi_ARC_Switch(ARCStatus);
//#endif			
			cec_RequestAudioStatus();//for HIKEEN special AMP. QueryARC not report vol. state, need to ask again.			
		}
		preARCStatus=ARCStatus;
	}
	else if( paudio->audioRxARCstatus == ARC_DeActive )
	{
		//In this, mean ARC function disable.
		stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
		stEvt.dParam = (AMP_ARC|ARC_OFF);//AMP ARC OFF
		_SendEvt(stEvt);
		pcec->systemAudio.volMute = 0;
		pcec->systemAudio.volLevel = 0;
		cec_RequestARC(pcec, ARC_DeActive);
#ifndef SUPPORT_HDMI_ARC		
		cec_Hdmi_ARC_Switch(ARC_DeActive);
#endif		
		pcec->systemAudio.ARCstatus = paudio->audioRxARCstatus;
		preARCStatus=ARCStatus;
	}
	else if( paudio->audioRxARCstatus == ARC_FeatureAbort)
	{
		stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
		stEvt.dParam = (AMP_ARC|ARC_OFF);//AMP ARC OFF
		_SendEvt(stEvt);
		pcec->systemAudio.volMute = 0;
		pcec->systemAudio.volLevel = 0;	
		pcec->systemAudio.ARCstatus = paudio->audioRxARCstatus;
		preARCStatus=ARCStatus;
	}

	return S_OK;
}

HRESULT cec_ReportAudioCodecCapability(CEC_t *pcec, CECDMSG_AUDIO *paudio)
{
	DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
	INT32 i = 0;
	
	#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
	CECTV_MessageBody_t stEvt;
	BOOL Atmos = FALSE;
	BOOL DDPlus = FALSE;
	#else
	TVFE_Audio_INFO_t AudioInfo = {0};
	UINT32 audioFormat = 0;
	#endif
	UINT8 ARCPort = HDMI_ARC_PORT_INDEX;
    #if (HDMI_ARC_PORT_INDEX != -1)
    {
        ARCPort = ((CONFIG_HDMI_PORT_MAP & (0xf<<HDMI_ARC_PORT_INDEX*4)) >> HDMI_ARC_PORT_INDEX*4);
    }
    #endif
	
	for (i = 0; i < paudio->audioNumFormatCodec; i++)
    {
        if (i < 16)
        {
        	switch(paudio->audioFormat[i].audioFormatCodec)
        	{
				#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
				case Audio_Format_DDPlus:
					DDPlus = TRUE;
					if(paudio->audioFormat[i].audioAtmos == 1)
						Atmos = TRUE;
					else
						Atmos = FALSE;
					break;
				default:
					break;
				#else
				case Audio_Format_AC3:
					audioFormat |= AUDIO_FEATURE_AC3;
					break;
				case Audio_Format_AAC:
					audioFormat |= AUDIO_FEATURE_AAC;
					break;
				case Audio_Format_DDPlus:
					audioFormat |= AUDIO_FEATURE_EAC3;
					break;
				default:
					break;
				#endif	
        	}				       
        }
        else
        {
            UMFDBG(0, "AudioCodecCapability:Error: i >=16 \n");
        }
    }
	
#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
	if(bcec_Atmos!=Atmos || bcec_DDPlus!=DDPlus)
	{
		stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
		stEvt.dParam = (AMP_AUDIO_FORMAT);//send audio SPDIF format info. to audio driver.
		_SendEvt(stEvt);
	}

	// record atmos value
	bcec_Atmos = Atmos;
	bcec_DDPlus = DDPlus;
#endif

	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		#ifdef CONFIG_SUPPORT_DOLBY_AUDIO
		if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM && pdeviceList->device[i].hdmi_source == ARCPort)
		{
			if ( CECTV_GetCECEnable() == CECTV_ENABLE )
			{
				if(!CECTV_GetAudioARC() || !CECTV_GetSpeakerPreference())
				{
					Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE);
				}
				else
				{
					Cmd_Hdmi_SetHDMIEDIDAtmosCmd(Atmos);
				}
			}
			UMFDBG(0, " %s, Amp at ARC port %d, Atmos:%d, sent format to audio\n",__FUNCTION__, ARCPort, Atmos);
			break;
		}
		#else
		if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM && pdeviceList->device[i].hdmi_source == ARCPort)
		{
			AudioInfo.flag = SEND_INFO_HDMI_CEC;
			AudioInfo.cec_audio_format = audioFormat;
			TVFE_Audio_Send_AudioInfo(&AudioInfo);
			UMFDBG(0, " %s, Amp at ARC port %d, sent format to audio\n",__FUNCTION__, ARCPort);
			break;
		}
		#endif
	}	
	
	//UMFDBG(0, "Receive %s, audioNumFormatCodec=%d, audioFormat=0x%x\n",__FUNCTION__, paudio->audioNumFormatCodec, AudioInfo.cec_audio_format);

	return S_OK;
}

HRESULT cec_RequestCurrentLatency(CEC_t *pcec, CECDMSG_AUDIO *paudio)
{
	UMFDBG(0,"Receive %s, logAddr=%d\n",__FUNCTION__, paudio->logAddr);
	CECD_MSG cecdMsg;

	cecdMsg.MsgType = CECDMSG_SYSTEM_AUDIO_CONTROL;
	cecdMsg.CmdType = CMD_ReportCurrentLatency;
	cecdMsg.audio.logAddr = 0xf;//pcec->systemAudio.logAddr;
	cecdMsg.audio.vlatency= 32; //video latenct
	cecdMsg.audio.lflgs=(Reserved_Latency_Flags |Low_Latency_Mode_Normal |Audio_Output_Com_Partially);//  latency flag
	cecdMsg.audio.aod=10; //audio output delay

	UMFDBG(0,"Send ReportCurrentLatency: %d, %d, %d, addr = 0x%x\n", cecdMsg.audio.vlatency, cecdMsg.audio.lflgs, cecdMsg.audio.aod, cecdMsg.audio.logAddr);
	cecd_UmfEventHandle(&cecdMsg);
	return S_OK;
}


void cec_CecdHandler(CECD_MSG *cecdMsg)
{
	UMFDBG(0,"===> %s MsgType = %d\n", __FUNCTION__, cecdMsg->MsgType);
	//CEC_t *pcec = (CEC_t *)arg;
	CEC_t *pcec = cec_GetHandle();
	//CECD_MSG cecdMsg;

	//while(1)
	{
		/*if(msgrcv(pcec->CECtoUMFMsqid, &cecdMsg, CECD_MSG_SIZE, 0, 0) == -1)
		{
			UMFDBG(0,"%s  CEC MsqQ Delete\n",__FUNCTION__);
			break;
		}*/

		switch(cecdMsg->MsgType)
		{
			case CECDMSG_NOTICE_UMF:
				if (cecdMsg->CmdType == CMD_ReportTVPowerOff)
					cec_ReportTVPowerOff();
				else if (cecdMsg->CmdType == CMD_ReportCecdStatus)
					cec_ReportCecdStatus(pcec, &cecdMsg->notice);
				else if (cecdMsg->CmdType == CMD_ReportActiveSource)
					cec_ReportActiveSource(pcec, &cecdMsg->notice);
				else if (cecdMsg->CmdType == CMD_ReportInactiveSource)
					cec_ReportInactiveSource(pcec, &cecdMsg->notice);
				else if (cecdMsg->CmdType == CMD_ReportPhysicalAddress)
					cec_ReportPhysicalAddress(pcec, &cecdMsg->notice);
				else if(cecdMsg->CmdType == CMD_ReportPowerStatus)
					cec_ReportPowerStatus(pcec, &cecdMsg->notice);
				else if(cecdMsg->CmdType == CMD_ReportFeatures)
					cec_Recevice_Report_Features(pcec, &cecdMsg->notice);
				else if(cecdMsg->CmdType == CMD_GIVE_FEATURES)
					cec_Recevice_Give_Features();
				break;
			case CECDMSG_NETWORK_REPORT:
				if (cecdMsg->CmdType == CMD_ReportDeviceList)
					cec_ReportDeviceList(pcec, &cecdMsg->network);
				else if (cecdMsg->CmdType == CMD_ReportAddDevice)
					cec_ReportAddDevice(pcec, &cecdMsg->network);
				else if (cecdMsg->CmdType == CMD_ReportOSDString)
					cec_ReportOSDString(pcec, &cecdMsg->network);			
				
				break;
			case CECDMSG_DECK_REPORT:
				if (cecdMsg->CmdType == CMD_ReportDeckStatus)
					cec_ReportDeckStatus(pcec, &cecdMsg->deck);
				break;
			case CECDMSG_DEVICE_MENU_REPORT:
				if (cecdMsg->CmdType == CMD_ReportDeviceMenuStatus)
					cec_ReportDeviceMenuStatus(pcec, &cecdMsg->menu);
				break;
			case CECDMSG_SYSTEM_AUDIO_REPORT:
				if (cecdMsg->CmdType == CMD_ReportAudioMode)
					cec_ReportAudioMode(pcec, &cecdMsg->audio);
				else if (cecdMsg->CmdType == CMD_ReportAudioVolume)
					cec_ReportAudioVolume(pcec, &cecdMsg->audio);
				else if (cecdMsg->CmdType == CMD_ReportAudioARCStatus)
					cec_ReportAudioARCStatus(pcec, &cecdMsg->audio);
				else if (cecdMsg->CmdType == CMD_ReportAudioCodecCapability)
					cec_ReportAudioCodecCapability(pcec, &cecdMsg->audio);
				else if(cecdMsg->CmdType ==CMD_RequestCurrentLatency)
					cec_RequestCurrentLatency(pcec,&cecdMsg->audio);
				break;
			default:
				UMFDBG(0, "Unknown CEC message type: %d\n", cecdMsg->MsgType);
				break;
		}
	}
}

//=======================================================
// UMF Deck Control CEC
//=======================================================
HRESULT cec_QueryDeckStatus(CEC_t *pcec)
{
	CECD_MSG cecdMsg;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_DECK_CONTROL;
	cecdMsg.CmdType = CMD_QueryDeckStatus;
	//cecdMsg.deck.logAddr = pcec->LogAddr;
	cecdMsg.deck.logAddr = gPlayBackDevice;

	UMFDBG(0, "%s logAddr=%d\n",__FUNCTION__, pcec->LogAddr);
	//msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);
	cecd_UmfEventHandle(&cecdMsg);

	return S_OK;
}

INT32 cec_DeckControl(UINT8 CECTV_KEY)
{
	CEC_t *pcec = cec_GetHandle();
	CECD_MSG cecdMsg;
	deck_control_t deckControl;
	UINT8 counter;
	bUpdateDeck = FALSE;

	switch(CECTV_KEY)
	{
		case CECTV_KEY_PLAY:
			//query first -- check current player is play or pause
			cec_QueryDeckStatus(pcec);
			counter = waitUpdateCECMsg(&bUpdateDeck, 30); //wait for deck state update
			if (counter >= 30)
			{
				UMFDBG(0, "%s deck control no response!!\n",__FUNCTION__);
			}
			if(pcec->deckState == DS_PLAY)
			{
				CECTV_KEY = CECTV_KEY_PAUSE;
				cec_UserControlCode(CECTV_KEY);//turn out the "play" key to "pause" key
				bPlaying = FALSE;
				return S_OK;
			}
			else if(pcec->deckState < DS_START || pcec->deckState > DS_END)
			{
				if(bPlaying)
				{
					CECTV_KEY = CECTV_KEY_PAUSE;
					bPlaying = FALSE;
				}
				else
				{
					CECTV_KEY = CECTV_KEY_PLAY;
					bPlaying = TRUE;
				}
				cec_UserControlCode(CECTV_KEY);//turn out the "play" key to "pause" key				
				return S_OK;
			}
			else	
			{
				deckControl = DC_PLAY_FORWARD;
			}

			break;
		case CECTV_KEY_STOP:
			deckControl = DC_STOP;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_FORWARD:
			deckControl = DC_SKIP_FORWARD_OR_WIND_FORWARD;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_BACKWARD:
			deckControl = DC_SKIP_BACKWARD_OR_REWIND;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_EJECT:
			deckControl = DC_EJECT;
			bPlaying = FALSE;
			break;
		default:
			//[Remove old menu command]
			//CTL_ShowNotAvailable();
			//~[Remove old menu command]
			return S_OK;
	}
	cecdMsg.MsgType = CECDMSG_DECK_CONTROL;
	cecdMsg.CmdType = CMD_DeckControl;
	//cecdMsg.deck.logAddr = pcec->LogAddr;
	cecdMsg.deck.logAddr = gPlayBackDevice;
	cecdMsg.deck.deckCmd = deckControl;

	UMFDBG(0, "%s logAddr=%d, deckControl=%d\n",__FUNCTION__, cecdMsg.deck.logAddr,deckControl);
	//msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);
	cecd_UmfEventHandle(&cecdMsg);

	counter = waitUpdateCECMsg(&bUpdateDeck, 20); //wait 2s
	if (counter >= 20)
	{
		UMFDBG(0, "%s deck control no response!!\n",__FUNCTION__);
		return E_FAIL;
	}
	else if (pcec->deckState == DS_NOTSUPPORTED)
	{
		//STB_ERSendEvent(FALSE, FALSE, EV_CLASS_UI, EV_NOT_SUPPORT);
		if(CECTV_KEY == CECTV_KEY_PLAY)
		{
			if(bPlaying)
			{
				CECTV_KEY = CECTV_KEY_PAUSE;
				bPlaying = FALSE;
			}
			else
			{
				bPlaying = TRUE;
			}
		}

		cec_UserControlCode(CECTV_KEY);
	}

	return S_OK;
}

//=======================================================
// UMF Device Menu Control CEC
//=======================================================
HRESULT cec_RequestDeviceMenuStatus(CEC_t *pcec, menu_request_t menuRequestType, UINT8 waitSecs)
{
	CECD_MSG cecdMsg;
	UINT8 waitTime=waitSecs*10;

	bUpdateMenu = FALSE;

	if (!pcec->bCECExecuted)
		return S_OK;

	cecdMsg.MsgType = CECDMSG_DEVICE_MENU_CONTROL;
	cecdMsg.CmdType = CMD_RequestDeviceMenuStatus;
	cecdMsg.menu.logAddr = pcec->LogAddr;
	cecdMsg.menu.menuRequestType = menuRequestType;

	UMFDBG(0, "%s logAddr=%d, menuRequestType=%d\n",__FUNCTION__, pcec->LogAddr,menuRequestType);
	//msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0);
	cecd_UmfEventHandle(&cecdMsg);

	if(waitTime>0)
	{

	}

	return pcec->menuState;
}

BOOL sendUserControlCode(user_control_code_t userControlCode ,UINT8 waitSecs)
{
	CEC_t *pcec = cec_GetHandle();
	BOOL exeResult=FALSE;
	UINT8 waitTime=waitSecs*10;

	CECD_MSG cecdMsg;
	cecdMsg.MsgType = CECDMSG_DEVICE_MENU_CONTROL;
	cecdMsg.CmdType = CMD_RemoteControlPassThrough;
	//cecdMsg.menu.logAddr = pcec->LogAddr;
	cecdMsg.menu.logAddr = gPlayBackDevice;
	cecdMsg.menu.userControlCode = userControlCode;
	
	UMFDBG(0,"%s logAddr=%d, userControlCode=%d, pcec->inputsrc=%d\n",__FUNCTION__, cecdMsg.menu.logAddr,userControlCode, pcec->inputSource);

	if(pcec->inputSource != CECTV_CheckDeviceSoruce(cecdMsg.menu.logAddr))
	{
		UMFDBG(0,"%s pcec->inputsrc=%d, logAddr[%d].deviceSource=%d, don't send key\n",__FUNCTION__, pcec->inputSource, cecdMsg.menu.logAddr, CECTV_CheckDeviceSoruce(cecdMsg.menu.logAddr));
		return exeResult;
	}
	
	//if(msgsnd(pcec->UMFtoCECMsqid, &cecdMsg, CECD_MSG_SIZE, 0) == -1)
	//{
	//	printf("\e[1;42m[UMF][cec_SendIRKeycodeToCECDevice]ERROR!!!!!!msgsnd fail with param %d \e[0m\n",errno);
	//	return E_FAIL;
	//}
	cecd_UmfEventHandle(&cecdMsg);

	exeResult=TRUE;
	if(waitSecs>0)//If set waitsec >0, wait response
	{
		UINT8 counter;
		counter = waitUpdateCECMsg(&bUpdateMenu, waitTime); //wait second
		if (counter >= waitTime)
		{
			UMFDBG(0, "%s UCC state no response!!\n",__FUNCTION__);
			exeResult=FALSE;
		}
		else if (pcec->uccState == MS_KEYNOTSUPPORTED)
		{
			pcec->uccState = E_FAIL;
			exeResult=FALSE;
		}
	}

	return exeResult;
}

INT32 cec_RemoteControlPassThrough(UINT8 CECTV_KEY)
{
	user_control_code_t userControlCode;
	bUpdateMenu = FALSE;

	UMFDBG(0,"[UMF] %s CECTV_KEY=0x%x\n", __FUNCTION__, CECTV_KEY);

	switch(CECTV_KEY)
	{
		case CECTV_KEY_UP:
			userControlCode = UCC_Up;
			break;
		case CECTV_KEY_DOWN:
			userControlCode = UCC_Down;
			break;
		case CECTV_KEY_LEFT:
			userControlCode = UCC_Left;
			break;
		case CECTV_KEY_RIGHT:
			userControlCode = UCC_Right;
			break;
		case CECTV_KEY_SELECT:
			userControlCode = UCC_Select;
			break;
		case CECTV_KEY_ENTER:
			userControlCode = UCC_Enter;
			break;
		case CECTV_KEY_EXIT:
			userControlCode = UCC_Exit;
			break;
		case CECTV_KEY_0:
		case CECTV_KEY_1:
		case CECTV_KEY_2:
		case CECTV_KEY_3:
		case CECTV_KEY_4:
		case CECTV_KEY_5:
		case CECTV_KEY_6:
		case CECTV_KEY_7:
		case CECTV_KEY_8:
		case CECTV_KEY_9:
			userControlCode = UCC_0+(CECTV_KEY-CECTV_KEY_0);
			break;
		default:
			cec_KeyProcess(CECTV_KEY);
			return S_OK;
	}

	sendUserControlCode(userControlCode,0);

	return S_OK;
}

INT32 cec_KeyProcess(UINT8 CECTV_KEY)
{
	CEC_t *pcec = cec_GetHandle();
	//menu_status_t menustate;

	if(CECTV_GetCECEnable() == CECTV_DISABLE)
	{
		return S_NOTHANDLE;
	}

	switch(CECTV_KEY)
	{

		case CECTV_KEY_PLAY:
		case CECTV_KEY_STOP:
		case CECTV_KEY_FORWARD:
		case CECTV_KEY_BACKWARD:
		case CECTV_KEY_EJECT:
#ifdef SUPPORT_CEC_DECK_CONTROL
			cec_DeckControl(CECTV_KEY);
			break;
#endif
		case CECTV_KEY_ROOT_MENU:
		case CECTV_KEY_SETUP_MENU:
		case CECTV_KEY_CONTENTS_MENU:
		case CECTV_KEY_FAVORITE_MENU:
		case CECTV_KEY_PAGE_DOWN:
		case CECTV_KEY_PAGE_UP:
		case CECTV_KEY_RECORD:
		case CECTV_KEY_PAUSE:
		case CECTV_KEY_SOUND_SELECT:
		case CECTV_KEY_SUB_PICTURE:
		case CECTV_KEY_REWIND:
		case CECTV_KEY_FAST_FORWARD:
		case CECTV_KEY_PAUSE_PLAY_FUNC:
			cec_UserControlCode(CECTV_KEY);
			break;
		case CECTV_KEY_MUTE:
		case CECTV_KEY_MUTE_RELEASE:
			//if (pcec->systemAudio.state == AS_ON && !ptv->HPStatus)
			if (pcec->systemAudio.state == AS_ON)
			{
				//if(VolInQueue==FALSE)
				//if(abs(tv_GetClockDiff(UCCQueueTimestamp))>UCCKEYTIMEINTERVAL)//Add abs for avoid timestamp less than system time
				{
					//UCCQueueTimestamp=tv_GetClockMilliseconds();
					//avoid send too much vol key to CECD
					cec_RemoteControlAudioVolume(pcec, CECTV_KEY);
					cec_RequestAudioStatus();
				}
			}
			else{
				//[Remove old menu command]
				//MenuKeyProcess(keycode.key, keycode.status);
				//~[Remove old menu command]
			}
			break;
		case CECTV_KEY_VOLUME_UP:
		case CECTV_KEY_VOLUME_DOWN:
		case CECTV_KEY_VOLUME_UP_RELEASE:
		case CECTV_KEY_VOLUME_DOWN_RELEASE:
			//if (pcec->systemAudio.state == AS_ON && !ptv->HPStatus)
			if (pcec->systemAudio.state == AS_ON)
			{
				//if(VolInQueue==FALSE)
				//if(abs(tv_GetClockDiff(UCCQueueTimestamp))>UCCKEYTIMEINTERVAL)//Add abs for avoid timestamp less than system time
				{
					//UCCQueueTimestamp=tv_GetClockMilliseconds();
					//avoid send too much vol key to CECD
					cec_RemoteControlAudioVolume(pcec, CECTV_KEY);
					if(CECTV_KEY == CECTV_KEY_VOLUME_UP || CECTV_KEY == CECTV_KEY_VOLUME_DOWN)
						cec_RequestAudioStatus();
				}
			}
			else{
				//[Remove old menu command]
				//MenuKeyProcess(keycode.key, keycode.status);
				//~[Remove old menu command]
			}
			break;
	#if 0
		case KEYCODE_CECAudio:
			if (keycode.status != KEYSTATUS_NORMAL) return S_OK;
				cec_SetSystemAudio();
			break;
		case KEYCODE_CECMenu:
			if (keycode.status != KEYSTATUS_NORMAL) return S_OK;
			if (pcec->menuState == MS_MENUNOTSUPPORTED){
				//printf("==CEC==CECMenu Not support !\n");
				//STB_ERSendEvent(FALSE, FALSE, EV_CLASS_UI, EV_NOT_SUPPORT);
				cec_SendOSDEvent(Not_Support);
			}
			else
			{
				menustate = cec_RequestDeviceMenuStatus(pcec, MRT_QUERY,2);
				if (menustate != E_FAIL)
				{
					if (menustate == MS_MENUNOTSUPPORTED){
						//STB_ERSendEvent(FALSE, FALSE, EV_CLASS_UI, EV_NOT_SUPPORT);
						cec_SendOSDEvent(Not_Support);
						//printf("==CEC==CECMenu Not support 2!\n");
					}
					else
					{
						menustate = (menustate == MS_ACTIVATED) ? MRT_DEACTIVATE : MRT_ACTIVATE;
						cec_RequestDeviceMenuStatus(pcec, menustate,2);
					}
				}
			}
			break;
		#endif
		case CECTV_KEY_UP:
		case CECTV_KEY_DOWN:
		case CECTV_KEY_LEFT:
		case CECTV_KEY_RIGHT:
		case CECTV_KEY_SELECT:
		case CECTV_KEY_EXIT:
		case CECTV_KEY_0:
		case CECTV_KEY_1:
		case CECTV_KEY_2:
		case CECTV_KEY_3:
		case CECTV_KEY_4:
		case CECTV_KEY_5:
		case CECTV_KEY_6:
		case CECTV_KEY_7:
		case CECTV_KEY_8:
		case CECTV_KEY_9:
			cec_RemoteControlPassThrough(CECTV_KEY);
			break;
		default:
			//[Remove old menu command]
			//MenuKeyProcess(keycode.key, keycode.status);
			//~[Remove old menu command]
			break;
	}

	return S_OK;
}

INT32 cec_UserControlCode(UINT8 CECTV_KEY)
{
	user_control_code_t userControlCode;

	switch(CECTV_KEY)
	{
		case CECTV_KEY_ROOT_MENU:
			userControlCode = UCC_Root_Menu;
			break;
		case CECTV_KEY_SETUP_MENU:
			userControlCode = UCC_Setup_Menu;
			break;
		case CECTV_KEY_CONTENTS_MENU:
			userControlCode = UCC_Contents_Menu;
			break;
		case CECTV_KEY_FAVORITE_MENU:
			userControlCode = UCC_Favorite_Menu;
			break;
		case CECTV_KEY_PAGE_UP:
			userControlCode = UCC_Page_Up;
			break;
		case CECTV_KEY_PAGE_DOWN:
			userControlCode = UCC_Page_Down;
			break;
		case CECTV_KEY_RECORD:
			userControlCode = UCC_Record;
			break;
		case CECTV_KEY_PAUSE:
			userControlCode = UCC_Pause;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_SOUND_SELECT:
			userControlCode = UCC_Sound_Select;
			break;
		case CECTV_KEY_SUB_PICTURE:
			userControlCode = UCC_Sub_Picture;
			break;
		case CECTV_KEY_BACKWARD:
			userControlCode = UCC_Backward;
			break;
		case CECTV_KEY_FORWARD:
			userControlCode = UCC_Forward;
			break;
		case CECTV_KEY_PLAY:
			userControlCode = UCC_Play;
			bPlaying = TRUE;
			break;
		case CECTV_KEY_PAUSE_PLAY_FUNC:			
			{
				if(bPlaying)
				{	
					userControlCode = UCC_Pause;
					bPlaying = FALSE;
				}
				else
				{
					userControlCode = UCC_Play;
					bPlaying = TRUE;
				}
			}
			break;
		case CECTV_KEY_STOP:
			userControlCode = UCC_Stop;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_EJECT:
			userControlCode = UCC_Eject;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_REWIND:
			userControlCode = UCC_Rewind;
			bPlaying = FALSE;
			break;
		case CECTV_KEY_FAST_FORWARD:
			userControlCode = UCC_Fast_Forward;
			bPlaying = FALSE;
			break;
		default:
			return S_OK;
	}

	sendUserControlCode(userControlCode,0);

	return S_OK;
}

//=======================================================
tv_source_t cec_QueryPlayBackDeviceLogaddr(tv_source_t tvsource)
{
	DEVICEINFO_LIST *pdeviceList;
	tv_source_t deviceLogaddr = (tv_source_t)gPlayBackDevice;
	UINT32 i;	
	
	pdeviceList = &g_CECDeviceList;
	
	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		if (pdeviceList->device[i].hdmi_source == tvsource)
		{
			deviceLogaddr = (tv_source_t)(pdeviceList->device[i].logical_addr);
			break; 	
		}
	}	
	return deviceLogaddr;
}

UINT32 cec_QueryPlayBackDevicePhyaddr(tv_source_t tvsource)
{
	DEVICEINFO_LIST *pdeviceList;
	UINT32 devicePhyaddr = 0x0;
	UINT32 i;	
	
	pdeviceList = &g_CECDeviceList;
	
	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		if (pdeviceList->device[i].hdmi_source == tvsource && pdeviceList->device[i].device_type ==DEVICE_TYPE_DVD)
		{
			devicePhyaddr = pdeviceList->device[i].physical_addr;
			break; 	
		}
	}
	return devicePhyaddr;
}

void cec_ChangeSource(tv_source_t tvsource)
{
	CEC_t *pcec = cec_GetHandle();
	
	if (!pcec->bCECExecuted)
		return;
	UMFDBG(0,"%s pcec->inputSource=%d, tvsource=%d\n",__FUNCTION__, pcec->inputSource, tvsource);
	
	if (pcec->inputSource != tvsource 
#if defined (CONFIG_DTV_SUPPORT) || defined (CONFIG_ATV_SUPPORT)
	|| AL_CS_IsStop() == al_false
#endif
	)
	{
		pcec->menuState = MS_DEACTIVATED;
		pcec->LogAddr = 0xff;
		pcec->PreSource = pcec->inputSource;
		pcec->inputSource = tvsource;
		if (tvsource == SRC_OTHERS)
			pcec->PhyAddr = CECTV_PHYSICAL_ADDR;

		#ifdef CONFIG_HDMI_ALL_PORT_TERMINATION_ON
		if (tvsource < SRC_END)
		{
			clock_gettime(CLOCK_MONOTONIC, &time1);
		}
		#endif

		gPlayBackDevice = cec_QueryPlayBackDeviceLogaddr(tvsource);
		cec_NoticeSourceChange(pcec);
		if ((pcec->PreSource > SRC_OTHERS && pcec->PreSource < SRC_END) && tvsource == SRC_OTHERS && CECTV_GetAudioARC() && pcec->systemAudio.state)
			cec_QueryARCStatus(pcec, ARC_Active, 2);
	}
	
	UMFDBG(0,"%s NewSrc=%d logaddr=0x%x\n",__FUNCTION__, tvsource, pcec->LogAddr);
}
//=======================================================
// for Menu
//=======================================================

void CECTV_SetRequestARC(bool val)
{
	CEC_t *pcec = cec_GetHandle();
	if(val==TRUE)
		cec_RequestARC(pcec, ARC_Active);
	else	
		cec_RequestARC(pcec, ARC_DeActive);
}

INT32 CECTV_SetDeviceNum(UINT8 DevIndex)
{
	if( CECTV_GetCECEnable()== CECTV_DISABLE )
	{
		//Add set CEC command if only if CEC on
		return S_NOTHANDLE;
	}
	CEC_t *pcec = cec_GetHandle();
	DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
	UINT8 source;
	PHYADDR phyAddr;
	LOGADDR logAddr;
	bUpdateState = FALSE;

	UMFDBG(0,"........................%s  Device Index=%d\n",__FUNCTION__,DevIndex);

	if (DevIndex >= MAX_DEVICE_NUM)
		return E_FAIL;

	source = pdeviceList->device[DevIndex].hdmi_source;
	phyAddr = pdeviceList->device[DevIndex].physical_addr;
	logAddr = pdeviceList->device[DevIndex].logical_addr;
	cec_AssignDisplayDevice(pcec, phyAddr, logAddr);

	if (pcec->inputSource != source)
	{
		cec_ChangeSource(pcec->inputSource);
	}
	pcec->PhyAddr = phyAddr;
	pcec->LogAddr = logAddr;

	return S_OK;
}

DEVICEINFO_LIST *cec_UpdateDeviceList(void)
{
	bUpdateDevice = FALSE;

	UMFDBG(0, "%s start\n",__FUNCTION__);

	cec_RefreshDeviceList();

	return &g_CECDeviceList;

}

//=======================================================

struct timespec cecdiff(struct timespec start, struct timespec end) 
{
  struct timespec temp;
  if ((end.tv_nsec-start.tv_nsec)<0) {
    temp.tv_sec = end.tv_sec-start.tv_sec-1;
    temp.tv_nsec = 1000000000+end.tv_nsec-start.tv_nsec;
  } else {
    temp.tv_sec = end.tv_sec-start.tv_sec;
    temp.tv_nsec = end.tv_nsec-start.tv_nsec;
  }
  return temp;
}

void cec_SetTvAutoPwrOn(BOOL status)
{
	CecTvAutoPwrOn = status;

	ioctl(kmfdev, KMF_IOC_CECAUTOPOWERON, status);

	UMFDBG(0,"%s state=%d\n",__FUNCTION__, status);
}

#if 0

BOOL cec_GetTvAutoPwrOn(BOOL bDefault)
{
	PTV_t ptv = getptv();
	MenuSetting_t *pMenuSetting = ptv->pMenuSetting;

	UMFDBG(0, "%s state=%d\n",__FUNCTION__,CecTvAutoPwrOn);
	return CecTvAutoPwrOn;
}
#endif

//=======================================================
#ifdef SUPPORT_CEC_TV
INT32 CECTV_HDMIPortStatus(UINT32 HdmiPortStatus)    //Bilibala 2011/02/16
{
	CECTV_MessageBody_t stEvt;
	DEVICEINFO_LIST *pdeviceList = &g_CECDeviceList;
	UINT8 i = 0;
	UINT8 ampSrc = 0;
	BOOL bRefreshList = TRUE;
         struct timespec quickplugdetect;
	UINT8 DeviceNum = 0;
	//printf("[LAI]%s,%d  ~~~~~~~~~0x%x\n",__FUNCTION__,__LINE__,HdmiPortStatus);

	UMFDBG(0,"HDMIPortStatus, %x 0x%x\n", cecHdmiPortStatus,HdmiPortStatus);

	if(cecHdmiPortStatus == 0xffff)
	{
		UMFDBG(0,"update cecHdmiPortStatus\n");
		cecHdmiPortStatus = HdmiPortStatus;
		return S_OK;
	}
	if(HdmiPortStatus == 0x0)
		return E_FAIL;
	if((cecHdmiPortStatus & 0xff00) == (HdmiPortStatus&0xff00))
	    return S_OK;

	for (i = 0; i < pdeviceList->deviceNum; i++)
	{
		if (pdeviceList->device[i].device_type == DEVICE_TYPE_AUDIO_SYSTEM)
		{
			ampSrc = pdeviceList->device[i].hdmi_source - 1;
			break; 
		}
	}

	//First 8 bits(bit 7~ bit0) record HDMI if change. Following 8 bit(bit 15 ~ bit 8) record HMDI status
	for(i=0; i<CONFIG_HDMI_NUM; i++)
	{
		if(HdmiPortStatus & (0x1 << i) && !((HdmiPortStatus) & (0x1 <<(8+i))))
		{	
		   	if(i == ampSrc)
		   	{
		   	 	bcec_Atmos = FALSE;
			 	bcec_DDPlus = FALSE;

				CEC_t *pcec = cec_GetHandle();
				if(CECTV_GetCECEnable()==CECTV_ENABLE)
				{
					UMFDBG(0,"ARC_Power5V_PIN=>Low\n");									
					#ifdef CONFIG_SUPPORT_DOLBY_AUDIO												
					Cmd_Hdmi_SetHDMIEDIDAtmosCmd(FALSE); //reset default atmos.
					#endif
					//cec_SetAudioARC(FALSE);
					cec_EnableARCfunctionTimer(FALSE);
					cec_SendDeactivedARCTX(pcec);
					pcec->systemAudio.state = AS_OFF;
					pcec->systemAudio.ARCstatus = ARC_DeActive;
					pcec->systemAudio.volMute = 0;
					pcec->systemAudio.volLevel = 0;
					preARCStatus = ARC_FeatureAbort;
					preQueryARCStatus = ARC_FeatureAbort;
					stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
					stEvt.dParam =  (AMP_ARC|ARC_OFF|AMP|AMP_5V_OFF);//ARC OFF
					_SendEvt(stEvt);
				    UMFDBG(0,"Switch to TV Speakers\n");
				}
				else

				{
					//stEvt.dMessage = CECTV_MESSAGE_SET_SYSTEMAUDIO_STATUS;
					//stEvt.dParam =  (AMP|AMP_5V_OFF);//AMP_5V_OFF
					//_SendEvt(stEvt);
				}
		   	}	
			bRefreshList = TRUE;

		}
	}

    if((HdmiPortStatus&0xff)) // means port change
    {
        if((cecHdmiPortStatus&0x0100)==0x100  && (HdmiPortStatus&0x0100)==0x0 ) // port 1
        {
		DeviceNum = pdeviceList->deviceNum;
		DEVICEINFO tempdevicelist[MAX_DEVICE_NUM] ;
		int k =0;
		memset(tempdevicelist, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);
		
		for (i = 0; i < DeviceNum; i++)
		 {	
			if ((pdeviceList->device[i].physical_addr & 0x1000) == 0x1000)
			{
				cec_RemoveDevice(pdeviceList->device[i].logical_addr);
				memset(&pdeviceList->device[i], 0x0, SIZE_OF_CECDDEVICEINFO);
				//if(DeviceNum>1 && i!=DeviceNum-1)
				//	memcpy(&pdeviceList->device[i],&pdeviceList->device[i+1],SIZE_OF_CECDDEVICEINFO);
				pdeviceList->deviceNum --;
			}
			else
			{
				memcpy(&tempdevicelist[k] ,&pdeviceList->device[i],sizeof(DEVICEINFO));
				k++;
			}
		}
	 	memset(pdeviceList->device, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);	
	   	memcpy(pdeviceList->device, tempdevicelist,sizeof(DEVICEINFO)*MAX_DEVICE_NUM);		

            UMFDBG(0,"1 port device remove\n");
            cecHdmiPortStatus = HdmiPortStatus;
            return S_OK;
        }
        else if((cecHdmiPortStatus&0x0200)==0x200  && (HdmiPortStatus&0x0200)==0x0) //port 2
        {         
           	 DeviceNum = pdeviceList->deviceNum;
		DEVICEINFO tempdevicelist[MAX_DEVICE_NUM] ;
		int k =0;
		memset(tempdevicelist, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);
		
	            for (i = 0; i < DeviceNum; i++)
	        	   {
	        	   	
	        		if ((pdeviceList->device[i].physical_addr & 0x2000) == 0x2000)
	        		{
	        			cec_RemoveDevice(pdeviceList->device[i].logical_addr);
				memset(&pdeviceList->device[i], 0x0, SIZE_OF_CECDDEVICEINFO);
				//if(DeviceNum>1 && i!=DeviceNum-1)
				//	memcpy(&pdeviceList->device[i],&pdeviceList->device[i+1],SIZE_OF_CECDDEVICEINFO);
				pdeviceList->deviceNum --;
	        		}
			else
			{
				memcpy(&tempdevicelist[k] ,&pdeviceList->device[i],sizeof(DEVICEINFO));
				k++;
			}
	        	   }
		memset(pdeviceList->device, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);	
	  	 memcpy(pdeviceList->device, tempdevicelist,sizeof(DEVICEINFO)*MAX_DEVICE_NUM);		

	   
            UMFDBG(0,"2 port device remove\n");
            cecHdmiPortStatus = HdmiPortStatus;
            return S_OK;
        }
        else if((cecHdmiPortStatus&0x0400)==0x400  && (HdmiPortStatus&0x0400)==0x0) //port 3
        {
		DeviceNum = pdeviceList->deviceNum;
		DEVICEINFO tempdevicelist[MAX_DEVICE_NUM] ;
		int k =0;
		memset(tempdevicelist, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);

		for (i = 0; i < DeviceNum; i++)
		 {	
			if ((pdeviceList->device[i].physical_addr & 0x3000) == 0x3000)
			{
				cec_RemoveDevice(pdeviceList->device[i].logical_addr);
				memset(&pdeviceList->device[i], 0x0, SIZE_OF_CECDDEVICEINFO);
				//if(DeviceNum>1 && i!=DeviceNum-1)
				//	memcpy(&pdeviceList->device[i],&pdeviceList->device[i+1],SIZE_OF_CECDDEVICEINFO);
				pdeviceList->deviceNum --;
			}
			else
			{
				memcpy(&tempdevicelist[k] ,&pdeviceList->device[i],sizeof(DEVICEINFO));
				k++;
			}
		}
		memset(pdeviceList->device, 0x0, sizeof(DEVICEINFO)*MAX_DEVICE_NUM);	
		memcpy(pdeviceList->device, tempdevicelist,sizeof(DEVICEINFO)*MAX_DEVICE_NUM);		

            UMFDBG(0,"3 port device remove\n");
            cecHdmiPortStatus = HdmiPortStatus;
            return S_OK; 
        }
    }
    
	cecHdmiPortStatus = HdmiPortStatus;

    clock_gettime(CLOCK_MONOTONIC, &quickplugdetect);
    struct timespec plugdiff= cecdiff(g_quickplugdetect, quickplugdetect);

    UMFDBG(0,"temp.tv_sec: %ld\n", plugdiff.tv_sec);
    UMFDBG(0,"tem.ptv_nsec: %ld\n", plugdiff.tv_nsec);

	if(bRefreshList)
	{
	    if(plugdiff.tv_sec < 1)
            {
                umfsleep(2, 0);
                cec_RefreshDeviceList();
               }
              else
		cec_RefreshDeviceList();
		//cec_RequestShortAudioDescriptor();
	}
	g_quickplugdetect = quickplugdetect;
	//Move to cecd receive report physical address
	//cec_RefreshDeviceList();

	return S_OK;
}
#endif
static void _Destroy(CEC_t *pcec)
{
	if (!pcec->bCECExecuted)
		return;

	UMFDBG(0, "==>%s\n", __FUNCTION__);

	cecd_disable();

	UMFDBG(0, "<==%s\n", __FUNCTION__);
}
#if 0
static void _Suspend(CEC_t *pcec)
{
	if (!pcec->bCECExecuted)
		return;

	if (gfCECTVEnable)
	{
		cec_NoticeStandby(pcec, TRUE);
	}
}
#endif
void _Stop(void)
{
	CEC_t *pcec = cec_GetHandle();
	UINT8 counter = 0;

	if (!pcec->bCECExecuted)
		return;

	UMFDBG(0,"==>%s\n", __FUNCTION__);
	
	if (gfCECTVEnable)
	{
		if (pcec->systemAudio.ARCstatus == ARC_Active)
			cec_RequestARC(pcec, ARC_DeActive);
		
		cec_NoticeStandby(pcec, TRUE);

		while(pcec->cecState != CS_EXIT_OK && counter < 20)
		{
#ifdef watchdog
			wdog_main_counter = 0;
#endif

			if(counter == 0)
			{
				UMFDBG(0,"Waiting CEC standby");
			}
			else
			{
				UMFDBG2(0, ".");
			}
			umfsleep(0, 100000000); //0.1s*20
			counter++;
		}
		//counter = waitUpdateCECMsg(&bUpdateState, 20); //wait 2s
		_Destroy(pcec);
	}
	else
	{
		_Destroy(pcec);
	}
	pcec->bCECExecuted = FALSE;

	UMFDBG(0, "<==%s\n", __FUNCTION__);
}

CECTV_Status_e CECTV_SendCmd(UINT32 dMessage, UINT32 dParam)
{
	CEC_CmdBody_t stMsg;

    stMsg.dMessage = dMessage;
    stMsg.dParam = dParam;

    GL_QueueSend(_hCECTVCmdQueue, &stMsg, sizeof(CEC_CmdBody_t));

    return CECTV_SUCCESS;
}

void CECTV_MainRoutine(void* pParam)
{
	static BOOL CECEnableStatus = 1;

    _stCECRcvBuf.pstCmd = NULL;
    _stCECRcvBuf.pstAckList = NULL;
   // _stCECRcvBuf.pstFrm = NULL;
    _stCECSendBuf.pstEvtList = NULL;
    //_stCECSendBuf.pstFrmList = NULL;

    while (1)
    {
     	if(CECTV_GetCECEnable()==CECTV_ENABLE)
     	{
			if(CECTV_GetCECTaskStatus()!=CEC_TASK_Standby)
			{
	        	_RcvModule();
		        //_MultiActionModule();
		        _SingleActionModule();
			}
			else if(CECTV_GetCECTaskStatus()==CEC_TASK_Standby)
			{
				if(_stCECRcvBuf.pstCmd!=NULL)
				{
		       	 	free(_stCECRcvBuf.pstCmd);
		        	_stCECRcvBuf.pstCmd = NULL;
				}
		        //free(_stCECRcvBuf.pstFrm);
		        //_stCECRcvBuf.pstFrm = NULL;
			}
	        _SendModule();
			if (CECEnableStatus == 0)
			{
			    _stCECRcvBuf.pstCmd = NULL;
			    _stCECRcvBuf.pstAckList = NULL;
			    //_stCECRcvBuf.pstFrm = NULL;
			    _stCECSendBuf.pstEvtList = NULL;
			    //_stCECSendBuf.pstFrmList = NULL;
	 			//MID_CECTV_Enable(TRUE);
				CECEnableStatus =1;
			}

     	}
	 	else
	 	{
	 		_RcvModule();
			if(_stCECRcvBuf.pstCmd!=NULL)
			{
				free(_stCECRcvBuf.pstCmd);
	        	_stCECRcvBuf.pstCmd = NULL;
			}

			_stCECSendBuf.pstEvtList = NULL;
			//_stCECSendBuf.pstFrmList = NULL;
			
			if (CECEnableStatus == 1)
			{
				//MID_CECTV_Enable(DTV_FALSE);
				//_LADevice[MID_CECTV_LA_AUDIO_SYSTEM].AliveFlag=FALSE;
				if(CECTV_GetAudioARC())
				{
					cec_SetAudioARC(FALSE);
					cec_EnableARCfunctionTimer(FALSE);
				}	
				cec_SetCECenable(CECTV_DISABLE);
				CECEnableStatus =0;
			}
			if (gfDeviceDiscover==FALSE)
			{
 		    	if(CECTV_GetCECTaskStatus()!=CEC_TASK_IDLE)
		    	{
					CECTV_SetCECTaskStatus(CEC_TASK_IDLE);
					CEC_TASK_IDLE_CNT=0;
		    	}
				else
				{
					CEC_TASK_IDLE_CNT++;
				}
				if(CEC_TASK_IDLE_CNT>20)
				{
					//cec_RefreshDeviceList();
				}
 			}
	 	}

        GL_TaskSleep(CECTV_DAEMON_DELAY);

    }

}

static GL_Task_t CECTV_DAEMON = NULL;

void CECTV_Init(CECTV_ModualCfg_t *pCEC_ModualCfg)
{
	CEC_t *pcec = cec_GetHandle();

	if (pcec->bCECExecuted)
		return;

	//[Marco] Temp variable & structure initilize
	pcec->menuState = MS_DEACTIVATED;
	pcec->LogAddr = g_pKMFShareData->CecLogAddr;
	pcec->inputSource = (tv_source_t)(g_pKMFShareData->CecPwrOnSrc);
	#ifdef CONFIG_HDMI_ALL_PORT_TERMINATION_ON
	clock_gettime(CLOCK_MONOTONIC, &time1);
	#endif
         clock_gettime(CLOCK_MONOTONIC, &g_quickplugdetect);
	//bCHScanStop = TRUE;
	//HPStatus = FALSE;
	CecAudioARC = FALSE;
	//cecHdmiPortStatus = ptv->pKMFShareData->iHDMIStatus;
	//bAudioModeOn = ptv->pMenuSetting->CecAudioARC;
	bAudioModeOn = FALSE;
	
	UmfHandler_Register(cec_CecdHandler);
	cecd_enable();
	pcec->bCECExecuted = TRUE;

	//[Marco] need new time function
	//Add initial to get device list
	//if(abs(tv_GetClockDiff(DeviceListTimestamp))>DEVICELISINTERVAL)
	{
//		cec_RefreshDeviceList();
	}

	if ((pCEC_ModualCfg != NULL) && (pCEC_ModualCfg->pfCallBack != NULL))
	{
		g_pfCECCallback = pCEC_ModualCfg->pfCallBack;
	}

    if (GL_SUCCESS !=  GL_TaskCreate("CEC TV Daemon",(void*)CECTV_MainRoutine, NULL,
    									3,
    									4096,						// thread stack size
    									TRUE,					// resume after created
    									&(CECTV_DAEMON)))
    {
		printf("[%s:%d] CEC TV Daemon thread create fail !!!\n",__FUNCTION__,__LINE__);
	}
	
    if (GL_SUCCESS !=  GL_QueueCreate("CEC Cmd Queue", sizeof(CEC_CmdBody_t), 32, 0, &_hCECTVCmdQueue))
    {
		printf("[%s:%d] CEC Cmd Queue create fail !!!\n",__FUNCTION__,__LINE__);
	}

	UMFDBG(0,"<=== %s\n", __FUNCTION__);

}



