/**
 * Copyright (C) 2011 Samsung Electronics Co., Ltd. All rights reserved.
 *
 * Mobile Communication Division,
 * Digital Media & Communications Business, Samsung Electronics Co., Ltd.
 *
 * This software and its documentation are confidential and proprietary
 * information of Samsung Electronics Co., Ltd.  No part of the software and
 * documents may be copied, reproduced, transmitted, translated, or reduced to
 * any electronic medium or machine-readable form without the prior written
 * consent of Samsung Electronics.
 *
 * Samsung Electronics makes no representations with respect to the contents,
 * and assumes no responsibility for any errors that might appear in the
 * software and documents. This publication and the contents hereof are subject
 * to change without notice.
 *
 */
/**
 * @file hdcp2_receiver.cpp
 * @author
 * @date
 * @brief This file contains Authentication messages functions for Receiver which interact with TrustZone.
 */

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>

#include "hdcp2.h"
#include "properties.h"

static int type = -1;
#ifdef USE_MOBICORE
static int USE_BUFFER_PROTECTION = 1;
#endif /* USE_MOBICORE */

/**
 * @fn int AKE_Init_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function Copies rtx sent by transmitter to the TZ HDCP Context.
 * @param hdcp - pointer to HDCP context.
 * @param received - Pointer to AKE init Object which contains message ID, rtx.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error.
 */
int AKE_Init_R(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = 0;

	if ((ret = TZ_COMMAND_R(CMD_AKE_INIT, received, sizeof(AKE_INIT), NULL, 0)) < 0) {
		HDCP2_Log("AKE_INIT failed [%d]!!!", ret);
		return ret;
	}

	//setting swd version corresponding to nwd
	ret = HDCP2_SetVersion(hdcp);

	if (ret != HDCP2_OK) {
		HDCP2_Log(" Rx CMD_SET_HDCP_VERSION Failed [%d]!!!",hdcp->entity);
		return HDCP2_ERR;
	}

	HDCP2_LogHex("[R<<<T] AKE_Init", received, sizeof(AKE_INIT));
	return ret;
}

/**
 * @fn int AKE_Tramsmitter_Info_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function Copies transmitter info received into TZ HDCP Context.
 * @param hdcp - pointer to HDCP context
 * @param received - Pointer to Transmitter info Object which contains message ID, Lenght,Version,and Transmitter Capability mask
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Tramsmitter_Info_R(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = 0;

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	AKE_TRANSMITTER_INFO *ake_tx_info = (AKE_TRANSMITTER_INFO *)received;
	//TRANSMITTER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of TRANSMITTER_CAPABILITY_MASK
	hdcp->Tx_LC_Precompute = ake_tx_info->TRANSMITTER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;

	if (hdcp->version > ake_tx_info->VERSION + HDCP2_VERSION_2_0) {
		hdcp->version = ake_tx_info->VERSION + HDCP2_VERSION_2_0;
		//setting swd version corresponding to nwd
		ret = HDCP2_SetVersion(hdcp);
		if (ret != HDCP2_OK) {
			HDCP2_Log(" Tx CMD_SET_HDCP_VERSION Failed [%d]!!!",hdcp->entity);
			return HDCP2_ERR;
		}
	}

	ret = TZ_COMMAND_R(CMD_AKE_TRANSMITTER_INFO, received, sizeof(AKE_TRANSMITTER_INFO), NULL, 0);
	HDCP2_LogHex("[R<<<T] AKE_Tramsmitter_Info", received, sizeof(AKE_TRANSMITTER_INFO));

	return ret;
}

/**
 * @fn int AKE_Send_Cert_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function Copies and sends receiver certificate to transmitter.
 * @param hdcp - pointer to HDCP context.
 * @param payload - Pointer to Receiver Certificate object which contains msg ID Repeater flag and receiver certificate.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error.
 */
int AKE_Send_Cert_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = 0;

#ifdef USE_QUALCOMM
	u8 entity[2] = { 0 };
#else
	u8 entity[1] = { 0 };
