/**
 * @file hv_mw_Hdcp.c
 * @brief MiddleWare Hdcp c file.
 * @details This file provides the following functions: \n
 *          (1) Hdcp1x FSM function for HDMI \n
 *          (2) Hdcp2x FSM function for HDMI \n
 *
 * @author HiView SoC Software Team
 * @version 1.0.0
 * @date 2022-08-31
 * @copyright Copyright(c),2022-8, Hiview Software. All rights reserved.
 * @par History:
 * <table>
 * <tr><th>Author                    <th>Date         <th>Change Description
 * <tr><td>HiView SoC Software Team  <td>2022-08-31   <td>Create First Version
 * </table>
*/
#include "hv_mw_Hdcp.h"
#include "hv_comm_Define.h"
#include "hv_comm_DataType.h"
#include "hv_mw_SystemManager.h"
#include "hv_vos_Comm.h"
#include "hv_vos_Task.h"
#include "hv_mw_Hdmi.h"

VOID Hv_Mw_Hdcp1x_HdmiRxB1Computations(HdcpCtrlData* pstHdcpData);

/*
 * B0: Unauthenticated
 * B1: Compute Km
 * B2: Compute L
 * B3: Compute Ks
 * B4: Authenticated
 */
Status Hv_Mw_Hdcp_SetHdmiRxData(HdcpCtrlData* pstHdcpData, LinkPortIndex enInputPortIndex, UCHAR8 ucHdmiPortIndex)
{
    HV_ASSERT_VALID_PTR(pstHdcpData);
    UCHAR8 ucHdcpId = pstHdcpData->ucHdcpIndex;

    pstHdcpData->enInputPortIndex = enInputPortIndex;
    pstHdcpData->enHdcpPortType = HdcpPortType_Hdmi;
    pstHdcpData->ucPortIndex = ucHdmiPortIndex;
    pstHdcpData->stHdcpRx.stHdcp1xRx.BCaps = 0;
    pstHdcpData->enCurrentPort2xState = HdcpPortState_B0;
    pstHdcpData->stHdcpRx.enHdcp2xMsgState = HDCP2X_SEND_MSG_INVALID;
    pstHdcpData->stHdcpRx.stHdcp2xRx.stParams.RxCaps[0] = HdcpVesion_Hdcp2X;
    pstHdcpData->stHdcpRx.stHdcp2xRx.stParams.RxCaps[1] = 0;
    pstHdcpData->stHdcpRx.stHdcp2xRx.stParams.RxCaps[2] = 0;

    Hv_Drv_Hdcp_InitSel(ucHdcpId, 1);

    Hv_Drv_Hdcp_SetLaneClk(ucHdmiPortIndex + 2, ucHdcpId);

    Hv_Drv_Hdcp_HdmiMuxSel(ucHdmiPortIndex, ucHdcpId);

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_HdmiReAtherOnSync(LinkPortIndex enInputPortIndex, BOOL bForced)
{
    HdcpCtrlData* pstHdcpData = NULL;
    UCHAR8 ucHdcpPortIndex  = 0;

    for(ucHdcpPortIndex = 0; ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM; ucHdcpPortIndex++)
    {
        pstHdcpData = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortIndex);

        if(enInputPortIndex != pstHdcpData->enInputPortIndex)
        {
            continue;
        }

        /* 找到对应的HDCP口了后释放 */
        if(pstHdcpData->enCurrentPort2xState == HdcpPortState_B4)
        {
            if((pstHdcpData->bAuth && Hv_Drv_Hdcp2x_IsHdmiInEncryed(pstHdcpData->ucHdcpIndex)) || bForced)
            {
                Hv_Drv_Hdcp2x_HdmiSetRxStatusReAuth(pstHdcpData->ucPortIndex);
                pstHdcpData->bAuth = HV_FALSE;
                HV_LOG_INFO(HDCP, "HDCP%d 2X Sync REAUTHENTICATED!", pstHdcpData->ucHdcpIndex);
            }
            else
            {
                Hv_Drv_Hdcp2x_HdmiStartRxAuthCallBack(pstHdcpData->ucPortIndex);
            }
        }

        if(pstHdcpData->bHdcp1XReAuthed == HV_TRUE 
            && pstHdcpData->enHdcpVersion == HdcpVesion_Hdcp1X)
        {
            Hv_Mw_Hdcp1x_HdmiRxB1Computations(pstHdcpData);
        }
    }

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_HdmiSetEessQstc(LinkPortIndex enInputPortIndex)
{
    HdcpCtrlData* pstHdcpData = NULL;
    UCHAR8 ucHdcpPortIndex  = 0;

    for(ucHdcpPortIndex = 0; ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM; ucHdcpPortIndex++)
    {
        pstHdcpData = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortIndex);

        if(enInputPortIndex == pstHdcpData->enInputPortIndex)
        {
            if(HdcpVesion_Hdcp1X == pstHdcpData->enHdcpVersion)
            {
                Hv_Drv_Hdcp1x_HdmiRxSetEessQstc(ucHdcpPortIndex);
                
                //HV_LOG_INFO(HDCP, "HDMI%d Have Set the HDCP1X to EESS.", pstHdcpData->ucPortIndex, ucHdcpPortIndex);
            }

            return HV_SUCCESS;
        }
    }

    return HV_SUCCESS;
}

UCHAR8 Hv_Mw_Hdcp_HdmiGetReAuthStatus(LinkPortIndex enInputPortIndex)
{
    UCHAR8 ucStatus = 0;
    if (LINK_PORT_INDEX_HDMI_RX0 == enInputPortIndex)
    {
        ucStatus = Hv_Drv_Hdcp_HdmiGetReAuthStatus(0);
    }

    if (LINK_PORT_INDEX_HDMI_RX1 == enInputPortIndex)
    {
        ucStatus = Hv_Drv_Hdcp_HdmiGetReAuthStatus(1);
    }

    return ucStatus;
}

