
/*
   *  Object %name    : SEPDriver.h
   *  State           :  %state%
   *  Creation date   :  Wed Nov 17 17:39:24 2004
   *  Last modified   :  %modify_time%
   */
  /** @file
   *  \brief  Key Management h file (API and structures )
   *
   *  \version 
   *  \author yevgenys
   *  \remarks Copyright (C) 2004 by Discretix Technologies Ltd.
   *           All Rights reserved
   */

//#include <string.h>
/* for memcpy */
#include <linux/mm.h>


#include "stdarg.h"
#include "BaseTypes.h"
#include "error.h"
#include "SEPDriver.h"
#include "gen.h"
#include "FVOS_Types.h"
#include "FVOS_API.h"
#include "FVOS_Config.h"
#include "FVOS_Error.h"




/*------------------------------
    DEFINES
--------------------------------*/
#define SEPDRIVER_START_MESSAGE_TOKEN   0X02558808


/*--------------------------------------
  PROTOTYPES
---------------------------------------*/


/*--------------------------------------
   GLOBAL variables
---------------------------------------*/


/* address of the shared RAM */
DxUint32_t    g_SharedRamAddr;

/* function to be called as callback for NVS transactions */
#ifdef DX_NVS_SUPPORT
extern DxError_t  NVSHost_Parser(void);
#endif



/*------------------------------------------------
    FUNCTIONS
--------------------------------------------------*/




/**
 * @brief       This function start the message in the SRAM. It inserts the token and the total length of the message,
 *              and returns the offset into message from where to start writing the next paramater
 *
 * @param[out] messageOffset_ptr - offset of the next paramater to be written into the message
 *
 */
void SEPDriver_StartMessage(DxUint32_t*  messageOffset_ptr)
{
  
  /*---------------
     CODE
  ------------------*/
/* Cancelling lint warning - Ignoring return value of function */
/*lint -save -e{534} */
  FVOS_Mmap(&g_SharedRamAddr);
/*lint -restore */
  
  /* write token into message and convert the endianness if needed */
  *(DxUint32_t*)g_SharedRamAddr = SEPDRIVER_START_MESSAGE_TOKEN; 
  
  /* set the next parameter offset - the first 2 words are token and messsage length */
  *messageOffset_ptr = sizeof(DxUint32_t) * 2;

}

/**
 * @brief       This function ends the message in the SRAM. It inserts CRS and then raises the interrupt to SEP
 *
 * @param[in] messageOffset - 
 *                  
 */
void SEPDriver_EndMessage(DxUint32_t   messageOffset)
{ 
  /* message length */
  DxUint32_t    messageLength;
  
  /*-----------------
    CODE
  -----------------*/
  
  /* length of message in words is the whole length + word of crc */
  messageLength = messageOffset / sizeof(DxUint32_t) + 1;
  
  /* insert the length in bytes into message */
  *(DxUint32_t*)(g_SharedRamAddr + 4) = messageLength;
  
  /* set 0 for temp CRC */
  *(DxUint32_t*)(g_SharedRamAddr + messageOffset) = 0;
  
  /* calculate the CRC and insert it */
  *(DxUint32_t*)(g_SharedRamAddr + messageOffset) = SEPDriver_CheckSumCalc((DxUint8_t*)g_SharedRamAddr , messageLength * sizeof(DxUint32_t));

/* Cancelling lint warning - Ignoring return value of function */
/*lint -save -e{534} */
  FVOS_Cntrl(FVOS_CNTRL_SEND_MSG_RDY_CMD , DX_NULL);
/*lint -restore */
  
}



/**
 * @brief       This function start the incoming message from SEP. It checks the start token , the length and the CRC
 *
 * @param[out] messageOffset_ptr - offset of the next paramater to be read from the message
 *                        
 */
