/*****************************************************************************
** al_setting.c: AL Layer System Setting Source Code
**
** Description: the interface of system setting module.
**
** Copyright(c) 2011 Sunmedia Technologies - All Rights Reserved
**
** Author : anlzhao
**
** $Id: al_setting.c 1900 2011-01-22 05:41:35Z liang.wu_c1 $
*****************************************************************************/
#include "gl_api.h"
#include "gl_sema.h"
#include "ai_debug_config.h"
#include "al_setting.h"
#include "nvm_ioctl.h"
#include "cust_nvm_cfg.h"
#include "mid_tvfe.h"
/* debug and error print */
#ifdef SETTING_DBG_FLAG
	#define SETTING_DEBUG_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Debug]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SETTING_DEBUG_MESSAGE(fmt, arg...);
#endif

#ifdef SETTING_ERROR_FLAG
	#define SETTING_ERROR_MESSAGE(fmt, arg...) \
	do { \
		UMFDBG(0,"[Error]%s: %d Line ", __FUNCTION__, __LINE__); \
		UMFDBG(0,fmt, ##arg); \
	} while(0)
#else
	#define SETTING_ERROR_MESSAGE(fmt, arg...);
#endif

/* if it have been initialized */
#define IS_INIT_ALREADY()			(gVD_State == VD_INITIALIZED)

/* Semaphore */
#define VD_SEM_NAME					"VIRTUALDEV_SEM"
#define VD_SEM_MAX					(1)
#define VD_SEM_INITIAL				(1)

/* 64 KByte */
#define FLASH_ERASEABLE_BLOCK_SIZE	(0)//(16)
#define EEPROM_ERASEABLE_BLOCK_SIZE	(0)
#define HDD_ERASEABLE_BLOCK_SIZE	(0)

/* semaphore take and give */
#define VD_SEM_TAKE(sem_id, sem_time) \
	if (GL_SemaphoreTake(sem_id, sem_time) != GL_SUCCESS) { \
		SETTING_ERROR_MESSAGE("VD SEM TAKE\n"); \
		return AL_FAILURE; \
	}

#define VD_SEM_GIVE(sem_id) \
	if (GL_SemaphoreGive(sem_id) != GL_SUCCESS) { \
		SETTING_ERROR_MESSAGE("VD SEM GIVE\n"); \
		return AL_FAILURE; \
	}


/*
** Internal data structure
*/
/* component type */
typedef struct
{
	ENVMPurposeID_t dev_type;
	al_uint32 component_start_address; /* start address of the component */
	al_uint16 component_size; /* Size of the component */
	al_uint32 component_offset; /* Offset of the component in memory cache */
	al_bool corrupt; /* CRC check flag */
} Setting_Component_st;

/*Info of the component to be stored into device for User Preference*/
typedef struct
{
	Setting_Component_st *pstComTbl;
	al_uint8 num_comp;
	al_uint32 cache_size;
	al_uint8 *cache;
} VD_Device_Info;

/* device control block of virtual device */
typedef struct
{
	al_uint8 u8Flag;    /* 1: used   0: free */
	VD_Device_Info *DevInfo;
	GL_Semaphore_t vd_sem_id;
	al_uint8 *pTmpBuffer;	//temp solution for SIS New System Porting by jun.luo @ 2013/7/2
}VD_DCB_t;

typedef enum
{
	VD_UN_INITIALIZED,
	VD_INITIALIZING,
	VD_INITIALIZED,
	VD_TERMINATING,
} VD_STATE_e;

#ifdef SUPPORT_FACTORY_AUTO_TEST_MODE4
int AutoTest_ResetSaveFlash = 1;
#endif

/*
** table of device control block of all virtual devices
** NOTE:  only allow initialize MAX_DEVICE virtual devices at ones.
*/
static VD_DCB_t *g_pstVD_DCB_Tbl = al_null;
/* semaphore of dcb table */
static GL_Semaphore_t gDCB_SemId;
static VD_STATE_e gVD_State = VD_UN_INITIALIZED;
VD_Device_Info  g_pDevInfo;/*   for device information */

/*
** static function
*/
static AL_SETTING_HANDLE _GetFreeVirtualDev(al_void)
{
    AL_SETTING_HANDLE handle = INVAILDHANDLE;
    al_int32 i = 0;

    if (al_null == g_pstVD_DCB_Tbl)
    {
        return INVAILDHANDLE;
    }

    for (i = 0; i < MAX_DEVICE; ++i)
    {
        if (0 == g_pstVD_DCB_Tbl[i].u8Flag) /* find free virtual device */
        {
            handle = i;
            break;
        }
    }

    if (MAX_DEVICE == i)        /* no free DCB */
    {
        handle = INVAILDHANDLE;
    }

    return handle;
}

static VD_DCB_t *_GetDCB(AL_SETTING_HANDLE handle)
{
    if (handle <= INVAILDHANDLE || handle >= MAX_DEVICE || al_null == g_pstVD_DCB_Tbl)
    {
        return al_null;
    }

    return &(g_pstVD_DCB_Tbl[handle]);
}

#define IsConflict(addr1, size1, addr2, size2)  \
    !(((addr1) >= (addr2)+(size2)) && ((addr2) >= (addr1)+(size1)))

static al_bool _CheckConflict(const al_uint16* size_arr, const al_uint32* addr_arr, al_uint8 num_comp)
{
    al_uint8 loop = 0;
    al_uint32 start_addr = 0;
    al_uint32 end_addr = 0;
    al_uint8 num_comp_temp;
    VD_Device_Info *p_stDevice = al_null;
    al_uint8 i, j;

    for (loop = 0; loop < MAX_DEVICE; ++loop)
    {
        if (g_pstVD_DCB_Tbl[loop].u8Flag == 0)
        {
            continue;
        }

        p_stDevice = g_pstVD_DCB_Tbl[loop].DevInfo;
        num_comp_temp = p_stDevice->num_comp;
        start_addr = p_stDevice->pstComTbl[0].component_start_address;
        end_addr = p_stDevice->pstComTbl[num_comp_temp - 1].component_start_address
            + p_stDevice->pstComTbl[num_comp_temp - 1].component_size + CRC_INFO_SIZE;

        if ((addr_arr[0] >= end_addr) && (start_addr >= addr_arr[num_comp - 1]))
        {
            continue;
        }

        for (i = 0; i < num_comp_temp; ++i)
        {
            for (j = 0; j < num_comp; ++j)
            {
                if (IsConflict(addr_arr[j], size_arr[j],
                               p_stDevice->pstComTbl[i].component_start_address,
                               p_stDevice->pstComTbl[i].component_size))
                {
                    return al_true;
                }
            }
        }
    }

    return al_false;
}

/***************************************************************************
** FUNCTION :      AI_Setting_Init
**
** DESCRIPTION :
**                 initialize the system setting modules.
** PARAMETERS :
**                 none
** RETURN VALUES :
**				AL_SUCCESS
**				AL_FAILURE
**				AL_MEMORY_ALLOC_FAILED
***************************************************************************/
AL_Return_t AI_Setting_Init(al_void)
{
    SETTING_DEBUG_MESSAGE("Enter...\n");
    /*
     ** check current state
     */
    /* it have been initialized or initializing */
    if (VD_UN_INITIALIZED != gVD_State)
    {
        return AL_FAILURE;
    }

    gVD_State = VD_INITIALIZING; /* initializing */

    /* malloc memory for dcb table */
    g_pstVD_DCB_Tbl = (VD_DCB_t *) malloc(MAX_DEVICE * sizeof(VD_DCB_t));
    if (al_null == g_pstVD_DCB_Tbl)
    {
        gVD_State = VD_UN_INITIALIZED; /* reset flag */

        SETTING_ERROR_MESSAGE("malloc faild!\n");
        return AL_MEMORY_ALLOC_FAILED;
    }
    memset(g_pstVD_DCB_Tbl, 0, MAX_DEVICE * sizeof(VD_DCB_t));

    /* Creating Semaphore for dcb table */
    if (GL_SUCCESS != GL_SemaphoreCreate(VD_SEM_NAME, VD_SEM_MAX, VD_SEM_INITIAL, &gDCB_SemId))
    {
        free(g_pstVD_DCB_Tbl);  /* release resouce */
        g_pstVD_DCB_Tbl = NULL;

        gVD_State = VD_UN_INITIALIZED; /* reset flag */
        SETTING_ERROR_MESSAGE("GL_SemaphoreCreate\n");
        return AL_FAILURE;
    }

	gVD_State = VD_INITIALIZED;
    SETTING_DEBUG_MESSAGE("Exit...\n");
    return AL_SUCCESS;
}

/***************************************************************************
** FUNCTION :      AI_Setting_Term
**
** DESCRIPTION :
**                 Terminate the system setting modules.
** PARAMETERS :
**                 none
** RETURN VALUES :
**				AL_SUCCESS
**				AL_FAILURE
***************************************************************************/
AL_Return_t AI_Setting_Term(al_void)
{
    al_int32 i = 0;

    if (VD_INITIALIZED != gVD_State)
    {
        SETTING_ERROR_MESSAGE("state is not at initialized!\n");
        return AL_FAILURE;
    }

    VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
    gVD_State = VD_TERMINATING;

    /* release all resource */
    for (i = 0; i < MAX_DEVICE; ++i)
    {
        if (al_null != g_pstVD_DCB_Tbl[i].DevInfo)
        {
            free(g_pstVD_DCB_Tbl[i].DevInfo);
            g_pstVD_DCB_Tbl[i].DevInfo = al_null;
        }
        if (al_null != g_pstVD_DCB_Tbl[i].vd_sem_id)
        {
            GL_SemaphoreDelete(g_pstVD_DCB_Tbl[i].vd_sem_id);
            g_pstVD_DCB_Tbl[i].vd_sem_id = al_null;
        }
    }

    if (al_null != g_pstVD_DCB_Tbl)
    {
        free(g_pstVD_DCB_Tbl);
        g_pstVD_DCB_Tbl = al_null;
    }

    VD_SEM_GIVE(gDCB_SemId);

    /* Deleting Semaphore for User Preference */
    GL_SemaphoreDelete(gDCB_SemId);
    gDCB_SemId = al_null;

    gVD_State = VD_UN_INITIALIZED;

    return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_SetDeviceComp
**
** DESCRIPTION :
**                      Through the API to get the system Settings module in a storage device layout information
**                      ex: There are two device  ENVMPurposeIDSysSetting and ENVMPurposeIDSysSettingPQSETTING
**                              DEFINE_BLOCK_DATA 
**
** PARAMETERS :
**			input:	
**                       size_arr	- Array of component sizes
**				addr_arr	- Array of component address
**                       tech_arr   - Array of component device type
**				num_comp	- No. of components
**			output:
**                       ppDevInfo	- device component information
**
*****************************************************************************/
AL_Return_t AL_Setting_SetDeviceComp(const al_uint16 * size_arr,const al_uint32 * addr_arr, const al_uint32 * tech_arr, al_uint8 num_comp, VD_Device_Info *ppDevInfo)
{
    /* initialize each component */
    al_uint8 loop = 0;
    al_uint8 componentIndex = 0;
    al_uint32 prev_size = size_arr[0];
    al_uint32 prev_addr = addr_arr[0];
    ENVMPurposeID_t prev_devtype = (ENVMPurposeID_t)(tech_arr[0]);
    Setting_Component_st * temp = NULL;
    
    al_uint32 total_size = sizeof(Setting_Component_st) * num_comp;

    temp = (Setting_Component_st *) malloc(total_size);
    if (temp == NULL)
    {
        return AL_FAILURE;
    }
    
    temp[componentIndex].dev_type = prev_devtype;
    temp[componentIndex].component_start_address = prev_addr;
    temp[componentIndex].component_size = prev_size;
    temp[componentIndex].component_offset = 0;
    temp[componentIndex].corrupt = al_true;

    for (loop = 1; loop < num_comp; loop++)
    {
        if (prev_devtype != tech_arr[loop])
        {      
            temp[componentIndex].dev_type = prev_devtype;
            temp[componentIndex].component_start_address = prev_addr;
            temp[componentIndex].component_size = prev_size;
            temp[componentIndex].component_offset = prev_addr;
            temp[componentIndex].corrupt = al_true;
    
            componentIndex++;
    
            temp[componentIndex].dev_type = (ENVMPurposeID_t)(tech_arr[loop]);
            temp[componentIndex].component_start_address = addr_arr[loop];
            temp[componentIndex].component_size = size_arr[loop];
            temp[componentIndex].component_offset = prev_size;
            temp[componentIndex].corrupt = al_true;
    
            prev_devtype = (ENVMPurposeID_t)(tech_arr[loop]);
            prev_addr    = addr_arr[loop];
            prev_size    = 0;
        }
    
        prev_size += size_arr[loop];
        
        if ((loop == (num_comp-1))&& prev_devtype == tech_arr[loop])
        {
            temp[componentIndex].dev_type = prev_devtype;
            temp[componentIndex].component_start_address = prev_addr;
            temp[componentIndex].component_size = prev_size;
            temp[componentIndex].component_offset = prev_addr;
            temp[componentIndex].corrupt = al_true;
    
            componentIndex++;
        }
    }

#if 0//debug
    SETTING_DEBUG_MESSAGE("nvm, start, size, offset\n");
    for (loop = 0; loop < componentIndex; loop++)
    {
        SETTING_DEBUG_MESSAGE("%d, %d, %d, %d\n\n", temp[loop].dev_type,
        temp[loop].component_start_address,
        temp[loop].component_size,
        temp[loop].component_offset);
    }
#endif    
    ppDevInfo->pstComTbl = temp;
    ppDevInfo->num_comp = componentIndex;
    
    return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_Open
**
** DESCRIPTION :
**				This method initializes the user preference component.
**				Notice:This function must be first before any functions
**				are called
**
** PARAMETERS :
**				VirtualDev_Dev_t	- Storage device
**				size_arr	- Array of component sizes
**				addr_arr	- Array of component address
**				num_comp	- No. of components
**				p_stParam	- Device registered functions
**
** RETURN VALUES:
**				AL_SETTING_HANDLE
*****************************************************************************/
AL_SETTING_HANDLE AL_Setting_Open(const al_uint16 * size_arr,
                                  const al_uint32 * addr_arr, const al_uint32 * tech_arr, al_uint8 num_comp)
{
    AL_SETTING_HANDLE handle = INVAILDHANDLE;
    Setting_Component_st *pstCom = al_null;
    al_uint32 offset = 0;
    al_uint16 cache_size = 0;
    al_uint8 loop = 0;
    al_uint32 crc_32 = 0;
    al_uint32 stored_crc_32 = 0;
    VD_DCB_t *pVD_DCB = al_null;


    SETTING_DEBUG_MESSAGE("Enter\n");

    /* check current state */
    if (!IS_INIT_ALREADY())
    {
        SETTING_ERROR_MESSAGE("Un intialized!\n");
        return INVAILDHANDLE;
    }

    /* Parameter check 1 */
    if (size_arr == al_null || addr_arr == al_null || tech_arr == al_null || num_comp <= 0 || num_comp > MAX_NUM_COMP)
    {
        SETTING_ERROR_MESSAGE("Invalid paramters\n");
        return INVAILDHANDLE;
    }

    VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
    /* check if conflict with virtual device before */
    if (_CheckConflict(size_arr, addr_arr, num_comp))
    {
        SETTING_ERROR_MESSAGE("conflict with virtual device before!\n");
        VD_SEM_GIVE(gDCB_SemId);
        return INVAILDHANDLE;
    }

    /* get free dcb */
    handle = _GetFreeVirtualDev();
    if (INVAILDHANDLE == handle)
    {
        SETTING_ERROR_MESSAGE("no free virtual device!\n");
        VD_SEM_GIVE(gDCB_SemId);
        return INVAILDHANDLE;
    }
    pVD_DCB = _GetDCB(handle);
    if (NULL == pVD_DCB)
    {
        SETTING_ERROR_MESSAGE("no free virtual device!\n");
        VD_SEM_GIVE(gDCB_SemId);
        return INVAILDHANDLE;
    }
    pVD_DCB->u8Flag = 1;
    VD_SEM_GIVE(gDCB_SemId);

    /*
     ** create need resource
     */
    /* calculate size of cache */
    cache_size = 0;
    for (loop = 0; loop < num_comp; ++loop)
    {
        cache_size += size_arr[loop] + CRC_INFO_SIZE;
    }

    /*
     ** malloc device information resource
     ** Note: contains VD_Device_Info, compTable, cache
     */
    al_uint32 total_size = sizeof(VD_Device_Info) + sizeof(Setting_Component_st) * num_comp + cache_size;

    pVD_DCB->DevInfo = (VD_Device_Info *) malloc(total_size);
    //temp solution for SIS New System Porting by jun.luo @ 2013/7/2
    pVD_DCB->pTmpBuffer = malloc(cache_size);

    if (al_null == pVD_DCB->DevInfo)
    {
        SETTING_ERROR_MESSAGE("malloc fail!\n");
        pVD_DCB->u8Flag = 0;    /* free DCB */
        return INVAILDHANDLE;
    }
    else                        /* initialize device information */
    {
        memset(pVD_DCB->DevInfo, 0, total_size);

        pVD_DCB->DevInfo->pstComTbl = (Setting_Component_st *) ((al_uint8 *) pVD_DCB->DevInfo + sizeof(VD_Device_Info));
        pVD_DCB->DevInfo->num_comp = num_comp;
        pVD_DCB->DevInfo->cache_size = cache_size;
        pVD_DCB->DevInfo->cache =
            (al_uint8 *) ((al_uint8 *) pVD_DCB->DevInfo->pstComTbl + sizeof(Setting_Component_st) * num_comp);
    }

    /* initialize each component */
    for (loop = 0, offset = 0; loop < num_comp; loop++)
    {
        pVD_DCB->DevInfo->pstComTbl[loop].dev_type = (ENVMPurposeID_t)(tech_arr[loop]);
        pVD_DCB->DevInfo->pstComTbl[loop].component_start_address = addr_arr[loop];
        pVD_DCB->DevInfo->pstComTbl[loop].component_size = size_arr[loop];
        pVD_DCB->DevInfo->pstComTbl[loop].component_offset = offset;
        pVD_DCB->DevInfo->pstComTbl[loop].corrupt = al_true;

        SETTING_DEBUG_MESSAGE("Addr 0x%x Size %d offset %d\n", addr_arr[loop], size_arr[loop], offset);

        /* Added Four byte for the CRC32 Value */
        offset += size_arr[loop] + CRC_INFO_SIZE;
    }

    /* Creating Semaphore for User Pref */
    if (GL_SUCCESS != GL_SemaphoreCreate(VD_SEM_NAME, VD_SEM_MAX, VD_SEM_INITIAL, &pVD_DCB->vd_sem_id))
    {
        SETTING_ERROR_MESSAGE("GL_SemaphoreCreate\n");
        free(pVD_DCB->DevInfo);
        pVD_DCB->DevInfo = NULL;
        pVD_DCB->u8Flag = 0;    /* free DCB */
        return INVAILDHANDLE;
    }
    
    AL_Setting_SetDeviceComp(size_arr, addr_arr, tech_arr, num_comp, &g_pDevInfo);

    pstCom = g_pDevInfo.pstComTbl;

#if 0  //temp solution for SIS New System Porting by jun.luo @ 2013/7/2
    for (loop = 0; loop < num_comp; loop++, ++pstCom)
    {
        if (pstCom != al_null)
        {
            NVMRead(pstCom->dev_type, pstCom->component_start_address,
                    pstCom->component_size + CRC_INFO_SIZE, pVD_DCB->DevInfo->cache + pstCom->component_offset);
        }
    }
#else
   INT8 ret = 0;

    for (loop = 1; loop <= g_pDevInfo.num_comp; loop++)
    {
        if (pstCom != al_null && pstCom->component_size > 0)
        {
            ret = Cmd_NVMRead(pstCom->dev_type, TRUE, pstCom->component_size, pVD_DCB->DevInfo->cache + pstCom->component_offset);    
            SETTING_DEBUG_MESSAGE("ret = %d, continue addr:%d, size:%d\n",ret, (al_uint32)(pVD_DCB->DevInfo->cache + pstCom->component_offset), pstCom->component_size);
            ret = ret;//for build error
        }
        
        pstCom = &(g_pDevInfo.pstComTbl[loop]);
    }
#endif
    /* Check CRC Value of the each item */
    if (CRC_INFO_SIZE != 0)
    {
        for (loop = 0; loop < num_comp; loop++)
        {
            offset = pVD_DCB->DevInfo->pstComTbl[loop].component_offset;
            crc_32 = GL_CRC32((pVD_DCB->DevInfo->cache + offset), pVD_DCB->DevInfo->pstComTbl[loop].component_size);

            offset = pVD_DCB->DevInfo->pstComTbl[loop].component_offset +
                pVD_DCB->DevInfo->pstComTbl[loop].component_size;
            stored_crc_32 = (*(pVD_DCB->DevInfo->cache + offset) |
                             *(pVD_DCB->DevInfo->cache + offset + 1) << 8 |
                             *(pVD_DCB->DevInfo->cache + offset + 2) << 16 |
                             *(pVD_DCB->DevInfo->cache + offset + 3) << 24);
            pVD_DCB->DevInfo->pstComTbl[loop].corrupt = al_false;
            if (crc_32 == stored_crc_32)
            {
                pVD_DCB->DevInfo->pstComTbl[loop].corrupt = al_false;
            }
            else
            {
                pVD_DCB->DevInfo->pstComTbl[loop].corrupt = al_true;
            }
        }
    }
    SETTING_DEBUG_MESSAGE("Exit\n");

    return handle;
}

/*****************************************************************************
** FUNCTION : AL_Setting_Close
**
** DESCRIPTION :
**				This method terminates the storage device for user
**				preference component, save all data and releases all
**				resources occpied by the technology
**
** PARAMETERS :
**				handle	- handle Storage device
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_Close(AL_SETTING_HANDLE handle)
{
    VD_DCB_t *pDCB = al_null;

    /* check current state */
    if (VD_INITIALIZED != gVD_State)
    {
        SETTING_ERROR_MESSAGE("un initialized!\n");
        return AL_FAILURE;
    }

    /* check parameter */
    if (INVAILDHANDLE == handle)
    {
        SETTING_ERROR_MESSAGE("invaild hadle!\n");
        return AL_INVALID_PARAM;
    }

    /* get dcb */
    VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
    pDCB = _GetDCB(handle);
    if (al_null == pDCB)
    {
        SETTING_ERROR_MESSAGE("get dcb fail!\n");
        VD_SEM_GIVE(gDCB_SemId);
        return AL_FAILURE;
    }
    VD_SEM_GIVE(gDCB_SemId);

    /* store data to device from cache */
    //AL_Setting_Store(handle, 0xFF);

	VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);
	/* free resource of this virtual device */
	free(pDCB->DevInfo);
	pDCB->DevInfo = al_null;

	//temp solution for SIS New System Porting by jun.luo @ 2013/7/2
	free(pDCB->pTmpBuffer);
	pDCB->pTmpBuffer = al_null;

    if (g_pDevInfo.pstComTbl != NULL)
    {
        free(g_pDevInfo.pstComTbl);
        g_pDevInfo.pstComTbl = NULL;
    }
    memset(&g_pDevInfo, 0, sizeof(VD_Device_Info));

    VD_SEM_GIVE(pDCB->vd_sem_id);

	/* release semaphore of this virtual device */
	GL_SemaphoreDelete(pDCB->vd_sem_id);
	pDCB->vd_sem_id = al_null;

	VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
	pDCB->u8Flag = 0;
	VD_SEM_GIVE(gDCB_SemId);

	return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_Read
**
** DESCRIPTION :
**				This method gets the specific user setting from certail
**				memory cache asked by the component from memory cache
**
** PARAMETERS :
**				handle	- handle of Storage device
**				user_pref_id- Fixed unique Id assigned to each component
**				offset		- Starting byte position from which data is read
**				num_bytes	- No.of bytes required by the component
**				data		- Data asked for by the calling component
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_Read(AL_SETTING_HANDLE handle,
	al_uint8 user_pref_id, al_uint32 offset, al_uint16 num_bytes,
	al_void *data)
{
	VD_DCB_t *pDCB = al_null;
	Setting_Component_st *pComp = al_null;
	al_uint32 start_pos = 0;
	al_bool corrupt;

	/* check current state */
	if (VD_INITIALIZED != gVD_State)
	{
		SETTING_ERROR_MESSAGE("un initialized!\n");
		return AL_FAILURE;
	}

	VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
	/* get dcb of virtual device */
	pDCB = _GetDCB(handle);
	if (al_null == pDCB || 0 == pDCB->u8Flag)
	{
		SETTING_ERROR_MESSAGE("get dcb fail!\n");
		VD_SEM_GIVE(gDCB_SemId);
		return AL_FAILURE;
	}
	VD_SEM_GIVE(gDCB_SemId);

	/* check paraments */
	if ((al_null == data) ||((0xff != user_pref_id) && (user_pref_id >= MAX_NUM_COMP)))
	{
		SETTING_ERROR_MESSAGE("invaild parameters!\n");
		return AL_INVALID_PARAM;
	}

	VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);
	pComp = &pDCB->DevInfo->pstComTbl[user_pref_id];

	if (offset + num_bytes > pComp->component_size)
	{
		SETTING_ERROR_MESSAGE("Size Violation\n");
		VD_SEM_GIVE(pDCB->vd_sem_id);
		return AL_INVALID_PARAM;
	}

	/* read data from cache */
	start_pos = pComp->component_offset + offset;
	corrupt = pComp->corrupt;
	memcpy(data, pDCB->DevInfo->cache + start_pos, num_bytes);
	VD_SEM_GIVE(pDCB->vd_sem_id);
	if (CRC_INFO_SIZE != 0)
	{
		if (corrupt == al_true)
		{
			SETTING_ERROR_MESSAGE("component corrupt!\n");
			return AL_CORRUPTED_MEMORY;
		}
	}
	return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_ReadDefault
**
** DESCRIPTION :
**				This method gets the default user setting to memory cache
**				Notice:when user_pref_id is equal to 0xFF, it represents
**				reading all default items of certain storage device
**
** PARAMETERS :
**				handle	- handle of Storage device
**				user_pref_id- Fixed unique Id assigned to each component
**				data		- Default Data
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_ReadDefault(AL_SETTING_HANDLE handle,
	al_uint8 user_pref_id, const al_void *data)
{
	VD_DCB_t *pDCB = al_null;
	Setting_Component_st *pstComp = al_null;
	al_uint8 loop = 0;
	al_uint16 start_pos = 0;

	SETTING_DEBUG_MESSAGE("Enter...\n");

	/* check current state */
	if (VD_INITIALIZED != gVD_State)
	{
		SETTING_ERROR_MESSAGE("un initialized!\n");
		return AL_FAILURE;
	}

	VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
	/* get dcb of virtual device */
	pDCB = _GetDCB(handle);
	if (al_null == pDCB || 0 == pDCB->u8Flag)
	{
		SETTING_ERROR_MESSAGE("get dcb fail!\n");
		VD_SEM_GIVE(gDCB_SemId);
		return AL_FAILURE;
	}
	VD_SEM_GIVE(gDCB_SemId);

	/* check paraments */
	if ((al_null == data) ||((0xff != user_pref_id) && (user_pref_id >= MAX_NUM_COMP)))
	{
		SETTING_ERROR_MESSAGE("invaild parameters!\n");
		return AL_INVALID_PARAM;
	}

	VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);
	if (user_pref_id != 0xFF)
	{
		pstComp = &(pDCB->DevInfo->pstComTbl[user_pref_id]);
		memcpy(pDCB->DevInfo->cache + pstComp->component_offset, data,
			pstComp->component_size);
		pstComp->corrupt = FALSE;
	}
	else
	{
		pstComp = pDCB->DevInfo->pstComTbl;
		/* Write every default items into memory cache */
		for (loop = 0; loop < pDCB->DevInfo->num_comp; loop++, ++ pstComp)
		{
			memcpy(pDCB->DevInfo->cache + pstComp->component_offset,
				(al_uint8*)data + start_pos, pstComp->component_size);
			pstComp->corrupt = FALSE;
			start_pos += pstComp->component_size;
		}
	}
	VD_SEM_GIVE(pDCB->vd_sem_id);

	SETTING_DEBUG_MESSAGE("Exit\n");
	return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_Write
**
** DESCRIPTION :
**				This method writes the user data into user setting cache
**
** PARAMETERS :
**				handle	- handle of Storage device
**				user_pref_id- Fixed unique Id assigned to each component
**				offset		- Starting position from which data is written
**				num_bytes	- No. of bytes required by the component
**				data		- Data to be written onto cache
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_Write(AL_SETTING_HANDLE handle,
	al_uint8 user_pref_id, al_uint32 offset, al_uint16 num_bytes,
	const al_void *data)
{
	VD_DCB_t *pDCB = al_null;
	Setting_Component_st *pstComp = al_null;
	al_uint32 start_pos = 0;
	//bool corrupt;

	/* check current state */
	if (VD_INITIALIZED != gVD_State)
	{
		SETTING_ERROR_MESSAGE("un initialized!\n");
		return AL_FAILURE;
	}

	VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
	/* get dcb of virtual device */
	pDCB = _GetDCB(handle);
	if (al_null == pDCB || 0 == pDCB->u8Flag)
	{
		SETTING_ERROR_MESSAGE("get dcb fail!\n");
		VD_SEM_GIVE(gDCB_SemId);
		return AL_FAILURE;
	}
	VD_SEM_GIVE(gDCB_SemId);

	/* check parameter */
	if ((al_null == data) ||((0xff != user_pref_id) && (user_pref_id >= MAX_NUM_COMP)))
	{
		SETTING_ERROR_MESSAGE("invaild parameters!\n");
		return AL_INVALID_PARAM;
	}

	VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);
	pstComp = &(pDCB->DevInfo->pstComTbl[user_pref_id]);

	/* check if overflow */
	if ((offset + num_bytes) > pstComp->component_size)
	{
		SETTING_DEBUG_MESSAGE("offset %x, bytes %d, total %d\n",
		offset, num_bytes, pstComp->component_size);
		SETTING_ERROR_MESSAGE("Size Violation\n");
		VD_SEM_GIVE(pDCB->vd_sem_id);
		return AL_FAILURE;
	}

	/* write data to cache */
	start_pos = pstComp->component_offset + offset;
	pstComp->corrupt = al_false;
	memcpy(pDCB->DevInfo->cache + start_pos, data, num_bytes);

	VD_SEM_GIVE(pDCB->vd_sem_id);

	SETTING_DEBUG_MESSAGE("Exit\n");
	return AL_SUCCESS;
}

/*****************************************************************************
** FUNCTION : AL_Setting_Reload
**
** DESCRIPTION :
**				This method retrieves the user setting from actual
**				storage device into memory cache.
**				Notice:when user_pref_id is equal to 0xFF, it represents
**				retrieving all items
**
** PARAMETERS :
**				handle	- handle of Storage device
**				user_pref_id- Fixed unique Id assigned to each component
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_Reload(AL_SETTING_HANDLE handle, al_uint8 user_pref_id)
{
    VD_DCB_t *pDCB = al_null;
    Setting_Component_st *pstComp = al_null;

    al_uint8 loop = 0;

    /* check current state */
    if (VD_INITIALIZED != gVD_State)
    {
        SETTING_ERROR_MESSAGE("un initialized!\n");
        return AL_FAILURE;
    }

    VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
    /* get dcb of virtual device */
    pDCB = _GetDCB(handle);
    if (al_null == pDCB || 0 == pDCB->u8Flag)
    {
        SETTING_ERROR_MESSAGE("get dcb fail!\n");
        VD_SEM_GIVE(gDCB_SemId);
        return AL_FAILURE;
    }
    VD_SEM_GIVE(gDCB_SemId);

    /* check parameter */
    if ((0xff != user_pref_id) && (user_pref_id >= MAX_NUM_COMP))
    {
        SETTING_ERROR_MESSAGE("invaild parameters!\n");
        return AL_INVALID_PARAM;
    }
    pstComp = g_pDevInfo.pstComTbl;
    if (pstComp == NULL)
    {
        SETTING_ERROR_MESSAGE("un initialized device!\n");
        return AL_FAILURE;
    }
    
    VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);

    for (loop = 1; loop <= g_pDevInfo.num_comp; loop++)
    {
        if (pstComp != al_null && pstComp->component_size > 0)
        {
            Cmd_NVMRead(pstComp->dev_type, TRUE, pstComp->component_size, pDCB->DevInfo->cache + pstComp->component_offset);
            SETTING_DEBUG_MESSAGE("Reload: nvmid:%d,start addr:%d,size:%d\n",pstComp->dev_type,(al_uint32)pDCB->DevInfo->cache+pstComp->component_offset, 
            pstComp->component_size);
        }
        pstComp = &(g_pDevInfo.pstComTbl[loop]);
    }
    memset(pDCB->pTmpBuffer, 0, pDCB->DevInfo->cache_size);

    memcpy(pDCB->pTmpBuffer, pDCB->DevInfo->cache, pDCB->DevInfo->cache_size);

    VD_SEM_GIVE(pDCB->vd_sem_id);

    SETTING_DEBUG_MESSAGE("Exit\n");

    return AL_SUCCESS;
}