static Status Hv_Mw_Hdcp2x_RxHdmiGetMsg(Hdcp2xRx *pstHdcp2xRxIns)
{
    UINT32 uiMsgId = 0;
    HV_ASSERT_VALID_PTR(pstHdcp2xRxIns);
    HDCP2X_RX_Msg *MsgPtr = (HDCP2X_RX_Msg*)pstHdcp2xRxIns->aucMsgBuff;
    uiMsgId = pstHdcp2xRxIns->aucMsgBuff[0];

    switch(uiMsgId)
    {
        case HV_HDCP_2X_RX_MSG_ID_AKEINIT:
        {
            Hv_Drv_Hdcp2x_RxResetParams(pstHdcp2xRxIns);
            HV_MEMCPY(pstHdcp2xRxIns->stParams.Rtx, MsgPtr->AKEInit.Rtx, HV_HDCP_2X_RX_RTX_SIZE);
            HV_MEMCPY(pstHdcp2xRxIns->stParams.TxCaps, MsgPtr->AKEInit.TxCaps, HV_HDCP_2X_RX_TXCAPS_SIZE);
            break;
        }
        case HV_HDCP_2X_RX_MSG_ID_AKENOSTOREDKM:
        {
            HV_MEMCPY(pstHdcp2xRxIns->stParams.EKpubKm, MsgPtr->AKENoStoredKm.EKpubKm, HV_HDCP_2X_TX_E_KPUB_KM_SIZE);
            break;
        }
        case HV_HDCP_2X_RX_MSG_ID_AKESTOREDKM:
        {
            HV_MEMCPY(pstHdcp2xRxIns->stParams.EKhKm, MsgPtr->AKEStoredKm.EKhKm, HV_HDCP_2X_TX_EKH_KM_SIZE);
            HV_MEMCPY(pstHdcp2xRxIns->stParams.M, MsgPtr->AKEStoredKm.M, HV_HDCP_2X_RX_M_SIZE);
            break;
        }
        case HV_HDCP_2X_RX_MSG_ID_LCINIT:
        {
            HV_MEMCPY(pstHdcp2xRxIns->stParams.Rn, MsgPtr->LCInit.Rn, HV_HDCP_2X_TX_RN_SIZE);
            break;
        }
        case HV_HDCP_2X_RX_MSG_ID_SKESENDEKS:
        {
            HV_MEMCPY(pstHdcp2xRxIns->stParams.EDkeyKs, MsgPtr->SKESendEks.EDkeyKs, HV_HDCP_2X_Rx_EDKEYKS_SIZE);
            HV_MEMCPY(pstHdcp2xRxIns->stParams.Riv, MsgPtr->SKESendEks.Riv, HV_HDCP_2X_RX_RIV_SIZE);
            break;
        }
        default:
        {
            HV_LOG_INFO(HDCP, "No Match Msg Id %d .", uiMsgId);
            return HV_FAILURE;
        }
    }
    return HV_SUCCESS;
}

static Status Hv_Mw_Hdcp2x_HdmiRxSetMsg(HdcpRx* pstHdcpRxIns, UCHAR8 ucMsgId, UCHAR8 ucPortIndex)
{
    USHORT16 usMsgSize = 0;

    /* Verify arguments */
    HV_ASSERT_VALID_PTR(pstHdcpRxIns);
    HV_MEMSET(pstHdcpRxIns->stHdcp2xRx.aucMsgBuff, 0, sizeof(pstHdcpRxIns->stHdcp2xRx.aucMsgBuff));
    HDCP2X_RX_Msg *MsgPtr = (HDCP2X_RX_Msg*)pstHdcpRxIns->stHdcp2xRx.aucMsgBuff;

    MsgPtr->AKESendCert.MsgId = ucMsgId;
    usMsgSize += 1;
    switch(ucMsgId)
    {
        case HV_HDCP_2X_RX_MSG_ID_AKESENDCERT:
        {
            HV_MEMCPY(MsgPtr->AKESendCert.RxCaps, pstHdcpRxIns->stHdcp2xRx.stParams.RxCaps, HV_HDCP_2X_RX_RXCAPS_SIZE);
            usMsgSize += HV_HDCP_2X_RX_RXCAPS_SIZE;
            HV_MEMCPY(MsgPtr->AKESendCert.CertRx, pstHdcpRxIns->stHdcp2xRx.pucPubCert, HV_HDCP_2X_RX_CERT_SIZE);
            usMsgSize += HV_HDCP_2X_RX_CERT_SIZE;
            HV_MEMCPY(MsgPtr->AKESendCert.Rrx, pstHdcpRxIns->stHdcp2xRx.stParams.Rrx, HV_HDCP_2X_RX_RRX_SIZE);
            usMsgSize += HV_HDCP_2X_RX_RRX_SIZE;
            break;
        }

        case HV_HDCP_2X_RX_MSG_ID_AKESENDHPRIME:
        {
            HV_MEMCPY(MsgPtr->AKESendHPrime.HPrime, pstHdcpRxIns->stHdcp2xRx.stParams.HPrime, HV_HDCP_2X_RX_HPRIME_SIZE);
            usMsgSize += HV_HDCP_2X_RX_HPRIME_SIZE;
            break;
        }

        case HV_HDCP_2X_RX_MSG_ID_AKESENDPAIRINGINFO:
        {
            HV_MEMCPY(MsgPtr->AKESendPairingInfo.EKhKm, pstHdcpRxIns->stHdcp2xRx.stParams.EKhKm, HV_HDCP_2X_RX_EKH_SIZE);
            usMsgSize += HV_HDCP_2X_RX_EKH_SIZE;
            break;
        }

        case HV_HDCP_2X_RX_MSG_ID_LCSENDLPRIME:
        {
            HV_MEMCPY(MsgPtr->LCSendLPrime.LPrime, pstHdcpRxIns->stHdcp2xRx.stParams.LPrime, HV_HDCP_2X_RX_LPRIME_SIZE);
            usMsgSize += HV_HDCP_2X_RX_LPRIME_SIZE;
            break;
        }

        default:
        {
            HV_LOG_INFO(HDCP, "No Match Msg Id \n");
            return HV_FAILURE;
        }
    }

    Hv_Drv_Hdcp2x_HdmiSetRxMsgToReg(pstHdcpRxIns->stHdcp2xRx.aucMsgBuff, usMsgSize, ucPortIndex);

    /* Set Size for RxStatus reg */
    Hv_Drv_Hdcp2x_HdmiSetRxStatSize(usMsgSize, ucPortIndex);

    return HV_SUCCESS;
}