DxError_t SEPDriver_StartIncomingMessage(DxUint32_t*  messageOffset_ptr)
{
  /* opcode */
  DxUint32_t  token;

  /* message length */
  DxUint32_t  messageLength;
  
  /* get CRC */
  DxUint32_t  crc;
  
  /* error */
  DxError_t     error;
  /*---------------
     CODE
  ------------------*/
  
  error = DX_OK;
  
  /* get start token */
  token = *(DxUint32_t*)g_SharedRamAddr;
  
  if(token != SEPDRIVER_START_MESSAGE_TOKEN)
  {
    error = DX_FAILED_START_TOKEN_ERR;
    goto end_function;
  }
  
  /* get message length */
  messageLength = *(DxUint32_t*)(g_SharedRamAddr + sizeof(DxUint32_t));
  
  /* get CRC */
  crc = *(DxUint32_t*)(g_SharedRamAddr + (messageLength - 1) * sizeof(DxUint32_t));
  
  /* calculate and check CRC */
  *(DxUint32_t*)(g_SharedRamAddr + (messageLength - 1) * sizeof(DxUint32_t)) = 0;
  if(crc != SEPDriver_CheckSumCalc((DxUint8_t*)g_SharedRamAddr , messageLength * sizeof(DxUint32_t)))
  {
    error = DX_FAILED_CRC_IN_MESSAGE_ERR;
    goto end_function;
  }
  
  /* set the offset */
  *messageOffset_ptr = sizeof(DxUint32_t) * 2; 
  
end_function:

  return error;
}


/**
 * @brief       This function writes a a parameter into SHARED memory. Paramter can be either a word or an array of words or bytes
 *              If this is an array of bytes, then the bytesArrayFlag should be set, so that the parameter will be converted into little endian (if needed)
 *
 * @param[in] paramAddress - address pf the parameter to insert
 * @param[in] paramLengthInBytes - parameter length in bytes
 * @param[in] maxParamLengthInBytes - maximum number of bytes that this parameter should take in the message.Must be word alligned
 * @param[in/out] messageOffset_ptr - offset into message before and after insertion
 * @param[in] bytesArrayFlag - if this is byte array that should be converted
 *  
 * @return: Error - if the maxParamLengthInBytes is not word alligned                      
 */
DxError_t SEPDriver_WriteParamater(DxUint32_t   paramAddress,
                                   DxUint32_t   paramLengthInBytes,
                                   DxUint32_t   maxParamLengthInBytes,
                                   DxUint32_t*  messageOffset_ptr,
                                   DxUint32_t   bytesArrayFlag)
{
  /* paramater address */
  DxUint32_t  sramAddress;

  /*------------------
    CODE
  -------------------*/
  
  if( (maxParamLengthInBytes < paramLengthInBytes) || (maxParamLengthInBytes % sizeof(DxUint32_t)) )
  {
    return DX_PARAM_NOT_ALLIGNED_ERR;
  }
  
  /* set address to where to insert parameter */
  sramAddress = g_SharedRamAddr + *messageOffset_ptr;
  
  /* copy the data into shared ram */
  memcpy((DxUint8_t*)sramAddress , (DxUint8_t*)paramAddress , paramLengthInBytes);
  
  if(bytesArrayFlag)
  {
    DX_GEN_CHANGE_ENDIANNESS(sramAddress , ((paramLengthInBytes + 3) / sizeof(DxUint32_t)) );
  }
  
  /* update the message offset */
  *messageOffset_ptr += maxParamLengthInBytes;

  return DX_OK;
}


/**
 * @brief       This function reads a a parameter from SHARED memory. Paramter can be either a word or an array of words or bytes
 *              If this is an array of bytes, then the bytesArrayFlag should be set, so that the parameter will be converted into little endian (if needed)
 *
 * @param[in] paramAddress - address of the parameter to read
 * @param[in] paramLengthInBytes - parameter length in bytes
 * @param[in] maxParamLengthInBytes - maximum number of bytes that this parameter should take in the message.Must be word alligned
 * @param[in/out] messageOffset_ptr - offset into message before and after insertion
 * @param[in] bytesArrayFlag - if this is byte array that should be converted
 *
 * @return: Error - if the maxParamLengthInBytes is not word alligned  
 */