#if 0
static bool IsCompContinue(VD_Device_Info *p_stDevice)
{
	al_uint8 i = 0;
	Setting_Component_st* pstCom_prev  = al_null;
	Setting_Component_st* pstCom_now   = al_null;

	for (i = 1; i < p_stDevice->num_comp; ++i)
	{
		pstCom_prev = &(p_stDevice->pstComTbl[i-1]);
		pstCom_now  = &(p_stDevice->pstComTbl[i]);

		if ((pstCom_prev->component_start_address
			+ pstCom_prev->component_size + CRC_INFO_SIZE) !=
			pstCom_now->component_start_address)
		{
			return FALSE;
		}
	}
	return al_true;
}
#endif
/*****************************************************************************
** FUNCTION : AL_Setting_Store
**
** DESCRIPTION :
**				This method stores the user setting into actual storage
**				device from memory cache.
**				Notice:when id is equal to 0xFF, it represents
**				to store all items
**
** PARAMETERS :
**				handle	- handle ofStorage device
**				id			- Fixed unique Id assigned to each component
**				item_offset	- component item offset
**				num_bytes	- number of data need to store
**
** RETURN VALUES:
**				AL_SUCCESS
**				AL_FAILURE
**				AL_INVALID_PARAM
*****************************************************************************/
AL_Return_t AL_Setting_Store(AL_SETTING_HANDLE handle,
	al_uint8 user_pref_id, al_uint32 offset, al_uint16 num_bytes)
{
	VD_DCB_t *pDCB = al_null;
	Setting_Component_st* pstCom = al_null;

	SETTING_DEBUG_MESSAGE("Enter\n");
    
#ifdef SUPPORT_FACTORY_AUTO_TEST_MODE4
	/*AutoTest no need to store*/
	{
		UINT8 value = 0;
		extern int AutoTest_NoSaveFlash;
		MID_TVFE_GetSpecialFileStatus(&value);
		if(value == TRUE)
		{
			if((AutoTest_NoSaveFlash == 1)&&(AutoTest_ResetSaveFlash == 1))
			{
				return AL_FAILURE;
			}
		}

		if((AutoTest_NoSaveFlash==0) && (value == TRUE)) // First Power on, need to get default data and save to this flash addr from another flash addr.
		{
			AutoTest_NoSaveFlash = 1;
		}
		
		if((AutoTest_ResetSaveFlash==0) && (value == TRUE)) 
		{
			AutoTest_ResetSaveFlash = 1;
		}
	}
#endif
	

	/* check current state */
	if (VD_INITIALIZED != gVD_State)
	{
		SETTING_ERROR_MESSAGE("un initialized!\n");
		return AL_FAILURE;
	}

	VD_SEM_TAKE(gDCB_SemId, GL_INFINITE_WAIT);
	/* get dcb of virtual device */
	pDCB = _GetDCB(handle);
	if (al_null == pDCB || 0 == pDCB->u8Flag)
	{
		SETTING_ERROR_MESSAGE("get dcb fail!\n");
		VD_SEM_GIVE(gDCB_SemId);
		return AL_FAILURE;
	}
	VD_SEM_GIVE(gDCB_SemId);

    /* check parameter */
    if ((0xff != user_pref_id) && (user_pref_id >= MAX_NUM_COMP))
    {
        SETTING_ERROR_MESSAGE("invaild parameters!\n");
        return AL_INVALID_PARAM;
    }
    
    pstCom = g_pDevInfo.pstComTbl;
    if (pstCom == NULL)
    {
        SETTING_ERROR_MESSAGE("un initialized device!\n");
        return AL_FAILURE;
    }
    VD_SEM_TAKE(pDCB->vd_sem_id, GL_INFINITE_WAIT);

    al_uint8   loop = 0;
    INT8 ret = 0;
    if (0 != memcmp(pDCB->pTmpBuffer, pDCB->DevInfo->cache, pDCB->DevInfo->cache_size))
    {
        for (loop = 1; loop <= g_pDevInfo.num_comp; loop++)
        {
            if (pstCom != al_null && pstCom->component_size > 0)
            {
                ret = Cmd_NVMWrite(pstCom->dev_type, TRUE, pstCom->component_size, pDCB->DevInfo->cache + pstCom->component_offset);
                SETTING_DEBUG_MESSAGE("store, nvmid:%d,addr:%d,size:%d, ret:%d\n",pstCom->dev_type,(al_uint32)(pDCB->DevInfo->cache + pstCom->component_offset),pstCom->component_size,ret);
                ret = ret;//for builde error
            }
            pstCom = &(g_pDevInfo.pstComTbl[loop]);
        }
        memset(pDCB->pTmpBuffer, 0, pDCB->DevInfo->cache_size);
        memcpy(pDCB->pTmpBuffer, pDCB->DevInfo->cache, pDCB->DevInfo->cache_size);
    }

    VD_SEM_GIVE(pDCB->vd_sem_id);

	SETTING_DEBUG_MESSAGE("Exit\n");

	return AL_SUCCESS;
}

/*****************************************************************************
** $Rev: 1900 $
**
*****************************************************************************/