//#define HV_HDCP_DEBUG_PRINT_BUFF

#ifdef HV_HDCP_DEBUG_PRINT_BUFF

#define HV_LOG_BUF_PRINT(...) HV_LOG_BUF(HV_LOG_LEVEL_ERROR, __VA_ARGS__)

#ifdef HV_SCALER_DEBUG_VERSION
extern void Hv_Shell_HdcpDebug_DumpHdcpStatus(UINT32 uiPortIndex, UINT32 uiDumpOption);
extern void Hv_Shell_HdcpDebug_DumpHdcpKey();
#endif
#endif

VOID Hv_Mw_Hdcp1x_HdmiRxB1Computations(HdcpCtrlData* pstHdcpData)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);

    UCHAR8   ucPortIndex = pstHdcpData->ucPortIndex;
    HdcpRx*  pstHdcpRx = &(pstHdcpData->stHdcpRx);
    UCHAR8   Repeat = 0;
    USHORT16 usR0;
    UCHAR8   ucHdcpPortIndex = pstHdcpData->ucHdcpIndex;
    UCHAR8   ucTryCnt = 10;

    /*检查入参*/
    HV_ASSERT_TRUE_VOID(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);
    HV_ASSERT_TRUE_VOID(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + ucHdcpPortIndex, HOTFIX_HDCP_1X_AUTH_START);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_HDCP_1X_AUTH_START);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_OFF)
    InputPortState eStatus = Hv_Mw_InputPort_GetInputPortStatus(pstHdcpData->enInputPortIndex);

    if(eStatus != INPUT_PORT_STATE_DISPLAY_RDY && eStatus != INPUT_PORT_STATE_SYNC_OK)
    {
        Hv_Mw_HdmiRx_SetHdcpStatus(pstHdcpData->enInputPortIndex, HdcpEncStatus_1XStart);
        pstHdcpData->bHdcp1XReAuthed = HV_TRUE;
        HV_LOG_INFO(HDCP, "HDCP1X:%d Wait HDMI%d REAUTHENTICATED", ucHdcpPortIndex, ucPortIndex);
        return;
    }
    else
    {
        pstHdcpData->bHdcp1XReAuthed = HV_FALSE;
    }
#endif

    HV_MEMSET(pstHdcpRx->stHdcp1xRx.stParams.An, 0, HV_HDCP_1X_SIZE_AN);
    HV_MEMSET(pstHdcpRx->stHdcp1xRx.stParams.AKsv, 0, HV_HDCP_1X_SIZE_AKSV);

    /* 不加延时获取数据为空，该处延时为了让HDCP把从Source收到对应的内容写到寄存器 */
    Hv_Drv_Hdcp1x_HdmiGetRxAksvFromReg(pstHdcpRx->stHdcp1xRx.stParams.AKsv, ucPortIndex);

    Hv_Drv_Hdcp1x_HdmiGetRxAnFromReg(pstHdcpRx->stHdcp1xRx.stParams.An, ucPortIndex);

    Hv_Engine_RxCalcKm(pstHdcpRx->stHdcp1xRx.stParams.AKsv, pstHdcpRx->stHdcp1xRx.stParams.Km, ucHdcpPortIndex);

    Hv_Engine_RxBlockCipher(pstHdcpRx->stHdcp1xRx.stParams.An, pstHdcpRx->stHdcp1xRx.stParams.Km, Repeat,
            pstHdcpRx->stHdcp1xRx.stParams.Ks, pstHdcpRx->stHdcp1xRx.stParams.M0, &(pstHdcpRx->stHdcp1xRx.stParams.R0), ucHdcpPortIndex);

    usR0 = pstHdcpRx->stHdcp1xRx.stParams.R0;

    do 
    {
        if(Hv_Cal_HdmiRx_DdcCurStateIsIdle(ucPortIndex))
        {
            Hv_Drv_Hdcp1x_HdmiRxSetRiSelToHw(ucPortIndex, ucHdcpPortIndex);
            Hv_Drv_Hdcp1x_HdmiRxSetRI(usR0, ucPortIndex);
            Hv_Drv_Hdcp2x_HdmiResetLinkIntegrityFailure(ucPortIndex);
            if(Hv_Cal_HdmiRx_DdcCurStateIsIdle(ucPortIndex))
            {
                break;
            }
        }

        Hv_Vos_Delayus(500);

    } while (ucTryCnt--);

    if (!ucTryCnt)
    {
        HV_LOG_ERROR(HDMI, "ddc busy when proc hdcp 1x, %u", ucPortIndex);
        Hv_Drv_Hdcp1x_HdmiRxSetRiSelToHw(ucPortIndex, ucHdcpPortIndex);
        Hv_Drv_Hdcp1x_HdmiRxSetRI(usR0, ucPortIndex);
        Hv_Drv_Hdcp2x_HdmiResetLinkIntegrityFailure(ucPortIndex);
    }

    Hv_Drv_Hdcp1x_HdmiRxAuthStart(ucPortIndex, ucHdcpPortIndex);

    Hv_Mw_HdmiRx_SetHdcpStatus(pstHdcpData->enInputPortIndex, HdcpEncStatus_1XDone);

    Hv_Drv_Hdcp1x_HdcpClrAnAksv(ucPortIndex);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + ucHdcpPortIndex, HOTFIX_HDCP_1X_AUTH_DONE);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_HDCP_1X_AUTH_DONE);

    HV_LOG_INFO(HDCP, "HDCP1X:%d With HDMI%d Auth SUCCESS R0:%x.", ucHdcpPortIndex, ucPortIndex, usR0);

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_LOG_BUF_PRINT("An:", pstHdcpRx->stHdcp1xRx.stParams.An, sizeof(pstHdcpRx->stHdcp1xRx.stParams.An));
    HV_LOG_BUF_PRINT("Aksv:", pstHdcpRx->stHdcp1xRx.stParams.AKsv, sizeof(pstHdcpRx->stHdcp1xRx.stParams.AKsv));
    HV_LOG_BUF_PRINT("Km:", pstHdcpRx->stHdcp1xRx.stParams.Km, sizeof(pstHdcpRx->stHdcp1xRx.stParams.Km));
    HV_LOG_BUF_PRINT("Ks:", pstHdcpRx->stHdcp1xRx.stParams.Ks, sizeof(pstHdcpRx->stHdcp1xRx.stParams.Ks));
    HV_LOG_BUF_PRINT("M0:", pstHdcpRx->stHdcp1xRx.stParams.M0, sizeof(pstHdcpRx->stHdcp1xRx.stParams.M0));