#endif /* USE_QUALCOMM */

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	if (hdcp->entity == HDCP2_REPEATER) {
		AKE_SEND_CERT *p = (AKE_SEND_CERT *) payload;

		// HDCP module is going to be set to "Repeater"
		p->REPEATER = 0x01;
		hdcp->REPEATER = p->REPEATER;

#ifdef USE_QUALCOMM
		entity[1] = hdcp->REPEATER;
		ret = TZ_COMMAND_R(CMD_AKE_SEND_CERT, entity, 2, payload, sizeof(AKE_SEND_CERT));
#else
		entity[0] = hdcp->REPEATER;
		ret = TZ_COMMAND_R(CMD_AKE_SEND_CERT, entity, 1, payload, sizeof(AKE_SEND_CERT));
#endif /* USE_QUALCOMM */
	} else {
		ret = TZ_COMMAND_R(CMD_AKE_SEND_CERT, NULL, 0, payload, sizeof(AKE_SEND_CERT));
	}
	HDCP2_LogHex("[R>>>T] AKE_Send_Cert", payload, ret);
	return ret;
}

/**
 * @fn int AKE_Receiver_Info_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function Forms receiver information and send it to transmitter.
 * @param hdcp - pointer to HDCP context
 * @param payload - Pointer to Receiver info Object which contains message ID, Lenght,Version,and Receiver Capability mask
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Receiver_Info_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = 0;
	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	ret = TZ_COMMAND_R(CMD_AKE_RECEIVER_INFO, NULL, 0, payload, sizeof(AKE_RECEIVER_INFO));
	AKE_RECEIVER_INFO *ake_rx_info = (AKE_RECEIVER_INFO *)payload;
	//RECEIVER_LOCALITY_PRECOMPUTE_SUPPORT is bit0 of RECEIVER_CAPABILITY_MASK
	hdcp->Rx_LC_Precompute = ake_rx_info->RECEIVER_CAPABILITY_MASK[1] & LOCALITY_PRECOMPUTE_SUPPORT;
	HDCP2_LogHex("[R>>>T] AKE_Receiver_Info", payload, sizeof(AKE_RECEIVER_INFO));
	return ret;
}

/**
 * @fn int AKE_No_Stored_km_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function Receives Ekpub_km from transmitter and Decrypts it to get km using RSA_OAEP_decrypt and copies it to the TZ HDCP Context
 * @param hdcp - pointer to HDCP context
 * @param received - Pointer to No stored Km Object which contains message ID and 128 bytes of Encrypted km[Ekpub_km] from transmitter
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_No_Stored_km_R(HDCP2_Ctx *hdcp, u8 *received)
{
	HDCP2_LogHex("[R<<<T] AKE_No_Stored_km", received, sizeof(AKE_NO_STORED_KM));
	int ret = TZ_COMMAND_R(CMD_AKE_NO_STORED_KM, received, sizeof(AKE_NO_STORED_KM), NULL, 0);
	return ret;
}

/**
 * @fn int AKE_Stored_km_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function Receives Ekh_km from transmitter and Decrypts it to get km and copies it to the TZ HDCP Context
 * @param hdcp - pointer to HDCP context
 * @param received - Pointer to stored Km Object which contains message ID and 128 bytes of Encrypted km[Ekh_km] from transmitter
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Stored_km_R(HDCP2_Ctx *hdcp, u8 *received)
{
	HDCP2_LogHex("[R<<<T] AKE_Stored_km", received, sizeof(AKE_STORED_KM));
	int ret = TZ_COMMAND_R(CMD_AKE_STORED_KM, received, sizeof(AKE_STORED_KM), NULL, 0);
	return ret;
}

/**
 * @fn int AKE_Send_rrx_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function Generates and sends 8bytes of random number[rrx] to transmitter.
 * @param hdcp - pointer to HDCP context
 * @param payload - Pointer to rrx  Object which contains message ID and 8bytes of rrx
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_rrx_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = TZ_COMMAND_R(CMD_AKE_SEND_RRX, NULL, 0, payload, sizeof(AKE_SEND_RRX));
	HDCP2_LogHex("[R>>>T] AKE_Send_rrx", payload, ret);
	return ret;
}

/**
 * @fn int AKE_Send_H_prime_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function Generates H prime and send it to the transmitter as below eqn.
 * @param hdcp - pointer to HDCP context
 * @param payload - Pointer to H prime Object which contains message ID and H prime
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int AKE_Send_H_prime_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = TZ_COMMAND_R(CMD_AKE_SEND_H_PRIME, NULL, 0, payload, sizeof(AKE_SEND_H_PRIME));
	HDCP2_LogHex("[R>>>T] AKE_Send_H_prime", payload, ret);
	return ret;
}

/**
 * @fn int AKE_Send_Pairing_Info_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function Generates Ekh_km and send it to the transmitter.
 * @param hdcp - pointer to HDCP context.
 * @param payload - Pointer to pairing info Object which contains message ID and Ekh_km.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error.
 */