DxError_t SEPDriver_ReadParamater(DxUint32_t    paramAddress ,
                                  DxUint32_t    paramLengthInBytes,
                                  DxUint32_t    maxParamLengthInBytes,
                                  DxUint32_t*   messageOffset_ptr,
                                  DxUint32_t    bytesArrayFlag)
{
  /* address in the sram */
  DxUint32_t    sramAddress;
  
  /*------------------
    CODE
  -------------------*/
  
  if( (maxParamLengthInBytes < paramLengthInBytes) || (maxParamLengthInBytes % sizeof(DxUint32_t)) )
  {
    return DX_PARAM_NOT_ALLIGNED_ERR;
  }
  
  /* set address to where to insert parameter */
  sramAddress = g_SharedRamAddr + *messageOffset_ptr;
  
  if(bytesArrayFlag)
  {
    DX_GEN_CHANGE_ENDIANNESS(sramAddress , ((paramLengthInBytes + 3) / sizeof(DxUint32_t)) );
  }
  
  /* copy from user data */
  memcpy((DxUint8_t*)paramAddress , (DxUint8_t*)sramAddress , paramLengthInBytes);
  
  /* update next message offset */
  *messageOffset_ptr += maxParamLengthInBytes;

  return DX_OK;
}



/**
 * @brief       This function locks access to the SEP driver and though it to the SEP
 *
 * @param[in] 
 *
 * @return     DxError_t: 
 *
 */
DxError_t SEPDriver_Lock()
{
  /* error */
  DxError_t   error;

  /*---------------------
      CODE
  -----------------------*/

  error = DX_OK;
	
  /* start transaction */
  error = FVOS_StartTransaction();
  
  if (error == FVOS_SEP_IS_DISABLED_ERR)
  {
  		return DX_MNG_SEP_IS_DISABLE_ERR;
  }
  	
  
  return error;
}

/**
 * @brief       This function unlocks access to the SEP driver and though it to the SEP
 *
 * @param[in] 
 *
 */
void SEPDriver_Unlock(void)
{
  /*------------------------
      CODE
  --------------------------*/

/* Cancelling lint warning - Ignoring return value of function */
/*lint -save -e{534} */
  FVOS_EndTransaction(g_SharedRamAddr);
/*lint -restore */
}

/**
 * @brief       This function waits for response from SEP(either by polling , or by event )
 *
 * @param[in] type - the type of polling - event, polling
 * @param[in] eventId - id of event in case type is EVENT, otherwise 0.
 * @param[in] callbackFunc_ptr - call back function in case the type is polling with callback
 * @return     DxError_t:  
 *                        
 */
DxError_t SEPDriver_WaitForResponse(SEPDriver_PollingType_t type , 
                                    DxUint32_t              eventId,
                                    SEP_CallbackFunc        callbackFunc_ptr,
                                    DxUint32_t              timeOut)
{
  /* source for interrupt */
  DxUint32_t  intSource;  
  
  /* error */
  DxError_t   error;
  /*--------------
    CODE
  ----------------*/
  /* Eliminating compiler warnings: */
  type = type;
  eventId = eventId;
  callbackFunc_ptr = callbackFunc_ptr;
  
  error = DX_OK;
  
  while(1)
  {
    error = FVOS_Poll(timeOut , &intSource);
    
    /* if we failed on timeout - exit with appropriate error code */
    if(error == FVOS_TIMEOUT_ERR)
    {
      goto end_function;
    }
    
    /* if this is reply to the original HOST request  - exit the function with OK status */
    if(intSource == FVOS_SEP_REPLY)
    {
      goto end_function;
    }
    
#ifdef DX_NVS_SUPPORT
    /* this is NVS request from SEP - activate the function */
    NVSHost_Parser();
#endif
  }
    

end_function:

  return error;
}

