//////////////////////////////////////////////////////////////////////////////
//
// FUNCTION      :  SiiDrvHdmiTxLiteIsAksvValid()
//
// PURPOSE       :  Check if AKSVs contain 20 '0' and 20 '1'
//
// INPUT PARAMS  :  None
//
// OUTPUT PARAMS :  None
//
// GLOBALS USED  :  TBD
//
// RETURNS       :  true if 20 zeros and 20 ones found in AKSV. false OTHERWISE
//
//////////////////////////////////////////////////////////////////////////////
bool_t SiiDrvHdmiTxLiteIsAksvValid (void)
{
    uint8_t B_Data[AKSV_SIZE];
    uint8_t NumOfOnes = 0;
    uint8_t i;

    SiiRegReadBlock(TPI_AKSV_1_REG, B_Data, AKSV_SIZE);

    for (i=0; i < AKSV_SIZE; i++)
    {
        while (B_Data[i] != 0x00)
        {
            if (B_Data[i] & 0x01)
            {
                NumOfOnes++;
            }
            B_Data[i] >>= 1;
        }
    }

    if (NumOfOnes != NUM_OF_ONES_IN_KSV)
	{
        HDCP_DEBUG_PRINT(("HDCP -> Illegal AKSV\n"));
       printk("HDCP -> Illegal AKSV\n");	
		
        return false;
	}

    return true;
}
static void MhlCbusIsr( void )
{
	uint8_t		cbusInt;
	uint8_t     gotData[4];	
	uint8_t		i;
	cbusInt = SiiRegRead(REG_CBUS_MSC_INT2_STATUS);
	if(cbusInt == 0xFF)
	{
		return;
	}
	if( cbusInt )
	{
        if ( BIT0 & cbusInt)
        {
            SiiMhlTxMscWriteBurstDone( cbusInt );
        }
    	if(cbusInt & BIT2)
    	{
            uint8_t intr[4]={0};
    	    TX_DEBUG_PRINT(("MHL INTR Received\n"));
            SiiRegReadBlock(REG_CBUS_SET_INT_0, intr, 4);
    		SiiMhlTxGotMhlIntr( intr[0], intr[1] );
            SiiRegWriteBlock(REG_CBUS_SET_INT_0, intr, 4);
    	}
    	if(cbusInt & BIT3)
    	{
            uint8_t status[4]={0};
    		TX_DEBUG_PRINT(("MHL STATUS Received\n"));
            for (i = 0; i < 4;++i)
            {
                status[i] = SiiRegRead(REG_CBUS_WRITE_STAT_0 + i);
    			SiiRegWrite((REG_CBUS_WRITE_STAT_0 + i), 0xFF  );
            }
    		SiiMhlTxGotMhlStatus( status[0], status[1] );
    	}
    	SiiRegWrite(REG_CBUS_MSC_INT2_STATUS, cbusInt);
        TX_DEBUG_PRINT(("Drv: Clear CBUS INTR_2: %02X\n", (int) cbusInt));
	}
	cbusInt = SiiRegRead(REG_CBUS_INTR_STATUS);
	if (cbusInt)
	{
		SiiRegWrite(REG_CBUS_INTR_STATUS, cbusInt);
	    TX_DEBUG_PRINT(("Drv: Clear CBUS INTR_1: %02X\n", (int) cbusInt));
	}
	if((cbusInt & BIT3))
	{
        uint8_t mscMsg[2];
	    TX_DEBUG_PRINT(("MSC_MSG Received\n"));
        mscMsg[0] = SiiRegRead(REG_CBUS_PRI_VS_CMD);
        mscMsg[1] = SiiRegRead(REG_CBUS_PRI_VS_DATA);
	    TX_DEBUG_PRINT(("MSC MSG: %02X %02X\n", (int)mscMsg[0], (int)mscMsg[1] ));
		SiiMhlTxGotMhlMscMsg( mscMsg[0], mscMsg[1] );
	}
	if (cbusInt & (BIT_MSC_ABORT | BIT_MSC_XFR_ABORT | BIT_DDC_ABORT))
	{
		gotData[0] = CBusProcessErrors(cbusInt);
		mscCmdInProgress = false;
	}
	if(cbusInt & BIT4)
	{
	    TX_DEBUG_PRINT(("MSC_REQ_DONE\n"));
		mscCmdInProgress = false;
		SiiMhlTxMscCommandDone( SiiRegRead(REG_CBUS_PRI_RD_DATA_1ST) );
	}
    if (cbusInt & BIT7)
    {
        TX_DEBUG_PRINT(("Parity error count reaches 15\n"));
        SiiRegWrite(REG_CBUS_STAT2, 0x00);
    }
}
///////////////////////////////////////////////////////////////////////////
//
// MhlCbusIsr
//
// Only when MHL connection has been established. This is where we have the
// first looks on the CBUS incoming commands or returned data bytes for the
// previous outgoing command.
//
// It simply stores the event and allows application to pick up the event
// and respond at leisure.
//
// Look for interrupts on CBUS:CBUS_INTR_STATUS [0xC8:0x08]
//		7 = RSVD			(reserved)
//		6 = MSC_RESP_ABORT	(interested)
//		5 = MSC_REQ_ABORT	(interested)	
//		4 = MSC_REQ_DONE	(interested)
//		3 = MSC_MSG_RCVD	(interested)
//		2 = DDC_ABORT		(interested)
//		1 = RSVD			(reserved)
//		0 = rsvd			(reserved)
///////////////////////////////////////////////////////////////////////////
static void MhlCbusIsr (void)
{
	uint8_t		cbusInt;
	uint8_t     gotData[4];	// Max four status and int registers.

	//
	// Main CBUS interrupts on CBUS_INTR_STATUS
	//
	cbusInt = SiiRegRead(REG_CBUS_INTR_STATUS);

	// When I2C is inoperational (D3) and a previous interrupt brought us here, do nothing.
	if(cbusInt == 0xFF)
	{
		return;
	}
	
	if( cbusInt )
	{
		//
		// Clear all interrupts that were raised even if we did not process
		//
		SiiRegWrite(REG_CBUS_INTR_STATUS, cbusInt);

	    TX_DEBUG_PRINT(("Drv: Clear CBUS INTR_1: %02X\n", (int) cbusInt));
	}

	// MSC_MSG (RCP/RAP)
	if ((cbusInt & BIT_CBUS_MSC_MR_MSC_MSG))
	{
    	uint8_t mscMsg[2];
	    TX_DEBUG_PRINT(("Drv: MSC_MSG Received\n"));
		//
		// Two bytes arrive at registers 0x18 and 0x19
		//
        mscMsg[0] = SiiRegRead(REG_CBUS_PRI_VS_CMD);
        mscMsg[1] = SiiRegRead(REG_CBUS_PRI_VS_DATA);

	    TX_DEBUG_PRINT(("Drv: MSC MSG: %02X %02X\n", (int)mscMsg[0], (int)mscMsg[1] ));
		SiiMhlTxGotMhlMscMsg( mscMsg[0], mscMsg[1] );
	}
	if (cbusInt & (BIT_MSC_ABORT | BIT_MSC_XFR_ABORT | BIT_DDC_ABORT))
	{
		gotData[0] = CBusProcessErrors(cbusInt);
		mscCmdInProgress = false;
	}
	// MSC_REQ_DONE received.
	if (cbusInt & BIT_CBUS_MSC_MT_DONE)
	{
		TX_DEBUG_PRINT(("Drv: MSC_REQ_DONE\n"));

		mscCmdInProgress = false;

        // only do this after cBusInt interrupts are cleared above
		SiiMhlTxMscCommandDone( SiiRegRead(REG_CBUS_PRI_RD_DATA_1ST) );
	}
	//
	// Clear all interrupts that were raised even if we did not process
	//

	//
	// Now look for interrupts on register 0x1E. CBUS_MSC_INT2
	// 7:4 = Reserved
	//   3 = msc_mr_write_state = We got a WRITE_STAT
	//   2 = msc_mr_set_int. We got a SET_INT
	//   1 = reserved
	//   0 = msc_mr_write_burst. We received WRITE_BURST
	//
	cbusInt = SiiRegRead(REG_CBUS_MSC_INT2_STATUS);
	if(cbusInt)
	{
		//
		// Clear all interrupts that were raised even if we did not process
		//
		SiiRegWrite(REG_CBUS_MSC_INT2_STATUS, cbusInt);

	    TX_DEBUG_PRINT(("Drv: Clear CBUS INTR_2: %02X\n", (int) cbusInt));
	}

    if ( BIT_CBUS_MSC_MR_WRITE_BURST & cbusInt)
    {
        // WRITE_BURST complete
        SiiMhlTxMscWriteBurstDone( cbusInt );
    }

	if(cbusInt & BIT_CBUS_MSC_MR_SET_INT)
	{
    uint8_t intr[4];

	    TX_DEBUG_PRINT(("Drv: MHL INTR Received\n"));
	    SiiRegReadBlock(REG_CBUS_SET_INT_0, intr, 4);
	    SiiRegWriteBlock(REG_CBUS_SET_INT_0, intr, 4);
		// We are interested only in first two bytes.
		SiiMhlTxGotMhlIntr( intr[0], intr[1] );
	}

	if (cbusInt & BIT_CBUS_MSC_MR_WRITE_STATE)
	{
    uint8_t status[4];
    uint8_t clear[4]={0xff,0xff,0xff,0xff};// must write 0xFF to clear regardless!

		// don't put debug output here, it just creates confusion.
	    SiiRegReadBlock(REG_CBUS_WRITE_STAT_0, status, 4);
	    SiiRegWriteBlock(REG_CBUS_WRITE_STAT_0, clear, 4);
		SiiMhlTxGotMhlStatus( status[0], status[1] );
	}

}
void SiiMhlTxDrvGetScratchPad (uint8_t startReg,uint8_t *pData,uint8_t length)
{

	SiiRegReadBlock(REG_CBUS_SCRATCHPAD_0+startReg, pData, length);
}
void SiiRxInterruptHandler(void)
{
    uint8_t interrupts[NMB_OF_RX_INTERRUPTS];

    //DEBUG_PRINT(MSG_STAT, ("RX Interrupt detected!\n"));
    // get interrupt requests
    SiiRegReadBlock(RX_A__INTR1, &interrupts[INT1], 4);
    SiiRegReadBlock(RX_A__INTR5, &interrupts[INT5], 2);
    SiiRegReadBlock(RX_A__INTR7, &interrupts[INT7], 2);

    // do not touch interrupts which are masked out
    interrupts[INT1] &= rx_isr.shadow_interrupt_mask[INT1];
    interrupts[INT2] &= rx_isr.shadow_interrupt_mask[INT2];
    interrupts[INT3] &= rx_isr.shadow_interrupt_mask[INT3];
    interrupts[INT4] &= rx_isr.shadow_interrupt_mask[INT4];
    interrupts[INT5] &= rx_isr.shadow_interrupt_mask[INT5];
    interrupts[INT6] &= rx_isr.shadow_interrupt_mask[INT6];
    interrupts[INT7] &= rx_isr.shadow_interrupt_mask[INT7];
    interrupts[INT8] &= rx_isr.shadow_interrupt_mask[INT8];

    // Cable plug-in / plug-out interrupts are handled elsewhere
    //interrupts[INT6] &= ~RX_M__INTR6__CABLE_UNPLUG;
    //interrupts[INT8] &= ~RX_M__INTR8__CABLE_IN;

    // clear interrupt requests
    SiiRegWriteBlock(RX_A__INTR1, &interrupts[INT1], 4);
    SiiRegWriteBlock(RX_A__INTR5, &interrupts[INT5], 2);
    SiiRegWriteBlock(RX_A__INTR7, &interrupts[INT7], 2);

    if(interrupts[INT1] & RX_M__INTR1__AUTH_DONE)
    {
        DEBUG_PRINT(MSG_STAT, ("RX: Authentication done!\n"));
        switch_hdcp_failure_check_with_v_sync_rate(OFF);
    }

    if(interrupts[INT2] & RX_M__INTR2__VID_CLK_CHANGED)
    {
        rx_isr.bVidStableChgEvent = true;
        DEBUG_PRINT(MSG_STAT, ("RX: video clock change\n"));
    }

    if(interrupts[INT2] & RX_M__INTR2__SCDT)
    {
        switch_hdcp_failure_check_with_v_sync_rate(OFF);
        SiiDrvRxMuteVideo(ON);
        rx_isr.bVidStableChgEvent = true;

        if(SiiDrvRxIsSyncDetected())
        {
		// SCDT detection for vdin utility.
		printk("sii9293 irq got SCDT!\n");

            rx_isr.bScdtState = true;
#if defined(__KERNEL__)
            SiiConnectionStateNotify(true);
#endif
        }
        else
        {
		// SCDT detection for vdin utility.
			printk("sii9293 irq lost SCDT!\n");
			sii_signal_notify(0);

            rx_isr.bScdtState = false;
            SiiDrvSoftwareReset(RX_M__SRST__SRST);
            VMD_ResetTimingData();
            DEBUG_PRINT(MSG_STAT, ("RX: IDLE!\n"));


        }

    }

    if(interrupts[INT2] & RX_M__INTR2__HDMI_MODE)
    {
        DEBUG_PRINT(MSG_STAT, ("RX: HDMI mode change!\n"));
        RxIsr_HdmiDviTransition();
    }

    if(interrupts[INT2] & RX_M__INTR2__VSYNC)
    {
        hdcp_error_handler(true);
    }

    if(interrupts[INT4] & RX_M__INTR4__HDCP)
    {
        hdcp_error_handler(false);
    }

    if((interrupts[INT5] & RX_M__INTR5__AUDIO_FS_CHANGED) || (interrupts[INT6] & RX_M__INTR6__CHST_READY))
    {
        // Note: RX_M__INTR6__CHST_READY interrupt may be disabled
        //DEBUG_PRINT(MSG_STAT, ("RX: New Audio Fs\n"));
        RxAudio_OnChannelStatusChange();
    }
    if(interrupts[INT4] & RX_M__INTR4__NO_AVI)
    {
        RxInfo_NoAviHandler();
        rx_isr.bVidStableChgEvent = true;
    }

    if(interrupts[INT3] & RX_M__INTR3__NEW_AVI_PACKET)
    {
        RxInfo_InterruptHandler(INFO_AVI);
        rx_isr.bVidStableChgEvent = true;
    }

    if(interrupts[INT7] & RX_M__INTR7__NO_VSI_PACKET)
    {
        // Clear also vsif_received flag (indicating any VSIF packet detection).
        // If there is any other VSIF packet, the flag will be set again shortly.
        RxInfo_NoVsiHandler();
    }

    if(interrupts[INT7] & RX_M__INTR7__NEW_VSI_PACKET)
    {
        RxInfo_InterruptHandler(INFO_VSI);
    }

    if(interrupts[INT3] & RX_M__INTR3__NEW_AUD_PACKET)
    {
        RxInfo_InterruptHandler(INFO_AUD);
    }

    if(interrupts[INT6] & RX_M__INTR6__NEW_ACP_PACKET)
    {
        RxInfo_InterruptHandler(INFO_AUD);
    }
    if (interrupts[INT6] & RX_M__INTR6__CABLE_UNPLUG)
    {
        if (SiiRegRead(RX_A__INTR6) & RX_M__INTR6__CABLE_UNPLUG)
        {
            rx_isr.bCableChgEvent = true;
            rx_isr.bCableState = false;
            rx_isr.shadow_interrupt_mask[INT6] &= ~RX_M__INTR6__CABLE_UNPLUG;       // Disable 5v plug-out interrup
            rx_isr.shadow_interrupt_mask[INT8] |= RX_M__INTR8__CABLE_IN;            // Enable 5v plug-in interrupt
            SiiRegWrite(RX_A__INTR6_MASK, rx_isr.shadow_interrupt_mask[INT6]);
            SiiRegWrite(RX_A__INTR8_MASK, rx_isr.shadow_interrupt_mask[INT8]);
            sii9293_cable_status_notify(0);

        }

    }
    if (interrupts[INT8] & RX_M__INTR8__CABLE_IN)
    {
        if (SiiRegRead(RX_A__INTR8) & RX_M__INTR8__CABLE_IN)
        {
            rx_isr.bCableChgEvent = true;
            rx_isr.bCableState = true;
            rx_isr.shadow_interrupt_mask[INT6] |= RX_M__INTR6__CABLE_UNPLUG;        // Enable 5v plug-out interrup
            rx_isr.shadow_interrupt_mask[INT8] &= ~RX_M__INTR8__CABLE_IN;           // Disable 5v plug-in interrupt
            SiiRegWrite(RX_A__INTR6_MASK, rx_isr.shadow_interrupt_mask[INT6]);
            SiiRegWrite(RX_A__INTR8_MASK, rx_isr.shadow_interrupt_mask[INT8]);
			sii9293_cable_status_notify(1);
        }
    }
}