/**
 * @file hv_mw_Hdcp.c
 * @brief MiddleWare Hdcp c file.
 * @details This file provides the following functions: \n
 *          (1) Initialization and reset functions \n
 *          (2) Set Hdcp Version functions \n
 *          (3) Hdcp Version Check functions \n
 *          (4) Hdcp1x FSM function for DP \n
 *          (5) Hdcp2x FSM function for DP \n
 *          (6) Hdcp1x FSM function for HDMI \n
 *          (7) 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>dp group      <td>2022-08-31   <td>init
 * </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_UrgentTask.h"
#include "hv_comm_Utilities.h"
#include "hv_mw_DisplayPort.h"

static BOOL s_bHdcpInitialized = HV_FALSE;;
static BOOL s_abWaitForHdcp[LINK_PORT_INDEX_INVALID] = {HV_FALSE, HV_FALSE, HV_FALSE, HV_FALSE};

HDCPManager* Hv_Mw_Hdcp_GetHdcpManager(VOID)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    HV_ASSERT_VALID_PTR_RET(pstInputPortManager, NULL);
    return &(pstInputPortManager->stHDCPManager);
}

HV_ATTR_ISR_SECTION HdcpCtrlData* Hv_Mw_Hdcp_GetHdcpData(UCHAR8 ucHdcpPortIndex)
{
    InputPortManager* pstInputPortManager = Hv_Mw_InputPort_GetManagerPtr();
    HV_ASSERT_VALID_PTR_RET(pstInputPortManager, NULL);
    HV_ASSERT_TRUE_RET(ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM, NULL);
    return &(pstInputPortManager->stHDCPManager.astHdcpData[ucHdcpPortIndex]);
}

UCHAR8 Hv_Mw_Hdcp_ForcedGetValidHdcpPortIndex(LinkPortIndex enInputPortIndex, LinkPortIndex enProtectPortIndex)
{
    UCHAR8     ucHdcpPortIndex  = 0;
    const HdcpCtrlData* pstHdcpData   = NULL;

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

        /* 返回第一个不等于保护的一个口 */
        if(enProtectPortIndex != pstHdcpData->enInputPortIndex
            && HDCP_PORT_INDEX_INVALID != pstHdcpData->ucHdcpIndex)
        {
            return ucHdcpPortIndex;
        }
    }

    return HDCP_PORT_INDEX_INVALID;
}

static VOID Hv_Mw_Hdcp_ReleaseRxDataPath(HdcpCtrlData* pstHdcpData, BOOL bPreempt)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);
    if(pstHdcpData->enHdcpPortType == HdcpPortType_Hdmi)
    {
        Hv_Drv_Hdcp_RealseHdmiPath(pstHdcpData->ucPortIndex);

        if(pstHdcpData->enCurrentPort2xState == HdcpPortState_B4)
        {
            Hv_Drv_Hdcp_RealseStatus(pstHdcpData->ucHdcpIndex);
            Hv_Drv_Hdcp2x_HdmiSetRxStatusReAuth(pstHdcpData->ucPortIndex);
            pstHdcpData->bAuth = HV_FALSE;
        }
    }

    if(pstHdcpData->enHdcpPortType == HdcpPortType_DisplayPort)
    {
        Hv_Drv_Hdcp_RealseDpPath(pstHdcpData->ucPortIndex);
    }

    if(bPreempt)
    {
        Hv_Mw_InputPort_ToggleHpd(pstHdcpData->enInputPortIndex);
    }

    /* 通道释放时, 复位HDCP, dp 清fifo*/
    Hv_Drv_Hdcp1X_ClrDpFifo(pstHdcpData->ucHdcpIndex);
    Hv_Drv_Hdcp2X_ClrDpFifo(pstHdcpData->ucHdcpIndex);
    Hv_Drv_Hdcp_Reset(pstHdcpData->ucHdcpIndex);

    Hv_Drv_Hdcp_RealseStatus(pstHdcpData->ucHdcpIndex);

    /* 释放完后先释放占用标志位 */
    pstHdcpData->enInputPortIndex = LINK_PORT_INDEX_INVALID;
    pstHdcpData->enHdcpPortType   = HdcpPortType_Invalid;
    pstHdcpData->enHdcpVersion    = HdcpVesion_None;
    pstHdcpData->stHdcpRx.enKmStoreState = HV_HDCP_NO_STORED_KM;
    pstHdcpData->ucPortIndex      = 0xFF;

    return ;
}