int AKE_Send_Pairing_Info_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int length = 0;

	if ((length = TZ_COMMAND_R(CMD_AKE_SEND_PAIRING_INFO,
			NULL,
			0,
			payload,
			sizeof(AKE_SEND_PAIRING_INFO))) < 0)
		return length;

	HDCP2_LogHex("[R>>>T] AKE_Send_Pairing_Info", payload, length);

	return length;
}

/**
 * @fn int LC_Init_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function Copies received random value [rn] from transmitter.
 * @param hdcp - pointer to HDCP context.
 * @param received - Pointer to Lc Init Object which contains message ID and random number sent by the transmitter.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error.
 */
int LC_Init_R(HDCP2_Ctx *hdcp, u8 *received)
{
	/* we comment below log due to the latency */
	HDCP2_LogHex("[R<<<T] LC_Init", received, sizeof(LC_INIT));
	int ret = TZ_COMMAND_R(CMD_LC_INIT, received, sizeof(LC_INIT), NULL, 0);
	return ret;
}

/**
 * @fn int RTT_Ready_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function sends RTT_Ready message to transmitter when L' computation is complete.
 * @param hdcp - pointer to HDCP context
 * @param payload - pointer to RTT_READY object which contains message ID.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RTT_Ready_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = TZ_COMMAND_R(CMD_RTT_READY, NULL, 0, payload, sizeof(RTT_READY));
	/* we may comment below log to decrease the latency */
	HDCP2_LogHex("[T<<<R] RTT_Ready_R", payload, sizeof(RTT_READY));
	return ret;
}

/**
 * @fn int RTT_Challenge_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function copies received least significant 128 bits of L from transmitter.
 * @param hdcp - pointer to HDCP context
 * @param received - pointer to RTT_CHALLENGE object which contains message ID and 128 lsb of L.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int RTT_Challenge_R(HDCP2_Ctx *hdcp, u8 *received)
{
	/* we may comment below log to decrease the latency */
	HDCP2_LogHex("[R<<<T] RTT_Challenge_R", received, sizeof(RTT_CHALLENGE));
	int ret = TZ_COMMAND_R(CMD_RTT_CHALLENGE, received, sizeof(RTT_CHALLENGE), NULL, 0);
	return ret;
}

/**
 * @fn int LC_Send_L_prime_R(HDCP2_Ctx *hdcp, u8 *payload)
 * @brief This function calaculates L by equation : HMAC_SHA256(rn, (kd ^ rrx) )
 * @param hdcp - pointer to HDCP context
 * @param payload - Pointer to L Prime Object which contains message ID and memory to place L value.
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int LC_Send_L_prime_R(HDCP2_Ctx *hdcp, u8 *payload)
{
	int ret = 0;
	uint32_t size = 0;

	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	if (hdcp->Tx_LC_Precompute && hdcp->Rx_LC_Precompute && hdcp->version >= HDCP2_VERSION_2_1)
		size = sizeof(LC_SEND_L_PRIME_PC);
	else
		size = sizeof(LC_SEND_L_PRIME);

	ret = TZ_COMMAND_R(CMD_LC_SEND_L_PRIME, NULL, 0, payload, size);
	/* we comment below log due to the latency */
	HDCP2_LogHex("[R>>>T] LC_Send_L_prime", payload, size);
	return ret;
}