/**
 * @brief       This function builds the DMA tables for symmetric CRYS APIs
 *
 * @param[in] dataInAddr - start address of the input data
 * @param[in] dataOutAddr - start address of the input data. If it is 0, then no output tables will be generated
 * @param[in] dataInSize - size of input data in bytes.
 * @param[in] blockSize - virtual allocated address
 * @param[out] firstInTable_ptr - pointer to physical address of the first input table
 * @param[out] firstOutTable_ptr - pointer to physical address of the first output table
 * @param[out] firstInTableNumEntries_ptr - pointer to the number of entries in the first input table
 * @param[out] firstOutTableNumEntries_ptr - pointer to the number of entries in the first output table
 * @param[out] firstTableDataSize_ptr - pointer to the data in the first in table ( the same for input and output)
 * 
 * @return     DxError_t:  
 *
 */
DxError_t SEPDriver_PrepareSymDMATables(DxUint32_t    dataInAddr,
                                        DxUint32_t    dataOutAddr,
                                        DxUint32_t    dataInSize,
                                        DxUint32_t    blockSize,
                                        DxUint32_t*   firstInTable_ptr,
                                        DxUint32_t*   firstOutTable_ptr,
                                        DxUint32_t*   firstInTableNumEntries_ptr,
                                        DxUint32_t*   firstOutTableNumEntries_ptr,
                                        DxUint32_t*   firstTableDataSize_ptr)
{
  /* input alloc structure */
  FVOS_Cntrl_info_t tableData;
  
  /* error */
  DxError_t         error;
  
  /*---------------
      CODE
  -----------------*/
  
  error = DX_OK;
  
  /* prepare input data */
  tableData.data.buildSymDMATables.dataInAddr = dataInAddr;
  tableData.data.buildSymDMATables.dataInSize = dataInSize;
  tableData.data.buildSymDMATables.dataOutAddr = dataOutAddr;
  tableData.data.buildSymDMATables.blockSize = blockSize;
  
  error = FVOS_Cntrl(FVOS_CNTRL_BUILD_SYM_DMA_TABLES_CMD , &tableData);
  if(error != DX_OK)
  {
    goto end_function;
  }
  
  /* set the output variables */
  *firstInTable_ptr = tableData.data.buildSymDMATables.firstInTableAddr;
  *firstInTableNumEntries_ptr = tableData.data.buildSymDMATables.firstInTableNumEntries;
  
  /* check output table data if needed */
  if(firstOutTable_ptr != DX_NULL)
  {
    *firstOutTable_ptr = tableData.data.buildSymDMATables.firstOutTableAddr;
    *firstOutTableNumEntries_ptr = tableData.data.buildSymDMATables.firstOutTableNumEntries;
  }
  
  *firstTableDataSize_ptr = tableData.data.buildSymDMATables.firstTableDataSize;
  
end_function:

  return error;
}



/**
 * @brief       This function performs the needed clenup after the DMA action is finished.Depending on the enviroment
 *              it frees any dynamically allocted resources
 *
 * @return     DxError_t:  
 *
 */
DxError_t SEPDriver_FreeDMATables(void)
{
  return FVOS_Cntrl(FVOS_CNTRL_FREE_DMA_RESOURSES , DX_NULL);
}





/**
 * @brief       This function calculates the check sum on the given data 
 *
 * @param[in] data- data to perfrom checksum on
 * @param[in] length - length of data
 *
 * @return  DxUint32_t  - Checksum 
 *                        
 */
DxUint32_t SEPDriver_CheckSumCalc(DxUint8_t *data, DxUint32_t length)
{
  DxUint32_t sum = 0;
	DxUint16_t *Tdata = (DxUint16_t *)data;

	while( length > 1 )  
	{
    /*  This is the inner loop */
    sum += *Tdata++;
    length -= 2;
  }
  /*  Add left-over byte, if any */
  if( length > 0 )
    sum += * (DxUint8_t *) Tdata;

  /*  Fold 32-bit sum to 16 bits */
  while (sum>>16)
    sum = (sum & 0xffff) + (sum >> 16);

	return (~sum &0xFFFF);
}