Status Hv_Mw_Hdcp_ReConfigRxDataPath(UCHAR8 ucHdcpPortIndex, LinkPortIndex enInputPortIndex)
{
    HdcpCtrlData* pstHdcpData = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortIndex);
    HV_ASSERT_VALID_PTR(pstHdcpData);

    /* 释放掉原来的链路 */
    Hv_Mw_Hdcp_ReleaseRxDataPath(pstHdcpData, HV_FALSE);

    /* 搭建起新的链路 */
    switch (enInputPortIndex)
    {
        case LINK_PORT_INDEX_HDMI_RX0 :
        {
            Hv_Mw_Hdcp_SetHdmiRxData(pstHdcpData, enInputPortIndex, 0);
            break;
        }

        case LINK_PORT_INDEX_HDMI_RX1 :
        {
            Hv_Mw_Hdcp_SetHdmiRxData(pstHdcpData, enInputPortIndex, 1);
            break;
        }

        case LINK_PORT_INDEX_DP_RX0 :
        {
            Hv_Mw_Hdcp_SetDpRxData(pstHdcpData, enInputPortIndex, 0);
            break;
        }

        case LINK_PORT_INDEX_DP_RX1 :
        {
            Hv_Mw_Hdcp_SetDpRxData(pstHdcpData, enInputPortIndex, 1);
            break;
        }

        default:
        {
            HV_LOG_ERROR(HDCP, "Invalid enInputPortIndex:%d", enInputPortIndex);
            return HV_FAILURE;
        }
    }

    return HV_SUCCESS;
}

static VOID Hv_Mw_Hdcp_SetRxDataPath(UCHAR8 ucHdcpPortIndex, LinkPortIndex enInputPortIndex, BOOL bPreempt)
{
    HdcpCtrlData* pstHdcpData = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortIndex);
    HV_ASSERT_VALID_PTR_VOID(pstHdcpData);

    if(pstHdcpData->enInputPortIndex == enInputPortIndex)
    {
        HV_LOG_INFO(HDCP,"HDCP:%d have been bind with Link Port:%d",ucHdcpPortIndex, enInputPortIndex);
        return ;
    }

    /* 释放掉原来的链路 */
    Hv_Mw_Hdcp_ReleaseRxDataPath(pstHdcpData, bPreempt);

    Hv_Vos_Timer_Rstop(pstHdcpData->pstRcvEks);

    /* 搭建起新的链路 */
    switch (enInputPortIndex)
    {
        case LINK_PORT_INDEX_HDMI_RX0 :
        {
            Hv_Mw_Hdcp_SetHdmiRxData(pstHdcpData, enInputPortIndex, 0);
            break;
        }

        case LINK_PORT_INDEX_HDMI_RX1 :
        {
            Hv_Mw_Hdcp_SetHdmiRxData(pstHdcpData, enInputPortIndex, 1);
            break;
        }

        case LINK_PORT_INDEX_DP_RX0 :
        {
            Hv_Mw_Hdcp_SetDpRxData(pstHdcpData, enInputPortIndex, 0);
            break;
        }

        case LINK_PORT_INDEX_DP_RX1 :
        {
            Hv_Mw_Hdcp_SetDpRxData(pstHdcpData, enInputPortIndex, 1);
            break;
        }

        default:
        {
            HV_LOG_ERROR(HDCP, "Invalid enInputPortIndex:%d", enInputPortIndex);
            return;
        }
    }

}

VOID Hv_Mw_Hdcp_Retry(LinkPortIndex enInputPortIndex)
{
    if (s_abWaitForHdcp[enInputPortIndex] == HV_TRUE)
    {
        s_abWaitForHdcp[enInputPortIndex] = HV_FALSE;
        Hv_Mw_InputPort_ToggleHpd(enInputPortIndex);
        HV_LOG_INFO(HDCP, "HDCP RETRY %d", enInputPortIndex);
    }

    return;
}