#endif

    return;
}

Status Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert(HdcpCtrlData* pstHdcpData)
{
    HV_ASSERT_VALID_PTR(pstHdcpData);

    UCHAR8 ucPortIndex = pstHdcpData->ucPortIndex;
    HdcpRx* pstHdcpRx = &(pstHdcpData->stHdcpRx);
    USHORT16 usMsgSize = 0;

    /*检查入参*/
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
#ifdef HV_SCALER_DEBUG_VERSION
    Hv_Shell_HdcpDebug_DumpHdcpStatus(pstHdcpData->ucHdcpIndex, 0);
    Hv_Shell_HdcpDebug_DumpHdcpKey();
#endif
#endif

    Hv_Drv_Hdcp2x_HdmiClrRxStatSize(ucPortIndex);
    usMsgSize = sizeof(HDCP2X_RX_AKEInit);

    pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff[0] = HV_HDCP_2X_RX_MSG_ID_INVALID;

    Hv_Drv_Hdcp2x_HdmiGetRxMsgFromReg(pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff, usMsgSize, ucPortIndex);

    if(HV_SUCCESS != Hv_Mw_Hdcp2x_RxHdmiGetMsg(&(pstHdcpData->stHdcpRx.stHdcp2xRx)))
    {
        HV_LOG_ERROR(HDCP, "Get Msg Error for HdmiRxB0ProcMsgAKESendCert");
        return HV_FAILURE;
    }

    Hv_Drv_Hdcp2x_RxGenRrxAndCaps(pstHdcpRx, 0);

    HV_ASSERT_SUCCESS(Hv_Mw_Hdcp2x_HdmiRxSetMsg(pstHdcpRx, HV_HDCP_2X_RX_MSG_ID_AKESENDCERT, ucPortIndex));

    pstHdcpRx->enHdcp2xMsgState = HDCP2X_AKE_SEND_CERT_DONE;

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_INIT);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + ucPortIndex, HOTFIX_HDMI_HDCP_2X_AUTH_START);

    HV_LOG_INFO(HDCP, "HDCP%d AKE_INIT on HDMI%d", pstHdcpData->ucHdcpIndex, pstHdcpData->ucPortIndex);

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB1ProcMsgAKENoStoredKm(HdcpCtrlData* pstHdcpData)
{
    HdcpRx*  pstHdcpRx =NULL;
    UCHAR8   EKpubKm[HV_HDCP_2X_TX_E_KPUB_KM_SIZE] = {0};
    UINT32   uiSize = 0;
    USHORT16 usMsgSize = 0;

    /*检查入参*/
    HV_ASSERT_VALID_PTR(pstHdcpData);
    UCHAR8 ucPortIndex = pstHdcpData->ucPortIndex;
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    pstHdcpRx = &(pstHdcpData->stHdcpRx);
    usMsgSize = sizeof(HDCP2X_RX_AKENoStoredKm);

    pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff[0] = HV_HDCP_2X_RX_MSG_ID_INVALID;
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_NO_STORE_KM);

    Hv_Drv_Hdcp2x_HdmiGetRxMsgFromReg(pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff, usMsgSize, ucPortIndex);
    if(HV_SUCCESS != Hv_Mw_Hdcp2x_RxHdmiGetMsg(&(pstHdcpData->stHdcpRx.stHdcp2xRx)))
    {
        HV_LOG_ERROR(HDCP, "Get Msg Error for HdmiRxB1ProcMsgAKENoStoredKm");
        return HV_FAILURE;
    }

    if(HV_SUCCESS == Hv_Engine_RxRsaesOaepDecrypt(&pstHdcpRx->stHdcp2xRx, (HDCP2X_RX_KPriv *)(pstHdcpRx->stHdcp2xRx.pucPrivKey),
            pstHdcpRx->stHdcp2xRx.stParams.EKpubKm, pstHdcpRx->stHdcp2xRx.stParams.Km, &uiSize))
    {
        Hv_Engine_RxComputeHPrime(pstHdcpRx->stHdcp2xRx.stParams.Rrx, pstHdcpRx->stHdcp2xRx.stParams.RxCaps,
        pstHdcpRx->stHdcp2xRx.stParams.Rtx, pstHdcpRx->stHdcp2xRx.stParams.TxCaps, pstHdcpRx->stHdcp2xRx.stParams.Km,
        pstHdcpRx->stHdcp2xRx.stParams.HPrime);

        Hv_Mw_Hdcp2x_HdmiRxSetMsg(pstHdcpRx, HV_HDCP_2X_RX_MSG_ID_AKESENDHPRIME, ucPortIndex);

        pstHdcpData->stHdcpRx.enHdcp2xMsgState = HDCP2X_AKE_SEND_HPRIME_DONE;
    }
    else
    {
        HV_LOG_ERROR(HDCP, "RsaesOaepDecrypt Failed!\n");
        return HV_FAILURE;
    }

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_LOG_BUF_PRINT("EKpubKm:", pstHdcpRx->stHdcp2xRx.stParams.EKpubKm, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EKpubKm));
    HV_LOG_BUF_PRINT("Rrx:",pstHdcpRx->stHdcp2xRx.stParams.Rrx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rrx));
    HV_LOG_BUF_PRINT("RxCaps:",pstHdcpRx->stHdcp2xRx.stParams.RxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.RxCaps));
    HV_LOG_BUF_PRINT("Rtx:",pstHdcpRx->stHdcp2xRx.stParams.Rtx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rtx));
    HV_LOG_BUF_PRINT("TxCaps:",pstHdcpRx->stHdcp2xRx.stParams.TxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.TxCaps));
    HV_LOG_BUF_PRINT("Km:", pstHdcpRx->stHdcp2xRx.stParams.Km, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Km));
    HV_LOG_BUF_PRINT("HPrime:", pstHdcpRx->stHdcp2xRx.stParams.HPrime, sizeof(pstHdcpRx->stHdcp2xRx.stParams.HPrime));