/**
 * @fn int SKE_Send_Eks_R(HDCP2_Ctx *hdcp, u8 *received)
 * @brief This function decrypts Eks using riv
 * @param hdcp - pointer to HDCP context
 * @param received - Pointer to Eks Object which contains message ID, Eks and riv
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int SKE_Send_Eks_R(HDCP2_Ctx *hdcp, u8 *received)
{
	int ret = 0;

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	if (hdcp->version == HDCP2_VERSION_2_3){
		ret = TZ_COMMAND_R(CMD_SKE_SEND_EKS, received, sizeof(SKE_SEND_EKS_VER23), NULL, 0); 
		HDCP2_LogHex("[R<<<T] SKE_Send_Eks_V23", received, sizeof(SKE_SEND_EKS_VER23));
	} else {
		ret = TZ_COMMAND_R(CMD_SKE_SEND_EKS, received, sizeof(SKE_SEND_EKS), NULL, 0); 
		HDCP2_LogHex("[R<<<T] SKE_Send_Eks", received, sizeof(SKE_SEND_EKS));
	}

	gettimeofday((struct timeval *)&hdcp->time_ske_done, NULL);

	return ret;
}

#ifndef USE_QUALCOMM
/**
 * @fn int HDCP2_SpsPpsToSecmem(HDCP2_Ctx *hdcp, u8 *sps_pps, u8 *phy_output, int inlen)
 * @brief sps_pps header is copied to secure memory
 * @param hdcp - pointer to HDCP context
 * @param sps_pps - pointer to to non-secure memory of sps_pps
 * @param output - pointer to to secure memory of sps_pps
 * @param inlen - length of input data
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int HDCP2_SpsPpsToSecmem(HDCP2_Ctx *hdcp, u8 *sps_pps, u8 *output, int inlen)
{
	int ret;
	addr_s *output_pa = (addr_s *)output;
	CIP_DATA_SPSPPS data;

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	#ifndef USE_TEEGRIS
	if (HDCP2_Ion2Addr((int)(intptr_t)output, &output_pa, NULL, inlen) != 0) {
		HDCP2_Log("Cannot convert ION handle");
		return HDCP2_ERR_INVALID_INPUT;
	}
#endif /* USE_TEEGRIS*/

	memset(&data, 0, sizeof(data));
	memcpy(data.spspps, sps_pps, inlen);
	data.phy_out = output_pa;
	data.size = inlen;

	HDCP2_DEBUG("HDCP2_SpsPpsToSecmem called size = %d, output=%x, output_pa=%x", inlen, output, output_pa);
	HDCP2_LogHex("SpsPps", sps_pps, inlen);

	if (inlen > MAX_SPS_BUFFER)
		return HDCP2_ERR;

	if ((ret = TZ_COMMAND_R(CMD_CIP_SPS_PPS_DATA, (u8 *)&data, sizeof(CIP_DATA_SPSPPS), NULL, 0)) < 0) {
		HDCP2_Log("SpsPpsToSecmem failed...%d", ret);
	}

	return ret;
}
#else
int HDCP2_SpsPpsToSecmem(HDCP2_Ctx *hdcp, u8 *sps_pps, u8 *output, int inlen)
{
	int ret = 0;
	return ret;
}
#endif /* USE_QUALCOMM */

/**
 * @fn int HDCP2_IsKeyFrame_WFD(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, int codec_type, void *pes_pkt, int pes_pkt_size)
 * @brief Checks whether the received frame is a key frame
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param codec_type - specifies code type
 * @param pes_pkt - pointer to Packetized Elementary Stream (PES)
 * @param pes_pkt_size - size od pes_pkt
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int HDCP2_IsKeyFrame_WFD(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, int codec_type,
			void *pes_pkt, int pes_pkt_size)
{
	int ret = 0;
	int len = DEC_MAX_HEADER_SIZE;
	u8 output[DEC_MAX_HEADER_SIZE];

	HDCP2_DEBUG("HDCP2_IsKeyFrame_WFD called. len: %d", len);

	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	len = (pes_pkt_size < DEC_MAX_HEADER_SIZE) ? pes_pkt_size : DEC_MAX_HEADER_SIZE;

#ifdef USE_QUALCOMM
	ret = HDCP2_Decrypt_Ex(hdcp, str_ctr, in_ctr, (u8 *) pes_pkt, len, output,
					DEC_TYPE_CHECK_KEY_FRAME, codec_type);
#else
	ret = HDCP2_Decrypt_Ex_IsKeyFrame(hdcp, str_ctr, in_ctr, (u8 *) pes_pkt, len, output,
					DEC_TYPE_CHECK_KEY_FRAME, codec_type);
#endif /* USE_QUALCOMM */

	if (ret < 0)
		ret = HDCP2_ERR;

	return ret;
}