Status Hv_Mw_Hdcp_RealseHdcpCmStatus(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);

        /* 找到对应的HDCP口了后释放 */
        if(enInputPortIndex == pstHdcpData->enInputPortIndex)
        {
            if (pstHdcpData->enHdcpPortType == HdcpPortType_DisplayPort)
            {
                if(HdcpVesion_Hdcp2X == pstHdcpData->enHdcpVersion)
                {
                    Hv_Drv_Hdcp2x_NotifyTxIrq(HV_HDCP_2X_RX_STATUS_LINK_INTERGITY_FAILTURE, pstHdcpData->ucPortIndex, pstHdcpData->ucHdcpIndex);
                }
                else
                {
                    Hv_Drv_Hdcp1x_NotifyTxIrq(HV_HDCP_1X_RX_STATUS_LINK_INTERGITY_FAILTURE, pstHdcpData->ucPortIndex, pstHdcpData->ucHdcpIndex);
                }
                Hv_Drv_Hdcp_RealseStatus(pstHdcpData->ucHdcpIndex);
                Hv_Mw_DpRx_IrqHpd(pstHdcpData->enInputPortIndex);
            }

            if(pstHdcpData->enHdcpPortType == HdcpPortType_Hdmi)
            {
                Hv_Drv_Hdcp_RealseStatus(pstHdcpData->ucHdcpIndex);
            }
        }
    }

    return HV_SUCCESS;
}
Status Hv_Mw_Hdcp_ReleaseHdcpBinding(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);

        /* 找到对应的HDCP口了后释放 */
        if(enInputPortIndex == pstHdcpData->enInputPortIndex)
        {
            if(pstHdcpData->enHdcpPortType == HdcpPortType_Hdmi)
            {
                Hv_Drv_Hdcp_RealseHdmiPath(pstHdcpData->ucPortIndex);

                if(pstHdcpData->enCurrentPort2xState == HdcpPortState_B4)
                {
                    Hv_Drv_Hdcp_RealseStatus(pstHdcpData->ucHdcpIndex);
                    Hv_Drv_Hdcp2x_HdmiSetRxStatusReAuth(pstHdcpData->ucPortIndex);
                    pstHdcpData->bAuth = HV_FALSE;
                }
            }

            pstHdcpData->enInputPortIndex = LINK_PORT_INDEX_INVALID;
            pstHdcpData->enHdcpPortType   = HdcpPortType_Invalid;
            pstHdcpData->enHdcpVersion    = HdcpVesion_None;
            pstHdcpData->stHdcpRx.enKmStoreState = HV_HDCP_NO_STORED_KM;
            pstHdcpData->ucPortIndex      = 0xFF;
        }
    }

    return HV_SUCCESS;
}

UCHAR8 Hv_Mw_Hdcp_GetValidHdcpPortIndex(LinkPortIndex enInputPortIndex)
{
    UCHAR8 ucHdcpPortIndex  = 0;
    UCHAR8 ucValidHdcpPortIndex  = HDCP_PORT_INDEX_INVALID;
    HdcpCtrlData* pstHdcpData   = NULL;
    UCHAR8 ucMainIndex = LINK_PORT_INDEX_INVALID;
    UCHAR8 ucSubIndex = LINK_PORT_INDEX_INVALID;
    BOOL   bPreempt = HV_FALSE;

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

        /* 如果已经使用的情况下，直接返回 */
        if(enInputPortIndex == pstHdcpData->enInputPortIndex)
        {
            return ucHdcpPortIndex;
        }

        /* 记录下第一个未用的HDCP Port */
        if(pstHdcpData->enInputPortIndex == LINK_PORT_INDEX_INVALID && 
            ucValidHdcpPortIndex  == HDCP_PORT_INDEX_INVALID)
        {
            ucValidHdcpPortIndex = pstHdcpData->ucHdcpIndex;
        }

        if(HV_FALSE == Hv_Mw_InputPort_GetCableStatus(pstHdcpData->enInputPortIndex) && 
            ucValidHdcpPortIndex  == HDCP_PORT_INDEX_INVALID)
        {
            ucValidHdcpPortIndex = pstHdcpData->ucHdcpIndex;
        }
    }

    if(ucValidHdcpPortIndex  == HDCP_PORT_INDEX_INVALID)
    {
        ucMainIndex = Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_MAIN);
        ucSubIndex = Hv_Mw_InputPort_GetChannelBindPortIndex(CHANNEL_TYPE_SUB);
        bPreempt = HV_TRUE;

        if(ucMainIndex == enInputPortIndex)
        {
            ucValidHdcpPortIndex = Hv_Mw_Hdcp_ForcedGetValidHdcpPortIndex(enInputPortIndex, ucSubIndex);
        }

        if(ucSubIndex == enInputPortIndex)
        {
            ucValidHdcpPortIndex = Hv_Mw_Hdcp_ForcedGetValidHdcpPortIndex(enInputPortIndex, ucMainIndex);
        }
    }

    if(ucValidHdcpPortIndex != HDCP_PORT_INDEX_INVALID)
    {
        Hv_Mw_Hdcp_SetRxDataPath(ucValidHdcpPortIndex, enInputPortIndex, bPreempt);
    }
    else
    {
        s_abWaitForHdcp[enInputPortIndex] = HV_TRUE;
    }

    return ucValidHdcpPortIndex;
}