#endif

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB1ProcMsgAKEStoredKm(HdcpCtrlData* pstHdcpData)
{
    HdcpRx* pstHdcpRx =NULL;
    USHORT16 usMsgSize = 0;

    //UCHAR8 M[HV_HDCP_2X_RX_M_SIZE] = {0};
    //UCHAR8 EKhKm[HV_HDCP_2X_RX_EKH_SIZE] = {0};

    /*检查入参*/
    HV_ASSERT_VALID_PTR(pstHdcpData);
    UCHAR8 ucPortIndex = pstHdcpData->ucPortIndex;
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    pstHdcpRx = &(pstHdcpData->stHdcpRx);

    usMsgSize = sizeof(HDCP2X_RX_AKEStoredKm);

    pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff[0] = HV_HDCP_2X_RX_MSG_ID_INVALID;
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_STORED_KM);

    Hv_Drv_Hdcp2x_HdmiGetRxMsgFromReg(pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff, usMsgSize, ucPortIndex);
    if(HV_SUCCESS != Hv_Mw_Hdcp2x_RxHdmiGetMsg(&(pstHdcpData->stHdcpRx.stHdcp2xRx)))
    {
        HV_LOG_ERROR(HDCP, "Get Msg Error for HdmiRxB1ProcMsgAKEStoredKm");
        return HV_FAILURE;
    }

    /* Concatenate M = (Rtx || Rrx) */
    //HV_MEMCPY(M, pstHdcpRx->stHdcp2xRx.stParams.M, HV_HDCP_2X_RX_M_SIZE);
    //HV_MEMCPY(EKhKm, pstHdcpRx->stHdcp2xRx.stParams.EKhKm, HV_HDCP_2X_RX_EKH_SIZE);

    Hv_Engine_RxComputeEkh(pstHdcpRx->stHdcp2xRx.pucPrivKey, pstHdcpRx->stHdcp2xRx.stParams.EKhKm,
        pstHdcpRx->stHdcp2xRx.stParams.M, pstHdcpRx->stHdcp2xRx.stParams.Km);

    Hv_Engine_RxComputeHPrime(pstHdcpRx->stHdcp2xRx.stParams.Rrx, pstHdcpRx->stHdcp2xRx.stParams.RxCaps,
    pstHdcpRx->stHdcp2xRx.stParams.Rtx, pstHdcpRx->stHdcp2xRx.stParams.TxCaps, pstHdcpRx->stHdcp2xRx.stParams.Km,
    pstHdcpRx->stHdcp2xRx.stParams.HPrime);

    Hv_Mw_Hdcp2x_HdmiRxSetMsg(pstHdcpRx, HV_HDCP_2X_RX_MSG_ID_AKESENDHPRIME, ucPortIndex);

    pstHdcpData->stHdcpRx.enHdcp2xMsgState = HDCP2X_AKE_SEND_HPRIME_DONE;

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_LOG_INFO(HDCP, "HdmiRxB1ProcMsgAKEStoredKm is Print:");
    HV_LOG_BUF_PRINT("EKpubKm:", pstHdcpRx->stHdcp2xRx.stParams.EKpubKm, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EKpubKm));
    HV_LOG_BUF_PRINT("Rrx:",pstHdcpRx->stHdcp2xRx.stParams.Rrx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rrx));
    HV_LOG_BUF_PRINT("RxCaps:",pstHdcpRx->stHdcp2xRx.stParams.RxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.RxCaps));
    HV_LOG_BUF_PRINT("Rtx:",pstHdcpRx->stHdcp2xRx.stParams.Rtx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rtx));
    HV_LOG_BUF_PRINT("TxCaps:",pstHdcpRx->stHdcp2xRx.stParams.TxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.TxCaps));
    HV_LOG_BUF_PRINT("Km:", pstHdcpRx->stHdcp2xRx.stParams.Km, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Km));
    HV_LOG_BUF_PRINT("EKhKm:", pstHdcpRx->stHdcp2xRx.stParams.EKhKm, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EKhKm));
    HV_LOG_BUF_PRINT("M:", pstHdcpRx->stHdcp2xRx.stParams.M, sizeof(pstHdcpRx->stHdcp2xRx.stParams.M));
    HV_LOG_BUF_PRINT("HPrime:", pstHdcpRx->stHdcp2xRx.stParams.HPrime, sizeof(pstHdcpRx->stHdcp2xRx.stParams.HPrime));