/**
 * @fn int HDCP2_Decrypt(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output)
 * @brief This function is used to decrypt the data.
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param input - pointer to the data to be decrypted.
 * @param inlen - length of input data.
 * @param output - pointer to the output data, that will be populated in this function.
 * @return int - returns input length in case of success else returns error values in case of failures.
 */
int HDCP2_Decrypt(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output)
{
	HDCP2_DEBUG("HDCP2_Decrypt. inlen: %d", inlen);

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

#if !defined(USE_QUALCOMM) && !defined(USE_TEEGRIS)
	addr_s out_pa = 0;
	addr_s *output_pa = &out_pa;
	if (HDCP2_Ion2Addr((int)(intptr_t)output, &output_pa, NULL, inlen) != 0) {
		HDCP2_Log("Cannot convert ION handle");
		return HDCP2_ERR_INVALID_INPUT;
	}
	return HDCP2_Decrypt_Ex_VP(hdcp, str_ctr, in_ctr, input, inlen, output_pa, DEC_TYPE_VIDEO, 0);
#else
#ifdef USE_TEEGRIS
	return HDCP2_Decrypt_Ex(hdcp, str_ctr, in_ctr, input, inlen, output, DEC_TYPE_VIDEO, 0);
#else
	return HDCP2_Decrypt_Ex(hdcp, str_ctr, in_ctr, input, inlen, output, DEC_TYPE_NORMAL, 0);
#endif /* USE_TEEGRIS */
#endif /* !USE_QUALCOMM && USE_TEEGRIS */
}

#ifdef USE_MOBICORE
int HDCP2_CopyToSecureMem(HDCP2_Ctx *hdcp, u8 *input, int inlen, u8 *output )
{
	int ret = 0;
	addr_s *output_pa = 0;
	CIP_DATA_SPSPPS data;
	int remain = inlen;
	int declen = 0;
	int i = 0;
	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	if (HDCP2_Ion2Addr((int)(intptr_t)output, &output_pa, NULL, inlen) != 0) {
		HDCP2_Log("Cannot convert ION handle");
		return HDCP2_ERR_INVALID_INPUT;
	}

	HDCP2_LogHex("Frame recvd...", input, 100);

	while (remain > 0) {
		declen = (remain > MAX_SPS_BUFFER) ? MAX_SPS_BUFFER : remain;
		memset(&data, 0, sizeof(data));
		memcpy(data.spspps, input+i, declen);
		data.phy_out = output_pa+i;
		data.size = declen;

		HDCP2_DEBUG("HDCP2_SpsPpsToSecmem called size = %d, output=%x, data.phy_out=%x",
				inlen, output, output_pa);
		HDCP2_DEBUG("declen before calling tz is %d", declen);
		HDCP2_LogHex("SpsPps", data.spspps, 100);

		if ((ret = TZ_COMMAND_R(CMD_CIP_SPS_PPS_DATA, (u8 *)&data, sizeof(CIP_DATA_SPSPPS), NULL, 0)) !=0) {
			HDCP2_Log("SpsPpsToSecmem failed...%d", ret);
			break;
		}
		i += declen;
		remain -= declen;
	}

	if (ret < 0)
	   return ret;
	else
	   return inlen;
}
#endif /* USE_MOBICORE */