VOID Hv_Mw_Hdcp_SetProcFlag(BOOL bProcFlag)
{
    return;
}

BOOL Hv_Mw_Hdcp_GetProcFlag(VOID)
{
    return HV_FALSE;
}

HV_ATTR_ISR_SECTION Status Hv_Mw_Hdcp_RxISRSndEvent(UINT32 uiHdcpIntFlag, USHORT16 usPortId, UrgentRevEventType enUrgEventType)
{
    HV_VOS_QUEUE_S* xUrgentQueue = Hv_Mw_System_GetUrgentQueue();
    UrgentEvent stHdcpRxEvt = {0,};

    if(0 != (uiHdcpIntFlag & HV_HDCP_HDMI_2X_WRITE_LCINIT_DONE_INT))
    {
        UCHAR8 ucHdcpPortIndex  = 0;

        for(ucHdcpPortIndex = 0; ucHdcpPortIndex < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM; ucHdcpPortIndex++)
        {
            HdcpCtrlData* pstHdcpData   = Hv_Mw_Hdcp_GetHdcpData(ucHdcpPortIndex);
            HV_ASSERT_VALID_PTR(pstHdcpData);
            if(usPortId == pstHdcpData->enInputPortIndex)
            {
                HdcpRx* pstHdcpRx = &(pstHdcpData->stHdcpRx);
                HDCP2X_RX_Msg *MsgPtr = (HDCP2X_RX_Msg*)pstHdcpRx->stHdcp2xRx.aucMsgBuff;

                if(pstHdcpData->enHdcpPortType == HdcpPortType_Hdmi)
                {
                    UINT32 uiAddrOffset = (usPortId == LINK_PORT_INDEX_HDMI_RX0) ? 0 : 0x1000;
                    Hv_Common_ReadRegBytes(pstHdcpRx->stHdcp2xRx.stParams.Rn, RX_HDMI_RX_HDCP2X_00_00_00 + uiAddrOffset + 1, HV_HDCP_2X_RX_RN_SIZE);

                    Hv_Engine_RxComputeLPrime(pstHdcpRx->stHdcp2xRx.stParams.Rn, pstHdcpRx->stHdcp2xRx.stParams.Km, pstHdcpRx->stHdcp2xRx.stParams.Rrx,
                        pstHdcpRx->stHdcp2xRx.stParams.Rtx, pstHdcpRx->stHdcp2xRx.stParams.LPrime);
                    HV_ASSERT_VALID_PTR(MsgPtr);
                    MsgPtr->LCSendLPrime.MsgId = HV_HDCP_2X_RX_MSG_ID_LCSENDLPRIME;

                    for (UINT32 uiLoop = 0; uiLoop < HV_HDCP_2X_RX_LPRIME_SIZE; uiLoop++)
                    {
                        MsgPtr->LCSendLPrime.LPrime[uiLoop] = pstHdcpRx->stHdcp2xRx.stParams.LPrime[uiLoop];
                    }

                    Hv_Common_WriteRegBytes(pstHdcpRx->stHdcp2xRx.aucMsgBuff, RX_HDMI_RX_HDCP2X_00_00_00 + uiAddrOffset, (HV_HDCP_2X_RX_LPRIME_SIZE + 1));
                    Hv_Drv_Hdcp2x_HdmiSetRxStatSize((HV_HDCP_2X_RX_LPRIME_SIZE + 1), pstHdcpData->ucPortIndex);

                    pstHdcpRx->enHdcp2xMsgState = HDCP2X_SEND_LPRIME_DONE;
                }

                break;
            }
            else
            {

            }
        }
    }

    stHdcpRxEvt.enEventType = enUrgEventType;
    stHdcpRxEvt.usEventId = InputPortEventId_HDCP_IntGen;
    stHdcpRxEvt.usPortIndex = usPortId;
    stHdcpRxEvt.uiValue = uiHdcpIntFlag;
    HV_ASSERT_VALID_PTR(xUrgentQueue);
    Hv_Vos_QueueSendFromISR_unYield(xUrgentQueue, (void *)&stHdcpRxEvt);
    Hv_Vos_TaskYield();
    return HV_SUCCESS;
}