#endif

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB1ProcAKEPairing(HdcpCtrlData* pstHdcpData)
{
    HdcpRx* pstHdcpRx = NULL;
    /*检查入参*/
    HV_ASSERT_VALID_PTR(pstHdcpData);
    UCHAR8 ucPortIndex = pstHdcpData->ucPortIndex;
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    pstHdcpRx = &(pstHdcpData->stHdcpRx);

    /* Concatenate M = (Rtx || Rrx) */
    HV_MEMCPY(pstHdcpRx->stHdcp2xRx.stParams.M, pstHdcpRx->stHdcp2xRx.stParams.Rtx, HV_HDCP_2X_RX_RTX_SIZE);
    HV_MEMCPY((pstHdcpRx->stHdcp2xRx.stParams.M) + HV_HDCP_2X_RX_RTX_SIZE, pstHdcpRx->stHdcp2xRx.stParams.Rrx, HV_HDCP_2X_RX_RRX_SIZE);

    Hv_Engine_RxComputeEkh(pstHdcpRx->stHdcp2xRx.pucPrivKey, pstHdcpRx->stHdcp2xRx.stParams.Km, 
        pstHdcpRx->stHdcp2xRx.stParams.M, pstHdcpRx->stHdcp2xRx.stParams.EKhKm);

    Hv_Mw_Hdcp2x_HdmiRxSetMsg(pstHdcpRx, HV_HDCP_2X_RX_MSG_ID_AKESENDPAIRINGINFO, ucPortIndex);

    pstHdcpData->stHdcpRx.enHdcp2xMsgState = HDCP2X_AKE_SEND_PAIRING_DONE;
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_RD_HPRIME);

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_LOG_INFO(HDCP, "HdmiRxB1ProcAKEPairing is Print:");
    HV_LOG_BUF_PRINT("EKpubKm:", pstHdcpRx->stHdcp2xRx.stParams.EKpubKm, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EKpubKm));
    HV_LOG_BUF_PRINT("Rrx:",pstHdcpRx->stHdcp2xRx.stParams.Rrx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rrx));
    HV_LOG_BUF_PRINT("RxCaps:",pstHdcpRx->stHdcp2xRx.stParams.RxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.RxCaps));
    HV_LOG_BUF_PRINT("Rtx:",pstHdcpRx->stHdcp2xRx.stParams.Rtx, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rtx));
    HV_LOG_BUF_PRINT("TxCaps:",pstHdcpRx->stHdcp2xRx.stParams.TxCaps, sizeof(pstHdcpRx->stHdcp2xRx.stParams.TxCaps));
    HV_LOG_BUF_PRINT("Km:", pstHdcpRx->stHdcp2xRx.stParams.Km, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Km));
    HV_LOG_BUF_PRINT("HPrime:", pstHdcpRx->stHdcp2xRx.stParams.HPrime, sizeof(pstHdcpRx->stHdcp2xRx.stParams.HPrime));
    HV_LOG_BUF_PRINT("EKhKm:", pstHdcpRx->stHdcp2xRx.stParams.EKhKm, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EKhKm));
    HV_LOG_BUF_PRINT("M:", pstHdcpRx->stHdcp2xRx.stParams.M, sizeof(pstHdcpRx->stHdcp2xRx.stParams.M));
#endif
    
    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB2LCSendLPrime(HdcpCtrlData* pstHdcpData)
{
#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_ASSERT_VALID_PTR(pstHdcpData);
    Hdcp2xRx* pst2XStatus = &(pstHdcpData->stHdcpRx.stHdcp2xRx);
    HV_LOG_BUF_PRINT("    Rn:", pst2XStatus->stParams.Rn, sizeof(pst2XStatus->stParams.Rn));
    HV_LOG_BUF_PRINT("LPrime:", pst2XStatus->stParams.LPrime, sizeof(pst2XStatus->stParams.LPrime));
#endif
    Hv_Vos_Timer_Rstop(pstHdcpData->pstRcvEks);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_LC_INIT);

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB3ComputeKs(HdcpCtrlData* pstHdcpData)
{
    /*检查入参*/
    HV_ASSERT_VALID_PTR(pstHdcpData);
    UCHAR8 ucPortIndex = pstHdcpData->ucPortIndex;
    USHORT16 usMsgSize = 0;
    HdcpRx* pstHdcpRx = &(pstHdcpData->stHdcpRx);
    HV_ASSERT_TRUE(ucPortIndex <= HV_BOARD_CONFIG_MAX_HDMI_PORT_NUM);

    usMsgSize = sizeof(HDCP2X_RX_SKESendEks);

    pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff[0] = HV_HDCP_2X_RX_MSG_ID_INVALID;

    Hv_Drv_Hdcp2x_HdmiGetRxMsgFromReg(pstHdcpData->stHdcpRx.stHdcp2xRx.aucMsgBuff, usMsgSize, ucPortIndex);
    if(HV_SUCCESS != Hv_Mw_Hdcp2x_RxHdmiGetMsg(&(pstHdcpData->stHdcpRx.stHdcp2xRx)))
    {
        HV_LOG_ERROR(HDCP, "Get Msg Error for HdmiRxB3ComputeKs");
        return HV_FAILURE;
    }

    Hv_Engine_RxComputeKs(pstHdcpRx->stHdcp2xRx.stParams.Rrx, pstHdcpRx->stHdcp2xRx.stParams.Rtx, pstHdcpRx->stHdcp2xRx.stParams.Km,
            pstHdcpRx->stHdcp2xRx.stParams.Rn, pstHdcpRx->stHdcp2xRx.stParams.EDkeyKs, pstHdcpRx->stHdcp2xRx.stParams.Ks);

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB4Authenticated(HdcpCtrlData* pstHdcpData)
{
    HdcpRx* pstHdcpRx =NULL;
    UCHAR8 ucHdcpPortIndex = 0;
    /*检查入参*/
    HV_ASSERT_VALID_PTR(pstHdcpData);

    pstHdcpRx = &(pstHdcpData->stHdcpRx);

    ucHdcpPortIndex = pstHdcpData->ucHdcpIndex;

    Hv_Drv_Hdcp2x_RxSaveKsRivToReg(pstHdcpRx->stHdcp2xRx.stParams.Ks, pstHdcpRx->stHdcp2xRx.stParams.Riv, ucHdcpPortIndex);

    Hv_Drv_Hdcp2x_StartRxAuth(ucHdcpPortIndex);

    Hv_Drv_Hdcp2x_HdmiStartRxAuthCallBack(pstHdcpData->ucPortIndex);

    Hv_Drv_Hdcp2x_HdmiResetLinkIntegrityFailure(pstHdcpData->ucPortIndex);

#ifdef HV_HDCP_DEBUG_PRINT_BUFF
    HV_LOG_BUF_PRINT("Ks:", pstHdcpRx->stHdcp2xRx.stParams.Ks, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Ks));
    HV_LOG_BUF_PRINT("Riv:", pstHdcpRx->stHdcp2xRx.stParams.Riv, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Riv));
    HV_LOG_BUF_PRINT("Rn:", pstHdcpRx->stHdcp2xRx.stParams.Rn, sizeof(pstHdcpRx->stHdcp2xRx.stParams.Rn));
    HV_LOG_BUF_PRINT("Edkeyks:", pstHdcpRx->stHdcp2xRx.stParams.EDkeyKs, sizeof(pstHdcpRx->stHdcp2xRx.stParams.EDkeyKs));
