/*****************************************************************
 *****************************************************************
 ***                                                            **
 ***    (C)Copyright 2005-2006, American Megatrends Inc.        **
 ***                                                            **
 ***            All Rights Reserved.                            **
 ***                                                            **
 ***        6145-F, Northbelt Parkway, Norcross,                **
 ***                                                            **
 ***        Georgia - 30071, USA. Phone-(770)-246-8600.         **
 ***                                                            **
 *****************************************************************
 *****************************************************************
 ******************************************************************
 *
 * fru.c
 * fru functions.
 *
 *  Author: Rama Bisa <ramab@ami.com>
 *
 ******************************************************************/

#include "com_BmcType.h"
#include "com_IPMI_FRU.h"
#include <string.h>
#include "Support.h"
#include "main.h"
#include <stdio.h>

#if FRU_DEVICE == 1
#define     IPMI_FRU_FORMAT_VERSION     0x01
#define     CC_FRU_DATA_UNAVAILABLE     0x81

#define DEV_ACCESS_MODE_IN_BYTES 		0
#define FRU_TYPE_OWNER_FLASH            1	//GD32 internal flash
#define FRU_TYPE_EEPROM                 2

FRUInfo_T	FRUInfo = {
	FRU_TYPE_OWNER_FLASH,		/* FRU type NVR/EEPROM/....                     */
	FRU_TOTAL_SIZE,				/* FRU Device size                              */
	DEV_ACCESS_MODE_IN_BYTES,	/* FRU device access type BYTE/WORD             */
	0,							/* Bus number if FRU is EEPROM                  */
	0,							/* FRU device slave address if FRU is EEPROM    */
	0							/* FRU device type if FRU is EEPROM             */
};

static int ReadFRUDevice (FRUInfo_T* pFRUInfo, uint16_t Offset, uint8_t Len, uint8_t* pData)
{
	switch (pFRUInfo->Type)
	{
		case FRU_TYPE_OWNER_FLASH:
			memcpy(pData, (((uint8_t*)&g_BMCInfo.FRU) + Offset), Len);
			return Len;

		case FRU_TYPE_EEPROM:
			//return  READ_EEPROM (pFRUInfo->DeviceType, pFRUInfo->BusNumber, pFRUInfo->SlaveAddr, pData,
			//									 pFRUInfo->Offset + Offset, Len); 
			printf("Read FRU from EEPROM not implement\r\n");
			return 0;

		default:
			printf ("PDKFRU.c : FRU Type not supported\n");
			return 0;
	}
}

static int WriteFRUDevice (FRUInfo_T* pFRUInfo, uint16_t Offset, uint8_t Len, uint8_t* pData)
{
    switch (pFRUInfo->Type)
    {
        case FRU_TYPE_OWNER_FLASH:
            //return  API_WriteNVR (pFRUInfo->NVRFile, Offset, Len, pData);
			memcpy((((uint8_t*)&g_BMCInfo.FRU) + Offset), pData, Len);
			FlushFRUToFlash();
            return Len;

        case FRU_TYPE_EEPROM:
            //return  WRITE_EEPROM (pFRUInfo->DeviceType, pFRUInfo->BusNumber, pFRUInfo->SlaveAddr, pData,
            //                                        pFRUInfo->Offset + Offset, Len);
            printf("Write FRU to EEPROM not implement\r\n");
			return 0;

        default:
            printf ("PDKFRU.c : FRU Type not supported\n");
            return 0;
    }
}

/*-----------------------------------------------------
 * GetFRUAreaInfo
 *----------------------------------------------------*/
int
GetFRUAreaInfo ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    FRUInventoryAreaInfoRes_T*  pFRUAreaInfoRes = (FRUInventoryAreaInfoRes_T*) pRes;

    pFRUAreaInfoRes->CompletionCode     = 	CC_NORMAL;
    pFRUAreaInfoRes->Size               = 	FRUInfo.Size;
    pFRUAreaInfoRes->DeviceAccessMode   = 	FRUInfo.AccessType;

    return sizeof(FRUInventoryAreaInfoRes_T);
}


/*-----------------------------------------------------
 * Read FRU Data
 *----------------------------------------------------*/
int
ReadFRUData ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    uint16_t          Offset;
    FRUReadReq_T*   pFRUReadReq = (FRUReadReq_T*) pReq;
    FRUReadRes_T*   pFRUReadRes = (FRUReadRes_T*) pRes;
    int retval = 0;

	Offset = pFRUReadReq->Offset;
    /* check if the offset is valid offset */
    if (Offset >= FRUInfo.Size)
    {
        pFRUReadRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(uint8_t);
    }

    /* Is CountToRead too big? */
    if (pFRUReadReq->CountToRead > (FRUInfo.Size - Offset))
    {
		pFRUReadRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
		return sizeof(uint8_t);
    }

    pFRUReadRes->CompletionCode  =  CC_NORMAL;

    /* Read the FRU date from the FRU device */
    retval = ReadFRUDevice (&FRUInfo, Offset,
                                    pFRUReadReq->CountToRead,
                                    (uint8_t*)(pFRUReadRes + 1));

    if (retval != -1)
    {
        pFRUReadRes->CountReturned = (uint8_t) retval;
    }
    else
    {
        pFRUReadRes->CompletionCode = CC_FRU_DATA_UNAVAILABLE;
        return sizeof(uint8_t);
    }

//    printf ("FRU Count returned  %x\r\n", pFRUReadRes->CountReturned);
    
    /*Updating Response Length.*/
    return (pFRUReadRes->CountReturned + sizeof(FRUReadRes_T));
}


/*-----------------------------------------------------
 * Write FRU Data
 *----------------------------------------------------*/
int
WriteFRUData ( uint8_t* pReq, uint8_t ReqLen,  uint8_t* pRes)
{
    uint16_t        Offset,Length;
    FRUWriteReq_T   *pFRUWriteReq = (FRUWriteReq_T*) pReq;
    FRUWriteRes_T   *pFRUWriteRes = (FRUWriteRes_T*) pRes;
    int 			retval = 0;
	
    /* Get the offset to write & number of bytes to write */
    Offset  =  (pFRUWriteReq->Offset);
    Length  = ReqLen - sizeof (FRUWriteReq_T);

    /* check if the offset is valid offset */
    if (Offset >= FRUInfo.Size)
    {
        pFRUWriteRes->CompletionCode = CC_INV_DATA_FIELD;
        return sizeof(uint8_t);
    }

    /* Is Length too big? */
    if (Length > (FRUInfo.Size - Offset))
    {
		pFRUWriteRes->CompletionCode = CC_PARAM_OUT_OF_RANGE;
		return sizeof(uint8_t);
    }

    pFRUWriteRes->CompletionCode = CC_NORMAL;

    /* Wrtie the date to FRU device */
    retval = WriteFRUDevice (&FRUInfo, Offset, Length,
                                                (uint8_t*)(pFRUWriteReq + 1));
    if (retval != -1)
    {
    	pFRUWriteRes->CountWritten  = (uint8_t) retval;
    }
    else
    {
        pFRUWriteRes->CompletionCode = CC_FRU_DATA_UNAVAILABLE;
        return sizeof(uint8_t);
    }
    return sizeof(FRUWriteRes_T);
}

#endif /* FRU_DEVICE */