HV_VOS_ISR_RESULT_E Hv_Mw_Hdcp_ISRHandler(UINT32 uiIrqNum, void *arg)
{
    UINT32 uiIrqMask = 0;

    uiIrqMask = Hv_Drv_Hdcp_GetIrqFlag();

    Hv_Vos_WClrMiscInt(HV_CHIP_IRQ_RX_HDCP_0 - HV_CHIP_IRQ_BASE);

    if(uiIrqMask & (HV_HDCP0_COM_IRQ_DP_LIC_DONE | HV_HDCP1_COM_IRQ_DP_LIC_DONE))
    {
        Hv_Mw_Hdcp_DpIsrHandler(uiIrqMask);
    }

    return HV_VOS_ISR_HANDLED;
}

VOID Hv_Mw_Hdcp_InterruptInit()
{
    HDCPManager* pstHdcpManager = Hv_Mw_Hdcp_GetHdcpManager();

    Hv_Vos_AttachIsr(HV_CHIP_IRQ_RX_HDCP_0 , Hv_Mw_Hdcp_ISRHandler, pstHdcpManager);
    Hv_Vos_UnmaskIrq(HV_CHIP_IRQ_RX_HDCP_0);

    Hv_Drv_Hdcp_ComIrqEnable();

    return;
}

#if (0 == HV_PROJECT_CONFIG_HDCP_KEY_CLEAR_TEXT)
extern UINT32 Hv_DecryptHdcpKey(HDCPKeyDataDBRegion *pstHdcpKey);
extern VOID Hv_Comm_EncryHdcpKey(HDCPKeyDataDBRegion *pstHdcpKey);

Status Hv_Mw_Hdcp_DecryptKey(HDCPKeyDataDBRegion *pstHdcpKey)
{
    if(0 == Hv_DecryptHdcpKey(pstHdcpKey))
    {
        return HV_SUCCESS;
    }
    else
    {
        HV_LOG_ERROR(HDMI, "HDCP Key Decrypt Failed.");
        return HV_FAILURE;
    }
}
#endif

VOID Hv_Mw_Hdcp_LoadKeys(HDCPManager* pstHdcpManager)
{
    HV_ASSERT_VALID_PTR_VOID(pstHdcpManager);
    pstHdcpManager->pstHdcpKey = Hv_Common_Db_GetHDCPKeyDataDBRegionPtr();
#if (0 == HV_PROJECT_CONFIG_HDCP_KEY_CLEAR_TEXT)
    Hv_Vos_TaskEnterCritical();
    Hv_Mw_Hdcp_DecryptKey(pstHdcpManager->pstHdcpKey);
    Hv_Vos_TaskExitCritical();
#endif
    /* 1X Load Dks To HDCP */
    Hv_Drv_Hdcp_LoadDKSTable(pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucDks);

    /* 2X Load To HDCP */
    Hv_Drv_Hdcp_LoadLc128(pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxLc128);

    /* 计算保存Hdcp2xRxMmult */
    Hv_Drv_Hdcp_LoadPrivateKey(&(pstHdcpManager->stMmult),
        (HDCP2X_RX_KPriv *)(pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxPrivKey));

    return;
}

void Hv_Mw_Hdcp_ReceivedEksHandle(VOID* pvArgument, USHORT16 usTimerId)
{
    HdcpCtrlData* pstHdcpDataPtr = Hv_Mw_Hdcp_GetHdcpData(usTimerId - SYS_EVENT_TIMER_HDCP0);
    HV_ASSERT_VALID_PTR_VOID(pstHdcpDataPtr);

    Hv_Drv_Hdcp2x_HdmiStartRxAuthCallBack(pstHdcpDataPtr->ucPortIndex);

    pstHdcpDataPtr->bAuth = HV_TRUE;

    return;
}