#ifdef USE_QUALCOMM
int HDCP2_CopyToSecureMem_ION(HDCP2_Ctx *hdcp, u8 *input, int inlen, u32 ion_fd)
{
	int ret = 0;
	int datasize = 0;

#ifdef CONFIG_HDCP_64BIT
	CIP_DATA_INFO_ION_RX data = {0, };
	datasize = sizeof(CIP_DATA_INFO_ION_RX);
#else
	CIP_DATA_INFO_RX data = {0, };
	datasize = sizeof(CIP_DATA_INFO_RX);
#endif /* CONFIG_HDCP_64BIT */

	if (inlen < 0 || !hdcp || !input || inlen > MAX_INPUT_LENTH) {
		HDCP2_Log("HDCP2_ERR_INVALID_INPUT (inlen = %d)", inlen);
		return HDCP2_ERR_INVALID_INPUT;
	}
	HDCP2_DEBUG("HDCP2_CopyToSecureMem_Rcv: input=0x%.8x, ion_fd=%d inlen=%d", input, ion_fd, inlen);
	data.input = (u8 *)(input);
	data.output = (u8 *)(uintptr_t)ion_fd;
	data.length = inlen;
	if ((ret = TZ_COMMAND_R_ION(CMD_CIP_SPS_PPS_DATA, (u8 *)&data, datasize, ion_fd)) < 0) {
		HDCP2_Log("Re-Decrypt Frame");
		if ((ret = TZ_COMMAND_R_ION(CMD_CIP_SPS_PPS_DATA, (u8 *)&data, datasize, ion_fd)) < 0) {
			HDCP2_Log("Ignore Frame, l=%d", data.length);
		}
		ret = HDCP2_OK;
	}
	HDCP2_DEBUG("HDCP2_CopyToSecureMem_Rcv: inlen %d outlen %d", inlen, ret);
	return ret;
}
#endif /* USE_QUALCOMM */

#ifdef USE_TEEGRIS
int HDCP2_CopyToSecureMem(HDCP2_Ctx *hdcp, u8 *input, int inlen, u8 *output )
{
	int ret = 0;
	addr_s *output_pa = 0;
	CIP_DATA_SPSPPS data;
	int remain = inlen;
	int length = 0;
	int i = 0;

	if (!hdcp || !input || inlen < 0 || !output) {
		HDCP2_Log("HDCP2_ERR_INVALID_INPUT (inlen = %d)", inlen);
		return HDCP2_ERR_INVALID_INPUT;
	}

	HDCP2_LogHex("Frame recvd...", input, 100);

	data.phy_in = input;
	data.phy_out = output;

	while (remain > 0) {
		length = (remain > MAX_SPS_BUFFER - 1) ? MAX_SPS_BUFFER - 1 : remain;
		memset(data.spspps, 0, sizeof(u8) * MAX_SPS_BUFFER - 1);
		memcpy(data.spspps, input+i, length);
		data.size = length;
		data.split_ctr = i;

		HDCP2_DEBUG("HDCP2_CopyToSecureMem called size = %d, output=%x", inlen, output);
		HDCP2_DEBUG("data length before calling tz is %d", length);
		HDCP2_LogHex("SpsPps", data.spspps, 100);

		if ((ret = TZ_COMMAND_R(CMD_CIP_SPS_PPS_DATA, (u8 *)&data, sizeof(CIP_DATA_SPSPPS), NULL, 0)) !=0) {
			HDCP2_Log("CopyToSecmem failed...%d", ret);
			break;
		}
		i += length;
		remain -= length;
	}

	if (ret < 0)
	   return ret;
	else
	   return inlen;
}
#endif /* USE_TEEGRIS */

/**
 * @fn int HDCP2_IsKeyFrame(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, int codec_type, void *pes_pkt, int pes_pkt_size)
 * @brief Checks whether the received frame is a key frame
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param codec_type codec type
 * @param pes_pkt - pointer to Packetized Elementary Stream (PES)
 * @param pes_pkt_size - size of pes_pkt
 * @return int - HDCP2_OK in case of success, else error code corresponding to the error
 */