#endif

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp2x_HdmiRxB3ComputeKsB4Authented(HdcpCtrlData* pstHdcpData)
{
    HV_ASSERT_SUCCESS(Hv_Mw_Hdcp2x_HdmiRxB3ComputeKs(pstHdcpData));
    HV_ASSERT_SUCCESS(Hv_Mw_Hdcp2x_HdmiRxB4Authenticated(pstHdcpData));

    Hv_Mw_HdmiRx_SetHdcpStatus(pstHdcpData->enInputPortIndex, HdcpEncStatus_2XDone);

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0 + pstHdcpData->ucHdcpIndex, HOTFIX_HDCP_2X_SND_EKS);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDMI0 + pstHdcpData->ucPortIndex, HOTFIX_HDMI_HDCP_2X_AUTH_DONE);

    HV_LOG_INFO(HDCP, "HDCP%d 2X AUTHENTICATED SUCCESS!", pstHdcpData->ucHdcpIndex);

#if (HV_PROJECT_CONFIG_CTS == HV_CONFIG_ON)
    Hv_Drv_Hdcp_HdmiRxClearMsgAfterAutherDone(pstHdcpData->ucPortIndex);
#endif
    return HV_SUCCESS;
}

/* Define Hdcp2x State Machine */
Hdcp2xRxStateMachine stHdmiHdcp2xRxStateMachine[] =
{
    {HdcpPortState_B0, Hdcp2xRxEvt_WrAKEInit,            Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert,   HdcpPortState_B1, HdcpPortState_B0},
    {HdcpPortState_B1, Hdcp2xRxEvt_WrAKEInit,            Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert,   HdcpPortState_B1, HdcpPortState_B0},
    {HdcpPortState_B1, Hdcp2xRxEvt_WrAKENoStoredKm,      Hv_Mw_Hdcp2x_HdmiRxB1ProcMsgAKENoStoredKm, HdcpPortState_B1, HdcpPortState_B0},
    {HdcpPortState_B1, Hdcp2xRxEvt_WrAKEStoredKm,        Hv_Mw_Hdcp2x_HdmiRxB1ProcMsgAKEStoredKm,   HdcpPortState_B2, HdcpPortState_B0},
    {HdcpPortState_B1, Hdcp2xRxEvt_RdHPrime,             Hv_Mw_Hdcp2x_HdmiRxB1ProcAKEPairing,       HdcpPortState_B2, HdcpPortState_B0},
    {HdcpPortState_B2, Hdcp2xRxEvt_WrAKEInit,            Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert,   HdcpPortState_B1, HdcpPortState_B0},
    {HdcpPortState_B2, Hdcp2xRxEvt_WrLcInit,             Hv_Mw_Hdcp2x_HdmiRxB2LCSendLPrime,         HdcpPortState_B3, HdcpPortState_B0},
    {HdcpPortState_B3, Hdcp2xRxEvt_WrAKEInit,            Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert,   HdcpPortState_B1, HdcpPortState_B0},
    {HdcpPortState_B3, Hdcp2xRxEvt_WrLcInit,             Hv_Mw_Hdcp2x_HdmiRxB2LCSendLPrime,         HdcpPortState_B3, HdcpPortState_B0},
    {HdcpPortState_B3, Hdcp2xRxEvt_WrAKESendEks,         Hv_Mw_Hdcp2x_HdmiRxB3ComputeKsB4Authented, HdcpPortState_B4, HdcpPortState_B0},
    {HdcpPortState_B4, Hdcp2xRxEvt_WrAKEInit,            Hv_Mw_Hdcp2x_HdmiRxB0ProcMsgAKESendCert,   HdcpPortState_B1, HdcpPortState_B0}
};

VOID Hv_Mw_Hdcp2x_RunHdmiRxFsm(HdcpRxEvtId uiHdcpRxEvt, HdcpCtrlData* pstHdcpData)
{   
    HdcpPort2xState enNxtState = HdcpPortState_Idle;
    USHORT16 usIndex = 0;

    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);
    HdcpPort2xState enHdcpCurState = pstHdcpData->enCurrentPort2xState;
    for (usIndex = 0; usIndex < sizeof(stHdmiHdcp2xRxStateMachine)/sizeof(stHdmiHdcp2xRxStateMachine[0]); usIndex++)
    {
        if ((uiHdcpRxEvt == stHdmiHdcp2xRxStateMachine[usIndex].enEvtId)
                &&(stHdmiHdcp2xRxStateMachine[usIndex].enCurState == enHdcpCurState))
        {
            if (HV_SUCCESS == stHdmiHdcp2xRxStateMachine[usIndex].pfEvtHandler(pstHdcpData))
            {
                enNxtState = stHdmiHdcp2xRxStateMachine[usIndex].enNxtSucState;
            }
            else
            {
                enNxtState = stHdmiHdcp2xRxStateMachine[usIndex].enNxtFailState;
            }

            HV_ASSERT_TRUE_VOID(HdcpPortState_Idle != enNxtState);
            if (enNxtState != stHdmiHdcp2xRxStateMachine[usIndex].enCurState)
            {
                pstHdcpData->enCurrentPort2xState = enNxtState;
                //HV_LOG_INFO(HDCP, "HDCP have changed from State %d to %d", enHdcpCurState, enNxtState);
            }
            /*
            else
            {
                HV_LOG_INFO(HDCP, "Keep Current State %d", enHdcpCurState);
            }
            */
            break;
        }
        else
        {
            /*Do Noting*/
        }
    }
    return ;
}