Status Hv_Mw_Hdcp_Init(HDCPManager* pstHdcpManager)
{
    UCHAR8 ucInx = 0;
    HdcpCtrlData* pstHdcpDataPtr = NULL; 
    HV_ASSERT_VALID_PTR(pstHdcpManager);

    if (s_bHdcpInitialized == HV_FALSE)
    {
        HV_MEMSET(&pstHdcpManager->astHdcpData[0], 0, sizeof(pstHdcpManager->astHdcpData));
        HV_MEMSET(&pstHdcpManager->stMmult, 0, sizeof(pstHdcpManager->stMmult));

        pstHdcpManager->astHdcpData[0].ucHdcpIndex = HDCP_PORT_INDEX_RX0;
        Hv_Drv_Hdcp_RxModuleInit(HDCP_PORT_INDEX_RX0);
#if (HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM == 2)
        pstHdcpManager->astHdcpData[1].ucHdcpIndex = HDCP_PORT_INDEX_RX1;
        Hv_Drv_Hdcp_RxModuleInit(HDCP_PORT_INDEX_RX1);
#endif
    }

    /* Load Keys */
    Hv_Mw_Hdcp_LoadKeys(pstHdcpManager);

    for(ucInx = 0; ucInx < HV_BOARD_CONFIG_MAX_HDCP_PORT_NUM; ucInx++)
    {
        pstHdcpDataPtr = &(pstHdcpManager->astHdcpData[ucInx]);

        if (s_bHdcpInitialized == HV_FALSE)
        {
            pstHdcpDataPtr->enCurrentPort2xState = HdcpPortState_B0;

            pstHdcpDataPtr->enHdcpPortType = HdcpPortType_Invalid;
            pstHdcpDataPtr->enHdcpVersion = HdcpVesion_None;
            pstHdcpDataPtr->enInputPortIndex = LINK_PORT_INDEX_INVALID;
            pstHdcpDataPtr->ucPortIndex = 0xFF;
            pstHdcpDataPtr->enRole = HV_HDCP_RECEIVER;
            pstHdcpDataPtr->bAuth = HV_FALSE;
            pstHdcpDataPtr->bHdcp1XReAuthed = HV_FALSE;
            pstHdcpDataPtr->stHdcpRx.enHdcp2xMsgState = HDCP2X_SEND_MSG_INVALID;
            pstHdcpDataPtr->stHdcpRx.enKmStoreState = HV_HDCP_STORED_KM_INVALID;
        }

        HV_ASSERT_VALID_PTR(pstHdcpManager->pstHdcpKey);
        pstHdcpDataPtr->stHdcpRx.stHdcp1xRx.DKS = pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucDks;
        pstHdcpDataPtr->stHdcpRx.stHdcp1xRx.BKsv = pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucBksv;

        HV_MEMSET(&(pstHdcpDataPtr->stHdcpRx.stHdcp1xRx.stParams), 0, sizeof(Hdcp1xRxParams));
        HV_MEMSET(&(pstHdcpDataPtr->stHdcpRx.stHdcp2xRx), 0, sizeof(Hdcp2xRx));

        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.aucMsgBuff[0] = HV_HDCP_2X_RX_MSG_ID_INVALID;
        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.uiMsgSize = 0;
        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.pucPubCert = pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxCert;
        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.pucPrivKey = pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxPrivKey;
        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.pucLc128 = pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxLc128;
        pstHdcpDataPtr->stHdcpRx.stHdcp2xRx.pstmmult = &(pstHdcpManager->stMmult);

        if ((ucInx == 0) && (s_bHdcpInitialized == HV_FALSE))
        {
            HV_TIMER_INIT_PARAMS stReceivedEks0 = \
            {"ReceivedEks0", 200, HV_FALSE, NULL, Hv_Mw_Hdcp_ReceivedEksHandle, SYS_EVENT_TIMER_HDCP0};
            pstHdcpDataPtr->pstRcvEks = Hv_Vos_Timer_Create(&stReceivedEks0);
            HV_ASSERT_VALID_PTR(pstHdcpDataPtr->pstRcvEks);
        }

        if ((ucInx == 1) && (s_bHdcpInitialized == HV_FALSE))
        {
            HV_TIMER_INIT_PARAMS stReceivedEks1 = \
            {"ReceivedEks1", 200, HV_FALSE, NULL, Hv_Mw_Hdcp_ReceivedEksHandle, SYS_EVENT_TIMER_HDCP1};
            pstHdcpDataPtr->pstRcvEks = Hv_Vos_Timer_Create(&stReceivedEks1);
            HV_ASSERT_VALID_PTR(pstHdcpDataPtr->pstRcvEks);
        }
    }

    if (s_bHdcpInitialized == HV_FALSE)
    {
        /* HDMI 相关的HDCP配置初始化 */
        Hv_Drv_Hdcp_HdmiCommInit();
        Hv_Drv_Hdcp_DpCommInit();
    }

    if((PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_0) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp1XValid)))
    {
        Hv_Drv_Hdcp_DpSaveBksvtoReg(pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucBksv, 0);
        Hv_Drv_Hdcp1x_DpSetBcaps(1, 0);
    }

    if((PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_1) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp1XValid)))
    {
        Hv_Drv_Hdcp_DpSaveBksvtoReg(pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucBksv, 1);
        Hv_Drv_Hdcp1x_DpSetBcaps(1, 1);
    }

    if((PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_0) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp2XValid)))
    {
        Hv_Drv_Hdcp_DpLoadPublicCert(pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxCert, 0);
    }

    if((PORT_VALID == HV_BOARD_CONFIG_DISPLAYPORT_1) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp2XValid)))
    {
        Hv_Drv_Hdcp_DpLoadPublicCert(pstHdcpManager->pstHdcpKey->stHdcp2xRxKey.aucHdcp2xRxCert, 1);
    }

    if((PORT_VALID == HV_BOARD_CONFIG_HDMI_0) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp1XValid)))
    {
        Hv_Drv_Hdcp_HdmiSaveBksvtoReg(pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucBksv, 0);
        Hv_Drv_Hdcp1x_HdmiSetBcaps(0, 0);
    }

    if((PORT_VALID == HV_BOARD_CONFIG_HDMI_1) && (HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp1XValid)))
    {
        Hv_Drv_Hdcp_HdmiSaveBksvtoReg(pstHdcpManager->pstHdcpKey->stHdcp1xRxKey.aucBksv, 1);
        Hv_Drv_Hdcp1x_HdmiSetBcaps(0, 1);
    }

    if(HV_TRUE == HV_COMMON_DATABASE_GET(HDCPData, bHdcp2XValid))
    {
        Hv_Drv_Hdcp_SetHdmiHdcpVersion(HV_HDCP_2X_HDMI_RX_VERSION_MASK);
        Hv_Drv_Hdcp2x_SetDpHdcpVersion(HdcpVesion_Hdcp2X);
        HV_LOG_DEBUG(HDCP, "Hv_Mw_Hdcp_Init With HDCP2X Open!");
    }
    else
    {
        Hv_Drv_Hdcp_SetHdmiHdcpVersion(0);
        Hv_Drv_Hdcp2x_SetDpHdcpVersion(0);
        HV_LOG_DEBUG(HDCP, "Hv_Mw_Hdcp_Init With HDCP2X Closed!");
    }

    s_bHdcpInitialized = HV_TRUE;

    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP0, HOTFIX_HDCP_INIT);
    Hv_Comm_SetHotfixRegister(HOTFIX_MAIN_HDCP1, HOTFIX_HDCP_INIT);

    HV_LOG_DEBUG(HDCP, "Hv_Mw_Hdcp_Init Success!");

    return HV_SUCCESS;
}