int HDCP2_IsKeyFrame(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, int codec_type,
			void *pes_pkt, int pes_pkt_size)
{
	int ret = 0;
	int len = DEC_MAX_HEADER_SIZE;
	u8 output[DEC_MAX_HEADER_SIZE];

#ifdef USE_QUALCOMM
	HDCP2_Log("HDCP2_IsKeyFrame");
#endif /* USE_QUALCOMM */

	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	len = (pes_pkt_size < DEC_MAX_HEADER_SIZE) ? pes_pkt_size : DEC_MAX_HEADER_SIZE;

#ifdef USE_QUALCOMM
	ret = HDCP2_Decrypt_Ex(hdcp, str_ctr, in_ctr, (u8 *) pes_pkt, len, output,
					DEC_TYPE_CHECK_KEY_FRAME, codec_type);
#else
	ret = HDCP2_Decrypt_Ex_IsKeyFrame(hdcp, str_ctr, in_ctr, (u8 *) pes_pkt, len, output,
					DEC_TYPE_CHECK_KEY_FRAME, codec_type);
#endif /* USE_QUALCOMM */

	if (ret < 0)
		ret = HDCP2_ERR;

#ifdef USE_QUALCOMM
	HDCP2_Log("HDCP2_IsKeyFrame end ret %d", ret);
#endif /* USE_QUALCOMM */

	return ret;
}

/**
 * @fn int HDCP2_DecryptAudio(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output)
 * @brief This function is used to decrypt the audio type data.
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param input - pointer to the data to be decrypted.
 * @param inlen - length of input data.
 * @param output - pointer to the output data, that will be populated in this function.
 * @return int - returns input length in case of success else returns error values in case of failures.
 */
int HDCP2_DecryptAudio(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr,
			u8 *input, int inlen, u8 *output)
{
#ifdef USE_QUALCOMM
	int ret = 0;
#endif /* USE_QUALCOMM */

	if (!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

#ifdef USE_QUALCOMM
	ret = HDCP2_Decrypt_Ex(hdcp, str_ctr, in_ctr, input, inlen, output, DEC_TYPE_AUDIO, 0);
	HDCP2_DEBUG("HDCP2_DecryptAudio", output, ret);
	return ret;
#else
	return HDCP2_Decrypt_Ex_Audio(hdcp, str_ctr, in_ctr, input, inlen, output, DEC_TYPE_AUDIO, 0);
#endif /* USE_QUALCOMM */
}

/**
 * @fn int HDCP2_DecryptVideo(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr, u8 *input, int inlen, u8 *output)
 * @brief This function is used to decrypt the video type data.
 * @param hdcp - pointer to HDCP context
 * @param str_ctr - It is 32 bit stream counter. HDCP transmitter assigns a distinct stream counter for each Packetized Elementary Stream (PES).
 * @param in_ctr - It is 64 bit input counter. It is initialized to zero after SKE and must not be reset at any other time.
 * @param input - pointer to the data to be decrypted.
 * @param inlen - length of input data.
 * @param output - pointer to the output data, that will be populated in this function.
 * @return int - returns input length in case of success else returns error values in case of failures.
 */
int HDCP2_DecryptVideo(HDCP2_Ctx *hdcp, u32 str_ctr, u64 in_ctr,
			u8 *input, int inlen, obp output)
{
	if(!hdcp)
		return HDCP2_ERR_INVALID_INPUT;

	HDCP2_DEBUG("HDCP2_DecryptVideo: input=0x%.8x, ionfd=%d, inlen=%d", input, output.fd, inlen);
	HDCP2_DEBUG("HDCP2_DecryptVideo: str_ctr=%d, in_ctr=%lld", str_ctr, in_ctr);

#if defined(USE_QUALCOMM) || defined(USE_TEEGRIS)
	return HDCP2_Decrypt_ION(hdcp, str_ctr, in_ctr, input, inlen, output.fd);
#else
	addr_s *output_pa = 0;
	if (HDCP2_Ion2Addr((int)output.fd, &output_pa, NULL, inlen) != 0) {
		HDCP2_Log("Cannot convert ION handle");
		return HDCP2_ERR_INVALID_INPUT;
	}

	HDCP2_DEBUG("HDCP2_DecryptVideo: ionfd=%d, out_pa=%x, inlen=%d", (int)output.fd, output_pa, inlen);

	return HDCP2_Decrypt_Ex_VP(hdcp, str_ctr, in_ctr, input, inlen, output_pa, DEC_TYPE_VIDEO, 0);
#endif /* USE_QUALCOMM || USE_TEEGRIS */
}