static VOID Hv_Mw_Hdcp_HdmiEventHandler(HdcpRxEvtId uiHdcpRxEvt, HdcpCtrlData* pstHdcpData)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);

    LinkPortIndex enInputPortId = pstHdcpData->enInputPortIndex;
    UCHAR8 ucHdmiIndex          = pstHdcpData->ucPortIndex;
    UCHAR8 ucHdcpId             = pstHdcpData->ucHdcpIndex;

    switch (uiHdcpRxEvt)
    {
        case Hdcp1xRxEvt_WrAksv :
        {
            /* 2X 切换到1X的时候需要重新配置 */
            if(pstHdcpData->enHdcpVersion == HdcpVesion_Hdcp2X)
            {
                Hv_Mw_Hdcp_ReConfigRxDataPath(ucHdcpId, enInputPortId);
            }

            Hv_Vos_Timer_Rstop(pstHdcpData->pstRcvEks);

            pstHdcpData->enHdcpVersion = HdcpVesion_Hdcp1X;
            pstHdcpData->enCurrentPort2xState = HdcpPortState_B0;

            Hv_Drv_Hdcp1x_HdmiSetHdcpPath(pstHdcpData->ucHdcpIndex);

            Hv_Drv_Hdcp_AttachHdmiPath(ucHdmiIndex);

            Hv_Cal_HdmiRx_SetPacketErrorInt(ucHdmiIndex, HV_FALSE);

            break;
        }

        case Hdcp2xRxEvt_WrAKEInit :
        {
            pstHdcpData->bAuth = HV_FALSE;
            pstHdcpData->bHdcp1XReAuthed = HV_FALSE;

            /* 1X 切换到2X的时候需要重新配置 */
            if(pstHdcpData->enHdcpVersion == HdcpVesion_Hdcp1X)
            {
                Hv_Mw_Hdcp_ReConfigRxDataPath(ucHdcpId, enInputPortId);
            }

            Hv_Vos_Timer_Rstop(pstHdcpData->pstRcvEks);

            if(pstHdcpData->enCurrentPort2xState != HdcpPortState_B4)
            {
                Hv_Drv_Hdcp_RealseStatus(ucHdcpId);

                pstHdcpData->enHdcpVersion = HdcpVesion_Hdcp2X;

                Hv_Drv_Hdcp2x_HdmiResetLinkIntegrityFailure(ucHdmiIndex);

                Hv_Drv_Hdcp2x_HdmiSetHdcpPath(pstHdcpData->ucHdcpIndex);

                Hv_Drv_Hdcp_AttachHdmiPath(ucHdmiIndex);
            }

            break;
        }

        case Hdcp2xRxEvt_WrAKENoStoredKm :
        {
            pstHdcpData->stHdcpRx.enKmStoreState = HV_HDCP_NO_STORED_KM;
            break;
        }

        case Hdcp2xRxEvt_WrAKEStoredKm :
        {
            pstHdcpData->stHdcpRx.enKmStoreState = HV_HDCP_RX_STORED_KM;
            break;
        }

        case Hdcp2xRxEvt_WrAKESendEks :
        {
            Hv_Vos_Timer_Rstart(pstHdcpData->pstRcvEks, 0);
            break;
        }

        default:
        {
            break;
        }
    }

    return ;
}

VOID Hv_Mw_Hdcp_ProcHdmiHdcpMessage(const UrgentEvent *pstUrgentEvent)
{
    HV_ASSERT_VALID_PTR_VOID(pstUrgentEvent);

    LinkPortIndex enLinkPortIndex   = pstUrgentEvent->usPortIndex;
    UCHAR8           ucHdcpPortId   = HDCP_PORT_INDEX_INVALID;
    HdcpRxEvtId       uiHdcpRxEvt   = HdcpRxEvt_Invalid;
    HdcpCtrlData*     pstHdcpData   = NULL;
    static UCHAR8     ucPrintContrl = 0;

    ucHdcpPortId = Hv_Mw_Hdcp_GetValidHdcpPortIndex(enLinkPortIndex);
    if(ucHdcpPortId >= HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM)
    {
        if((ucPrintContrl & 0x0F) == 0)
        {
            HV_LOG_INFO(HDCP, "There is not a valid HDCP for InputPort Index : %d", enLinkPortIndex);
        }
        ucPrintContrl ++;

        return;
    }

    pstHdcpData = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortId);
    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);

    uiHdcpRxEvt = Hv_Drv_Hdcp_HdmiGetIrqEvent(pstUrgentEvent->uiValue, pstHdcpData->ucPortIndex, 
        pstHdcpData->stHdcpRx.enKmStoreState, pstHdcpData->stHdcpRx.enHdcp2xMsgState);

    if(uiHdcpRxEvt == HdcpRxEvt_Invalid)
    {
        return;
    }

    Hv_Mw_Hdcp_HdmiEventHandler(uiHdcpRxEvt, pstHdcpData);

    if(Hdcp1xRxEvt_WrAksv == uiHdcpRxEvt)
    {
        Hv_Mw_Hdcp1x_HdmiRxB1Computations(pstHdcpData);
    }
    else
    {
        Hv_Mw_Hdcp2x_RunHdmiRxFsm(uiHdcpRxEvt, pstHdcpData);
    }

    return;
}