/*  */
HdcpKeyCheckResult Hv_Mw_Hdcp_CheckHdcpKey(HdcpVersion bHdcpVer)
{
    BOOL   bHdcpValid   = HV_FALSE;
    UCHAR8 *pucKeyID    = NULL;
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();

    if(pHdcpDataDb->uiMagicNumber != DATABASE_VALID_MAGIC_NUMBER)
    {
        HV_LOG_INFO(HDCP,"Key Is Empty.");
        return HV_HDCP_KEY_EMPTY;
    }

    if(bHdcpVer == HdcpVesion_Hdcp1X)
    {
        bHdcpValid = pHdcpDataDb->bHdcp1XValid;
        pucKeyID = (pHdcpDataDb->stKey).stHdcp1xRxKey.aucBksv;
    }
    else
    {
        bHdcpValid = pHdcpDataDb->bHdcp2XValid;
        pucKeyID = (pHdcpDataDb->stKey).stHdcp2xRxKey.aucHdcp2xRxCert;
    }

    if(bHdcpValid == HV_FALSE)
    {
        HV_LOG_INFO(HDCP,"Key set as Invalid.");
        return HV_HDCP_KEY_INVALID;
    }
    else
    {
        if(Hv_Drv_Hdcp_CheckKidValid(pucKeyID) != 20)
        {
            HV_LOG_INFO(HDCP,"Key check as Invalid.");
            return HV_HDCP_KEY_INVALID;
        }
    }

    if(HV_TRUE ==  pHdcpDataDb->bUseDefaultKey)
    {
        HV_LOG_INFO(HDCP, "HDCP Key is Default");
        return HV_HDCP_KEY_DEFAULT;
    }

    HV_LOG_INFO(HDCP, "HDCP Key is VALID");
    return HV_HDCP_KEY_VALID;
}

#ifndef HDCP_MCCS_API
Status Hv_Mw_Hdcp_DDCCIWriteHdcp1xKey(USHORT16 usKeyLength, const UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UCHAR8 *pucData = (UCHAR8 *)&((pHdcpDataDb->stKey).stHdcp1xRxKey);
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 285 && uiLoop < usKeyLength; uiLoop++)
    {
        pucData[uiLoop] = pucHdcpKey[uiLoop];
    }

#if (HV_PROJECT_CONFIG_HDCP_KEY_CLEAR_TEXT == HV_CONFIG_OFF)
    Hv_Comm_EncryHdcpKey(&(pHdcpDataDb->stKey));
#endif
    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bHdcp1XValid, HV_TRUE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    Hv_Vos_TaskEnterCritical();
    Hv_DecryptHdcpKey(&(pHdcpDataDb->stKey));
    Hv_Vos_TaskExitCritical();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIWriteHdcp2xKey(USHORT16 usKeyLength, const UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UCHAR8 *pucData = (UCHAR8 *)&((pHdcpDataDb->stKey).stHdcp2xRxKey);
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 858 && uiLoop < usKeyLength; uiLoop++)
    {
        pucData[uiLoop] = pucHdcpKey[uiLoop];
    }
#if (HV_PROJECT_CONFIG_HDCP_KEY_CLEAR_TEXT == HV_CONFIG_OFF)
    Hv_Comm_EncryHdcpKey(&(pHdcpDataDb->stKey));
#endif
    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bHdcp2XValid, HV_TRUE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    Hv_Vos_TaskEnterCritical();
    Hv_DecryptHdcpKey(&(pHdcpDataDb->stKey));
    Hv_Vos_TaskExitCritical();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIEraseHdcp1xKey()
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();

    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();

    for(uiLoop = 0; uiLoop < 8; uiLoop++)
    {
        (pHdcpDataDb->aucHdcp1XKeyId)[uiLoop] = 0x0;
    }

    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bHdcp1XValid, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIEraseHdcp2xKey()
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();

    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 8; uiLoop++)
    {
        (pHdcpDataDb->aucHdcp2XKeyId)[uiLoop] = 0x0;
    }
    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bHdcp2XValid, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIWriteHdcp1xKeyId(USHORT16 usKeyLength, const UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 8 && uiLoop < usKeyLength; uiLoop++)
    {
        (pHdcpDataDb->aucHdcp1XKeyId)[uiLoop] = pucHdcpKey[uiLoop];
    }
    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIWriteHdcp2xKeyId(USHORT16 usKeyLength, const UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 8 && uiLoop < usKeyLength; uiLoop++)
    {
        (pHdcpDataDb->aucHdcp2XKeyId)[uiLoop] = pucHdcpKey[uiLoop];
    }
    Hv_Vos_TaskExitCritical();

    HV_COMMON_DATABASE_SET(HDCPData, bUseDefaultKey, HV_FALSE);
    HV_COMMON_DATABASE_SET(HDCPData, bModifyFlag, HV_TRUE);

    Hv_Mw_DataBase_Sync();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIReadHdcp1xKeyId(USHORT16 usKeyLength, UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 8 && uiLoop < usKeyLength; uiLoop++)
    {
        pucHdcpKey[uiLoop] = (pHdcpDataDb->aucHdcp1XKeyId)[uiLoop];
    }
    Hv_Vos_TaskExitCritical();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIReadHdcp2xKeyId(USHORT16 usKeyLength, UCHAR8 *pucHdcpKey)
{
    HDCPDataDBRegion* pHdcpDataDb = Hv_Common_Db_GetHDCPDataDBRegionPtr();
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 8 && uiLoop < usKeyLength; uiLoop++)
    {
        pucHdcpKey[uiLoop] = (pHdcpDataDb->aucHdcp2XKeyId)[uiLoop];
    }
    Hv_Vos_TaskExitCritical();

    return HV_SUCCESS;
}

Status Hv_Mw_Hdcp_DDCCIReadHdcpBksv(USHORT16 usKeyLength, UCHAR8 *pucData)
{
    HDCPKeyDataDBRegion* pHdcpKeyDataDb = Hv_Common_Db_GetHDCPKeyDataDBRegionPtr();
    UINT32 uiLoop = 0;

    Hv_Vos_TaskEnterCritical();
    for(uiLoop = 0; uiLoop < 5 && uiLoop < usKeyLength; uiLoop++)
    {
        pucData[uiLoop] = (pHdcpKeyDataDb->stHdcp1xRxKey).aucBksv[uiLoop];
    }
    Hv_Vos_TaskExitCritical();

    return HV_SUCCESS;
}
#endif
