[Feature][Modem]Update MTK MODEM V1.6 baseline version: MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6

MTK modem version: MT2735_IVT_MOLY.NR15.R3.MD700.IVT.MP1MR3.MP.V1.6.tar.gz
RF  modem version: NA

Change-Id: I45a4c2752fa9d1a618beacd5d40737fb39ab64fb
diff --git a/mcu/driver/drv/src/fota_partial.c b/mcu/driver/drv/src/fota_partial.c
new file mode 100644
index 0000000..c7dd8a8
--- /dev/null
+++ b/mcu/driver/drv/src/fota_partial.c
@@ -0,0 +1,3405 @@
+/*****************************************************************************
+*  Copyright Statement:
+*  --------------------
+*  This software is protected by Copyright and the information contained
+*  herein is confidential. The software may not be copied and the information
+*  contained herein may not be used or disclosed except with the written
+*  permission of MediaTek Inc. (C) 2006
+*
+*  BY OPENING THIS FILE, BUYER HEREBY UNEQUIVOCALLY ACKNOWLEDGES AND AGREES
+*  THAT THE SOFTWARE/FIRMWARE AND ITS DOCUMENTATIONS ("MEDIATEK SOFTWARE")
+*  RECEIVED FROM MEDIATEK AND/OR ITS REPRESENTATIVES ARE PROVIDED TO BUYER ON
+*  AN "AS-IS" BASIS ONLY. MEDIATEK EXPRESSLY DISCLAIMS ANY AND ALL WARRANTIES,
+*  EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE IMPLIED WARRANTIES OF
+*  MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE OR NONINFRINGEMENT.
+*  NEITHER DOES MEDIATEK PROVIDE ANY WARRANTY WHATSOEVER WITH RESPECT TO THE
+*  SOFTWARE OF ANY THIRD PARTY WHICH MAY BE USED BY, INCORPORATED IN, OR
+*  SUPPLIED WITH THE MEDIATEK SOFTWARE, AND BUYER AGREES TO LOOK ONLY TO SUCH
+*  THIRD PARTY FOR ANY WARRANTY CLAIM RELATING THERETO. MEDIATEK SHALL ALSO
+*  NOT BE RESPONSIBLE FOR ANY MEDIATEK SOFTWARE RELEASES MADE TO BUYER'S
+*  SPECIFICATION OR TO CONFORM TO A PARTICULAR STANDARD OR OPEN FORUM.
+*
+*  BUYER'S SOLE AND EXCLUSIVE REMEDY AND MEDIATEK'S ENTIRE AND CUMULATIVE
+*  LIABILITY WITH RESPECT TO THE MEDIATEK SOFTWARE RELEASED HEREUNDER WILL BE,
+*  AT MEDIATEK'S OPTION, TO REVISE OR REPLACE THE MEDIATEK SOFTWARE AT ISSUE,
+*  OR REFUND ANY SOFTWARE LICENSE FEES OR SERVICE CHARGE PAID BY BUYER TO
+*  MEDIATEK FOR SUCH MEDIATEK SOFTWARE AT ISSUE. 
+*
+*  THE TRANSACTION CONTEMPLATED HEREUNDER SHALL BE CONSTRUED IN ACCORDANCE
+*  WITH THE LAWS OF THE STATE OF CALIFORNIA, USA, EXCLUDING ITS CONFLICT OF
+*  LAWS PRINCIPLES.  ANY DISPUTES, CONTROVERSIES OR CLAIMS ARISING THEREOF AND
+*  RELATED THERETO SHALL BE SETTLED BY ARBITRATION IN SAN FRANCISCO, CA, UNDER
+*  THE RULES OF THE INTERNATIONAL CHAMBER OF COMMERCE (ICC).
+*
+*****************************************************************************/
+
+/*****************************************************************************
+ *
+ * Filename:
+ * ---------
+ *   fota_partial.c
+ *
+ * Project:
+ * --------
+ *   Maui_Software
+ *
+ * Description:
+ * ------------
+ *   This file implement the function of FOTA firmware update downlaod 
+ *
+ * Author:
+ * -------
+ * -------
+ *
+ *============================================================================
+ *             HISTORY
+ * Below this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *------------------------------------------------------------------------------
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ * removed!
+ * removed!
+ * removed!
+ *
+ *------------------------------------------------------------------------------
+ * Upper this line, this part is controlled by PVCS VM. DO NOT MODIFY!!
+ *============================================================================
+ ****************************************************************************/
+/*******************************************
+*   Include File      
+********************************************/
+#if defined(__FOTA_DM__)
+
+#include "kal_general_types.h"
+#include "kal_debug.h"
+#include <stdio.h>
+#include <stdarg.h>
+#include "fue_err.h"
+#include "fota.h"
+#include "flash_opt.h"
+#include "fat_fs.h"
+#include "custom_fota.h"
+#include "custom_img_config.h"
+#include "fue.h"
+#include "ssf_fue_support.h"
+#include "fue_update_support.h"
+#if defined(__MAUI_BASIC__)
+#include "uart_sw.h"
+#endif /* __MAUI_BASIC__ */
+#if defined(__HP_FOTA__)
+#include "Bitfone_update.h"
+#endif
+
+#include "dcl.h"
+
+#ifdef __EMMC_BOOTING__
+#include "fue_emmc_adapt.h"
+#endif
+
+#define _FUE_PKG_DEBUG_
+
+/*******************************************************************************
+ *   Global Function and Structure Definition
+ *******************************************************************************/
+
+FOTA_DATA FOTAData={STATUS_FOTA_NOT_INITIAL};
+
+FOTA_NFB_Update_Control    FOTA_Update_Ctrl;
+FOTA_Package_Control_st    FOTA_Package_Ctrl;
+
+#pragma arm section zidata = "NONCACHEDZI"
+
+kal_uint32  fota_temp_page_buffer[FOTA_FLASH_MAX_PAGE_SIZE];
+kal_uint32  fota_replace_page_buffer[FOTA_FLASH_MAX_PAGE_SIZE];
+
+#pragma arm section zidata
+
+/*******************************************************************************
+ *   Static Function and Structure Definition
+ *******************************************************************************/
+static kal_int32 FOTA_MTD_Read_Buffer(void *Buffer, kal_uint32 read_len);
+
+/* start address of update package reserved area */
+extern const kal_uint32 FOTA_PACKAGE_BASE_ADDRESS;
+
+/* Following functions and data varoables are located in FOTA library */
+extern FUE_ERROR_CODE FUE_InitializeUpdateRecord(kal_uint32 base_blk, kal_uint32 end_blk, \
+                                                 Flash_GAL_st *fgal, dbg_trace_func dbg_trace);
+extern FUE_ERROR_CODE FUE_NFB_Flush_Update_Record(FOTA_Custom_Update_Info* info_buffer, \
+                                                  dbg_trace_func dbg_trace);
+extern FUE_ERROR_CODE FUE_NFB_Get_Update_Record(FOTA_Custom_Update_Info* info_buffer,\
+                                                dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_NFB_Allocate_Block(kal_uint32 begin_block, kal_uint32 end_block, \
+                                             kal_uint32 curr_block, kal_uint32 *alloc_block, \
+                                             Flash_GAL_st *fgal, IsBlockAvailable_func check_available, \
+                                             dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_BlkInfo_Resume_Package_Blocks(FOTA_Package_Control_st *pkg_ctrl, \
+                                                        kal_uint32 *found_blocks, \
+                                                        /*FOTA_Package_Location_st *found_list, \*/
+                                                        FOTA_Package_List_st *found_list,\
+                                                        kal_uint32 *buff_ptr, \
+                                                        kal_uint32 *buff_len, \
+                                                        /*alloc_pkg_blk alloc_blk, \*/
+                                                        dbg_trace_func dbg_trace);
+
+extern kal_bool FUE_NFB_Is_Available_Block(kal_uint32 block_idx, kal_uint32* buff_ptr, Flash_GAL_st *fgal, \
+                                           dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_NFB_Replace_Current_Package_Block(FOTA_Package_Control_st *pkg_ctrl,\
+                                                            kal_uint32 *buff_ptr, \
+                                                            dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_NFB_Mark_Package_Block_Complete(FOTA_Package_Control_st *pkg_ctrl, \
+                                                          FOTA_Package_Info_st *pkg_info, dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_NFB_Allocate_PackageBlock(FOTA_Package_Control_st *pkg_ctrl, kal_uint32 start_block, \
+                                                    kal_uint32 *alloc_block, dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_NFB_Create_Package_Block(FOTA_Package_Control_st *pkg_ctrl, kal_uint32 block_index,\
+                                                   kal_uint32 last_block, kal_uint32 replace_block, \
+                                                   kal_bool add_session, dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_CreateInitialUpdateRecord(FOTA_NFB_Update_Control *update_ctrl, kal_uint32 start_block, \
+                                                    Flash_GAL_st *fgal, dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_BlkInfo_Is_Package_Block(FOTA_Package_Control_st *pkg_ctrl, kal_uint32 blk_num, dbg_trace_func dbg_trace);
+
+extern FUE_ERROR_CODE FUE_BlkInfo_Is_Update_Block(FOTA_NFB_Update_Control *update_ctrl, kal_uint32 blk_num, dbg_trace_func dbg_trace);
+
+extern kal_uint32 SSF_GetMAUIImageNumber(void);
+
+extern void FUE_Start_Download_State(void);
+
+extern void FUE_Start_Package_Verification_State(void);
+
+extern FOTA_Area_Info_Wrapper_st  FOTA_NFB_Area_Info;
+
+/* For update package block management */
+extern FOTA_Package_List_st g_fota_package_blocks[FOTA_PACKAGE_BLOCK_NUMBER];
+extern kal_uint32 FOTA_PKG_BLOCKS;
+
+/* Following functions are located in init.c */
+extern kal_uint32 INT_GetCurrentTime(void);
+
+
+/* the NFI access synchronization is implemented in NAND flash MTD layer */
+#define FOTA_LOCK()   
+#define FOTA_UNLOCK() 
+
+/* Forward declaration */
+Flash_GAL_st *FOTA_Setup_FGAL(void);
+static kal_int32 FOTA_MTD_Program_Buffer(void *Buffer, kal_uint32 write_len);
+
+kal_int32 FOTA_InitializeUpdateRecord(void);
+
+kal_int32 FOTA_InitializePackageReservoir(void);
+kal_int32 FOTA_FinishPackageBlock(void);
+kal_int32 FOTA_CheckAvailablePackageBlocks(kal_uint32 *available_num);
+kal_int32 FOTA_ClearPackageReservoir(void);
+kal_int32 FOTA_Get_TotalPackageBlock(kal_uint32 *pkg_blks, kal_uint32* pkg_pages);
+kal_int32 FOTA_Get_CurrentPackagePosition(kal_uint32 *curr_blks, kal_uint32* curr_pages);
+kal_int32 FOTA_ProgramPackagePage(void* buff, kal_uint32 *page_size);
+
+kal_int32 FOTA_GetPackageFlashInfo(kal_uint32 *blk_size, kal_uint32 *page_size);
+
+#if defined(__MAUI_BASIC__)
+
+
+#endif /*  __MAUI_BASIC__ */
+/*****************************************************************
+Description : dump trace via kal_print function.
+Input       : 
+Output      : None
+******************************************************************/
+kal_char  g_char_buff[512];
+void fue_dbg_print(kal_char* fmt, ...)
+{
+   va_list trace_p;
+   va_start(trace_p, fmt);
+   vsprintf(g_char_buff, fmt, trace_p);
+   va_end(trace_p);
+   kal_print(g_char_buff);
+#if defined(__MAUI_BASIC__)
+   if(KAL_FALSE == kal_query_systemInit())
+   {
+       while(!UART_CheckTxBufferEmpty(uart_port1)); /* wait for UART dump complete */
+   }
+#endif
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Package_Blk_Address
+DESCRIPTION
+   convert to block aligned address
+PARAMETER
+   NULL
+RETURN
+   INVALOD_DWORD : out of range
+--------------------------------------------------------------------------------- */
+kal_uint32 FOTA_Package_Blk_Address(FOTA_Package_Control_st *pkg_ctrl, kal_uint32 dst_addr)
+{
+   Logical_Flash_info_st  info;
+   kal_uint32             blk_idx      = 0;
+   kal_uint32             blk_addr     = 0;
+   kal_uint32             phy_blk      = 0;
+   kal_uint32             curr_blk_num = pkg_ctrl->m_fota_pkg_blocks;
+   Flash_GAL_st           *fgal        = pkg_ctrl->m_pkg_fgal;
+
+   ASSERT(fgal);
+
+   fgal->query_info(&info);
+   for(blk_idx = 0 ; blk_idx < curr_blk_num ; blk_idx++)
+   {
+      phy_blk = pkg_ctrl->m_fota_pkg_list[blk_idx].m_pkg_block_position;
+      blk_addr += (fgal->block_size(phy_blk)- 2*info.Flash_page_size);
+      if(blk_addr >= dst_addr)
+         break;
+   }
+   if( blk_idx == curr_blk_num )
+   {
+      fue_dbg_print("FOTA_Package_Blk_Idx: address:0x%x is beyond available %dblks!\n\r",
+                     dst_addr, curr_blk_num);
+      ASSERT(0);
+      return INVALID_DWORD;
+   }
+   else
+   {
+      if(blk_addr == dst_addr)
+         fue_dbg_print("FOTA_Package_Blk_Idx: address:0x%x is on the bounadry of blk:%d(%d)!\n\r",
+                        dst_addr, blk_idx, phy_blk);
+
+      return blk_addr;
+   }
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Initialize
+DESCRIPTION
+   FOTA Initialization API
+   1. Initialize data structure and progress initial step
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Initialize(void)
+{
+   kal_int32              Ret;
+
+   if( STATUS_FOTA_INITIALIZED == FOTAData.Status )
+   {
+      return ERROR_FOTA_SUCCESS;
+   }
+
+   Ret = FOTA_InitializeUpdateRecord();
+   if( (ERROR_FOTA_NO_AVAILABLE_BLOCK == Ret) || (ERROR_FUE_OPERATION_STOP == Ret) ||
+       (ERROR_FUE_OVER_DESIGN == Ret) )
+      return Ret;
+   
+   Ret = FOTA_InitializePackageReservoir();
+
+   if(ERROR_FOTA_INVALID_PARAMETER == Ret)
+   {
+      return Ret;
+   }
+   fue_dbg_print("FOTA_Initialize: %d updatable images!\n\r", SSF_GetMAUIImageNumber());
+
+   FOTAData.SpareCurrWriteAddr = 0; 
+   FOTAData.SpareNextWriteBlockAddr = 0;
+   FOTAData.SpareCurrReadAddr = 0; 
+   FOTAData.SpareNextReadBlockAddr = 0;
+   FOTAData.BufferIndex = 0;
+   
+   if((Ret = FOTA_CustomInitialize()) < 0)
+      return Ret;
+   else
+      FOTAData.Status = STATUS_FOTA_INITIALIZED;
+   return ERROR_FOTA_SUCCESS;   
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_WriteData
+DESCRIPTION
+   FOTA write data API
+   1. This function is used to write data to spare image pool
+   2. This API only allow sequentially writing mechanism
+   3. Authentication mechanism is executed during writing
+PARAMETER
+   Length: the length of writing (Unit: Bytes)
+   Buffer: the start address of buffer
+RETURN
+   0: means pass write success (ERROR_FOTA_SUCCESS)
+   < 0: writing action is fail
+      ERROR_FOTA_AUTH_ROMINFO: authentication fail, can't find rom info
+      ERROR_FOTA_AUTH_FATBEGIN: authentication fail, fat begin address is different
+      ERROR_FOTA_AUTH_FATLEN: authentication fail, fat length is different
+      ERROR_FOTA_AUTH_HCHECKSUM: authentication fail, header checksum fail
+      ERROR_FOTA_AUTH_ID: authentication fail, platform id is different
+      ERROR_FOTA_AUTH_VERSION: authentication fail, downgrade is not allowed
+      ERROR_FOTA_AUTH_IMAGELEN: authentication fail, image length too large
+	 ERROR_FOTA_AUTH_FAIL: authentication fail before
+	 ERROR_FOTA_OVERRANGE: write over the spare image pool range
+	 ERROR_FOTA_NOT_INITIALIZED: not call FOTA_Initialize before
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_WriteData(kal_uint32 Length, void* Buffer)
+{
+   kal_int32  result;
+   kal_uint32 buff_addr = (kal_uint32)Buffer;
+   kal_uint8  *byte_ptr = NULL;
+
+   if (FOTAData.Status == STATUS_FOTA_NOT_INITIAL)
+      return ERROR_FOTA_NOT_INITIALIZED;
+
+   while(Length > 0)
+   {
+      if ((FOTAData.BufferIndex+Length)>=FOTA_BUFFER_SIZE)
+      {
+         /* no data in write buffer and user buffer is 4-byte aligned */
+         if( (FOTAData.BufferIndex == 0) && (0 == (buff_addr & 0x03)) ) 
+         {
+            result = FOTA_MTD_Program_Buffer((void*)buff_addr, FOTA_BUFFER_SIZE);
+         	  if (result < 0)
+               return result;
+            buff_addr += FOTA_BUFFER_SIZE;
+            Length -= FOTA_BUFFER_SIZE;
+         }
+         else
+         {
+            if(FOTAData.BufferIndex != FOTA_BUFFER_SIZE)
+            {
+               byte_ptr = (kal_uint8 *)(((kal_uint32)FOTAData.FOTAWriteBuffer) + FOTAData.BufferIndex);
+               //kal_mem_cpy((void*)&FOTAData.FOTABuffer[FOTAData.BufferIndex>>2], Buffer, FOTA_BUFFER_SIZE - FOTAData.BufferIndex);
+               kal_mem_cpy(byte_ptr, (void *)buff_addr, FOTA_BUFFER_SIZE - FOTAData.BufferIndex);
+               buff_addr += (FOTA_BUFFER_SIZE - FOTAData.BufferIndex);
+               Length -= (FOTA_BUFFER_SIZE - FOTAData.BufferIndex);
+               FOTAData.BufferIndex = FOTA_BUFFER_SIZE;
+            }
+            result = FOTA_MTD_Program_Buffer((void*)FOTAData.FOTAWriteBuffer, FOTA_BUFFER_SIZE);
+            if (result < 0)
+               return result;
+            FOTAData.BufferIndex = 0;
+         }
+      }
+      else
+      {
+         byte_ptr = (kal_uint8 *)(((kal_uint32)FOTAData.FOTAWriteBuffer) + FOTAData.BufferIndex);
+         //kal_mem_cpy((void*)&FOTAData.FOTABuffer[FOTAData.BufferIndex/4], Buffer, Length);
+         kal_mem_cpy(byte_ptr, (void *)buff_addr, Length);
+         FOTAData.BufferIndex += Length;
+         buff_addr += Length;
+         Length = 0;
+      }
+   }
+   return ERROR_FOTA_SUCCESS;   
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ReadData
+DESCRIPTION
+   FOTA read data API
+   1. This function is used to read data from spare image pool
+   2. This API only support sequentially read operation, i.e. from low address to high address
+PARAMETER
+   Length: the length of reading (Unit: Bytes)
+   Buffer: the start address of buffer
+RETURN
+   0: means pass write success (ERROR_FOTA_SUCCESS)
+   < 0: writing action is fail
+      ERROR_FOTA_AUTH_ROMINFO: authentication fail, can't find rom info
+      ERROR_FOTA_AUTH_FATBEGIN: authentication fail, fat begin address is different
+      ERROR_FOTA_AUTH_FATLEN: authentication fail, fat length is different
+      ERROR_FOTA_AUTH_HCHECKSUM: authentication fail, header checksum fail
+      ERROR_FOTA_AUTH_ID: authentication fail, platform id is different
+      ERROR_FOTA_AUTH_VERSION: authentication fail, downgrade is not allowed
+      ERROR_FOTA_AUTH_IMAGELEN: authentication fail, image length too large
+	 ERROR_FOTA_AUTH_FAIL: authentication fail before
+	 ERROR_FOTA_OVERRANGE: write over the spare image pool range
+	 ERROR_FOTA_NOT_INITIALIZED: not call FOTA_Initialize before
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ReadData(kal_uint32 Length, void* Buffer)
+{
+   kal_int32  result      = ERROR_FOTA_SUCCESS;
+   kal_uint32 buffer_addr = (kal_uint32)Buffer;
+   kal_uint32 read_len    = 0;
+   kal_uint32 copy_size   = 0;
+
+   if (FOTAData.Status == STATUS_FOTA_NOT_INITIAL)
+      return ERROR_FOTA_NOT_INITIALIZED;
+
+   while(Length > read_len)
+   {
+      if( ( (Length-read_len) >= FOTA_BUFFER_SIZE) && (0 == ((buffer_addr)&0x03)) )
+      {
+         /* directly read into user's buffer */
+         result = FOTA_MTD_Read_Buffer((void*)buffer_addr, FOTA_BUFFER_SIZE);
+         if(result < 0)
+            break;
+         buffer_addr += FOTA_BUFFER_SIZE;
+         read_len    += FOTA_BUFFER_SIZE;
+      }
+      else
+      {
+         if( (Length-read_len) >= FOTA_BUFFER_SIZE)
+            copy_size = FOTA_BUFFER_SIZE;
+         else
+            copy_size = (Length-read_len);
+
+         /* read into temporary buffer */
+         result = FOTA_MTD_Read_Buffer(FOTAData.FOTAReadBuffer, copy_size);
+         if (result < 0)
+            break;
+
+         kal_mem_cpy((void *)buffer_addr, FOTAData.FOTAReadBuffer, copy_size);
+         buffer_addr += copy_size;
+         read_len    += copy_size;
+      }
+   }
+
+   return result;   
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Finalize
+DESCRIPTION
+   FOTA finalization API
+   1. compare calculated checksum with image checksum in the header after 
+       whole image is written 
+   2. mark the status to UPDATE_NEEDED 
+PARAMETER
+   void
+RETURN
+   0: means pass error check step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_AUTH_FAIL: authentication fail, final step is not allowed
+      ERROR_FOTA_IMAGE_CHECKSUM: image checksum error
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Finalize(void)
+{
+   kal_int32  result = 0;
+
+   if (FOTAData.Status == STATUS_FOTA_NOT_INITIAL)
+      return ERROR_FOTA_NOT_INITIALIZED;
+
+   if(FOTAData.BufferIndex != 0)
+   {
+      result = FOTA_MTD_Program_Buffer((void*)FOTAData.FOTAWriteBuffer, FOTAData.BufferIndex);
+      FOTA_FinishPackageBlock();
+      if (result < 0)
+         return result;
+      FOTAData.BufferIndex = 0;
+   }
+
+   FOTAData.Status = STATUS_FOTA_FINAL;
+
+   return ERROR_FOTA_SUCCESS;
+}
+
+/* --------------------------------------------------------------------------------- *
+ * Flash device wrapper functions
+ * --------------------------------------------------------------------------------- */
+
+/************************************************************************************
+ * NAND flash part
+ *************************************************************************************/
+static kal_int32 FOTA_MTD_Program_Buffer(void *Buffer, kal_uint32 write_len)
+{
+   kal_uint32 buff_offset = 0;
+   kal_int32 left_length = write_len;
+   kal_uint32 page_size = 0;
+   kal_int32  ret_code = ERROR_FOTA_SUCCESS;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   while(left_length > 0)
+   {
+      ret_code = FOTA_ProgramPackagePage((void*)(((kal_uint32)Buffer)+buff_offset), &page_size);
+      if(ERROR_FOTA_SUCCESS == ret_code)
+      {
+         buff_offset += page_size;
+         left_length -= page_size;
+         FOTAData.SpareCurrWriteAddr += page_size;
+      }
+      else if( (ERROR_FOTA_NO_AVAILABLE_BLOCK == ret_code) || (ERROR_FOTA_FLASH_DEVICE==ret_code) ||
+              (ERROR_FOTA_UNSUPPORTED_CASES == ret_code) )
+      {
+         break;
+      }
+   }
+   return ret_code;
+
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_FinishePackageBlock
+DESCRIPTION
+   download is finished, complete current package block
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+        ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_FinishPackageBlock(void)
+{
+   kal_uint32               page_per_blk = 0;
+   FOTA_Package_Info_st     *pkg_info    = NULL;
+   kal_int32                ret_code     = ERROR_FOTA_SUCCESS;
+   FUE_ERROR_CODE           result       = ERROR_FUE_NONE;
+   Logical_Flash_info_st     info;
+   Flash_GAL_st              *fgal       = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+   ASSERT(fgal);
+   pkg_info = &FOTA_Package_Ctrl.m_fota_pkg_info;;
+   //page_per_blk = 1 << FOTA_Package_Ctrl.m_fota_flash_info.Flash_offset_shift;
+   fgal->query_info(&info);
+   page_per_blk = fgal->block_size(pkg_info->m_pkg_current_block)/info.Flash_page_size;
+
+   if(pkg_info->m_pkg_current_page == page_per_blk)
+   {
+      /* current package has been marked as complete in last package program operation */
+      if( pkg_info->m_pkg_valid_pages == (page_per_blk-3))
+      {
+         fue_dbg_print("FOTA_FinishPackageBlock: mark blk:%d as complete is already done!\n\r",\
+                        pkg_info->m_pkg_current_block);
+      }
+      #ifdef _FUE_PKG_DEBUG_
+      else
+      {
+         fue_dbg_print("FOTA_FinishPackageBlock: incomplete blk:%d has been marked complete already!\n\r",\
+                        pkg_info->m_pkg_current_block);
+         #if defined(__FOTA_DEBUG_ASSERT__)
+         ASSERT(0);
+         #endif /* __FOTA_DEBUG_ASSERT__ */
+      }
+      #endif /* _FUE_PKG_DEBUG_ */
+
+      /* indicate current package download is done */
+      FOTA_Package_Ctrl.m_fota_pkg_index = INVALID_DWORD;
+   }
+   else
+   {
+      while(1)
+      {
+         /* mark this package block as complete */
+         result = FUE_NFB_Mark_Package_Block_Complete(&FOTA_Package_Ctrl, pkg_info, fue_dbg_print);
+         if(ERROR_FUE_NONE == result)
+         {
+            fue_dbg_print("FOTA_FinishPackageBlock: mark blk:%d as complete done!\n\r",\
+                           pkg_info->m_pkg_current_block);
+            /* indicate current package download is done */
+            FOTA_Package_Ctrl.m_fota_pkg_index = INVALID_DWORD;
+            break;
+         }
+         else if(ERROR_FUE_PROGRAM_FAILED == result)
+         {
+            /* block replacement procedure - caused by marking complete function */
+            result = FUE_NFB_Replace_Current_Package_Block(&FOTA_Package_Ctrl, fota_replace_page_buffer, \
+                                                           fue_dbg_print);
+            if( ERROR_FUE_OVER_DESIGN == result )
+            {
+               ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+               break;
+            }
+            else if( ERROR_FUE_NO_AVAILABLE_BLOCK == result )
+            {
+               ret_code = ERROR_FOTA_NO_AVAILABLE_BLOCK;
+               break;
+            }
+            else if(ERROR_FUE_NOT_INITIALIZED == result)
+            {
+               ret_code = ERROR_FOTA_NOT_INITIALIZED;
+               break;
+            }
+         }
+         else
+         {
+            /* unexpected status, abort current update package */
+            fue_dbg_print("FOTA_FinishPackageBlock: unexpected error on blk:%d, Abort!!\n\r",\
+                           pkg_info->m_pkg_current_block);
+            break;
+         }
+      }
+   }
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ProgramPackagePage
+DESCRIPTION
+   clear downloaded update package
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+        ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ProgramPackagePage(void* buff, kal_uint32 *page_size)
+{
+   kal_int32            ret_code     = ERROR_FOTA_SUCCESS;
+   kal_uint32           page_per_blk = 0;
+   kal_uint32           curr_blk     = INVALID_DWORD;
+   kal_uint32           curr_order   = INVALID_DWORD;
+   kal_uint32           alloc_block  = INVALID_DWORD;
+   FOTA_Package_Info_st *pkg_info    = NULL;
+   Logical_Flash_info_st     info;
+   Flash_GAL_st          *fgal       = FOTA_Package_Ctrl.m_pkg_fgal;
+   _FGAL_ERROR_CODE     status       = ERROR_FGAL_NONE;
+   FUE_ERROR_CODE       result       = ERROR_FUE_NONE;
+   kal_bool             op_done      = KAL_FALSE;
+   
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+   ASSERT(fgal);
+
+   pkg_info     = &FOTA_Package_Ctrl.m_fota_pkg_info;
+   fgal         = FOTA_Package_Ctrl.m_pkg_fgal;
+   //page_per_blk = 1 << FOTA_Package_Ctrl.m_fota_flash_info.Flash_offset_shift;
+   fgal->query_info(&info);
+   *page_size   = 0;
+
+   if( INVALID_DWORD != pkg_info->m_pkg_current_block )
+   {
+      page_per_blk = fgal->block_size(pkg_info->m_pkg_current_block)/info.Flash_page_size;
+      if( pkg_info->m_pkg_current_page < (page_per_blk-1) )
+      {
+         do
+         {
+            if(pkg_info->m_pkg_current_page == (page_per_blk-2))
+            {
+               /* mark current package block as complete */
+               result = FUE_NFB_Mark_Package_Block_Complete(&FOTA_Package_Ctrl, pkg_info, fue_dbg_print);
+               if(ERROR_FUE_NONE == result)
+               {
+                  break;
+               }
+            }
+            else if(0 == *page_size)
+            {
+               status = fgal->write_page(buff, pkg_info->m_pkg_current_block, pkg_info->m_pkg_current_page);
+               if(ERROR_FGAL_NONE == status)
+               {
+                  pkg_info->m_pkg_current_page++;
+                  pkg_info->m_pkg_valid_pages++;
+                  FOTA_Package_Ctrl.m_fota_pkg_pages++;
+                  *page_size = info.Flash_page_size;
+                  op_done = KAL_TRUE;
+               }
+               else if(ERROR_FGAL_OPERATION_RETRY == status)
+               {
+                  ret_code = ERROR_FOTA_FLASH_DEVICE;
+                  break;
+               }
+            }
+            else
+            {
+               /* package page program done */
+               break;
+            }
+
+            if( (ERROR_FGAL_WRITE_FAILURE == status) || (ERROR_FUE_PROGRAM_FAILED == result) )
+            {
+               /* copy valid pages in bad block to new package block */
+               result = FUE_NFB_Replace_Current_Package_Block(&FOTA_Package_Ctrl, fota_replace_page_buffer, \
+                                                              fue_dbg_print);
+               if( ERROR_FUE_OVER_DESIGN == result )
+               {
+                  ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+                  break;
+               }
+               else if( ERROR_FUE_NO_AVAILABLE_BLOCK == result )
+               {
+                  ret_code = ERROR_FOTA_NO_AVAILABLE_BLOCK;
+                  break;
+               }
+               else if( ERROR_FUE_NOT_INITIALIZED == result )
+               {
+                  ret_code = ERROR_FOTA_NOT_INITIALIZED;
+                  break;
+               }
+            }
+         }while(1);
+      }
+   }
+   /* 
+    * else start to allocate new package block 
+    */
+
+   if(!op_done)
+   {
+      if(INVALID_DWORD == pkg_info->m_pkg_current_block)
+      {
+         ASSERT(INVALID_DWORD == FOTA_Package_Ctrl.m_fota_pkg_index);
+         ASSERT(INVALID_DWORD == pkg_info->m_pkg_block_session);
+         curr_blk = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base;
+         curr_order = INVALID_DWORD;
+      }
+      else
+      {
+         ASSERT(INVALID_DWORD != FOTA_Package_Ctrl.m_fota_pkg_index);
+         curr_blk = pkg_info->m_pkg_current_block;
+         curr_order = FOTA_Package_Ctrl.m_fota_pkg_list[FOTA_Package_Ctrl.m_fota_pkg_index].m_pkg_block_order;
+         FOTA_Package_Ctrl.m_fota_pkg_list[FOTA_Package_Ctrl.m_fota_pkg_index].m_pkg_valid_pages = 
+                                           pkg_info->m_pkg_valid_pages;
+         FOTA_Package_Ctrl.m_fota_pkg_list[FOTA_Package_Ctrl.m_fota_pkg_index].m_pkg_block_complete = 
+                                           KAL_TRUE;
+      }
+      while(1)
+      {
+         /* allocate new package block */
+         result = FUE_NFB_Allocate_PackageBlock(&FOTA_Package_Ctrl, curr_blk, &alloc_block, fue_dbg_print);
+         if(ERROR_FUE_NONE == result)
+         {
+            status = fgal->erase_block(alloc_block);
+            if(ERROR_FGAL_ERASE_FAILURE == status)
+            {
+               fgal->mark_bad(alloc_block);
+               curr_blk = alloc_block;
+               continue;
+            }
+            else if(ERROR_FGAL_NONE != status)
+            {
+               fue_dbg_print("FOTA_ProgramPackagePage: erase operation on block:%d error!\n\r", \
+                              alloc_block);
+               ret_code = ERROR_FOTA_FLASH_DEVICE;
+               break;
+            }
+            /* create package block */
+            result = FUE_NFB_Create_Package_Block(&FOTA_Package_Ctrl, alloc_block, \
+                                                  pkg_info->m_pkg_current_block,\
+                                                  INVALID_DWORD, KAL_TRUE, fue_dbg_print);
+            if( (ERROR_FUE_INSUFFICIENT_BUFFER == result) || (ERROR_FUE_INVALID_PARAMETER == result) )
+            {
+               ret_code = ERROR_FOTA_INVALID_PARAMETER;
+               break;
+            }
+            else if(ERROR_FUE_NONE == result)
+            {
+               status = fgal->write_page(buff, alloc_block, 1);
+               if(ERROR_FGAL_NONE == status)
+               {
+                  /* program done, update RAM copy information */
+                  FOTA_Package_Ctrl.m_fota_pkg_index++;
+                  FOTA_Package_Ctrl.m_fota_pkg_pages++;
+                  FOTA_Package_Ctrl.m_fota_pkg_list[FOTA_Package_Ctrl.m_fota_pkg_index].m_pkg_block_position = 
+                  alloc_block;
+                  FOTA_Package_Ctrl.m_fota_pkg_list[FOTA_Package_Ctrl.m_fota_pkg_index].m_pkg_block_order = 
+                  curr_order+1;
+
+                  pkg_info->m_pkg_previous_block = pkg_info->m_pkg_current_block;
+                  pkg_info->m_pkg_current_block = alloc_block;
+                  pkg_info->m_pkg_current_page = 2;
+                  pkg_info->m_pkg_valid_pages = 1;
+                  pkg_info->m_pkg_block_session++;
+                  *page_size = info.Flash_page_size;
+
+                  fue_dbg_print("FOTA_ProgramPackagePage: program on new package block:%d done!\n\r", \
+                                 pkg_info->m_pkg_current_block);
+                  break;
+               }
+            }
+            //else if(ERROR_FUE_PROGRAM_FAILED == result)
+            if( (ERROR_FUE_PROGRAM_FAILED == result) || (ERROR_FGAL_WRITE_FAILURE == status) )
+            {
+               /* create package block or program new page failed - try again */
+               fgal->erase_block(alloc_block);
+               fgal->mark_bad(alloc_block);
+               curr_blk = alloc_block;
+               continue;
+            }
+            else if(ERROR_FUE_OPERATION_STOP == result)
+            {
+               ret_code = ERROR_FOTA_FLASH_DEVICE;
+               break;
+            }
+            else if(ERROR_FUE_OVER_DESIGN == result)
+            {
+               ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+               break;
+            }
+         }
+         else if(ERROR_FUE_NO_AVAILABLE_BLOCK == result)
+         {
+            ret_code = ERROR_FOTA_NO_AVAILABLE_BLOCK;
+            break;
+         }
+      }
+   }
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ReadPackagePage
+DESCRIPTION
+   clear downloaded update package
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+        ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ReadPackagePage(void* buff, kal_uint32 page_addr, kal_uint32 *page_size)
+{
+   kal_int32            ret_code     = ERROR_FOTA_SUCCESS;
+   kal_uint32           page_count   = 0;
+   kal_int32            left_pages   = 0;
+   kal_uint32           blk_idx      = 0;
+   kal_uint32           page_idx     = 0;
+   kal_uint32           phy_blk      = 0;
+   FOTA_Package_Info_st *pkg_info    = NULL;
+   Logical_Flash_info_st info;
+   FOTA_Package_Access_st *pkg_read  = &FOTA_Package_Ctrl.m_fota_curr_read;
+   Flash_GAL_st          *fgal       = FOTA_Package_Ctrl.m_pkg_fgal;
+   _FGAL_ERROR_CODE     status       = ERROR_FGAL_NONE;
+   
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+   ASSERT(fgal);
+   *page_size = 0;
+
+   fgal     = FOTA_Package_Ctrl.m_pkg_fgal;
+   pkg_info = &FOTA_Package_Ctrl.m_fota_pkg_info;
+   fgal->query_info(&info);
+   if( ((pkg_read->m_pkg_curr_addr+info.Flash_page_size) != page_addr) || (INVALID_DWORD == pkg_read->m_pkg_curr_addr))
+   {
+      page_idx = page_addr/info.Flash_page_size;
+      for(blk_idx = 0 ; blk_idx <= FOTA_Package_Ctrl.m_fota_pkg_index ; blk_idx++)
+      {
+         phy_blk = FOTA_Package_Ctrl.m_fota_pkg_list[blk_idx].m_pkg_block_position;
+         page_count = (fgal->block_size(phy_blk)/info.Flash_page_size) - 3;
+         if(page_idx < page_count)
+            break;
+         else
+            page_idx -= page_count;
+      }
+   }
+   else
+   {
+      blk_idx = pkg_read->m_pkg_curr_blk;
+      phy_blk = FOTA_Package_Ctrl.m_fota_pkg_list[blk_idx].m_pkg_block_position;
+      page_count = (fgal->block_size(phy_blk)/info.Flash_page_size) - 3;
+      if( (pkg_read->m_pkg_curr_page+1) == page_count)
+      {
+         /* advance to next block */
+         blk_idx = pkg_read->m_pkg_curr_blk+1;
+         page_idx = 0;
+      }
+      else
+      {
+         blk_idx = pkg_read->m_pkg_curr_blk;
+         page_idx = pkg_read->m_pkg_curr_page+1;
+      }
+   }
+
+   /* sanity check 
+    * !CAUTION! all package blocks are assumed to have same size.
+    */
+   left_pages = FOTA_Package_Ctrl.m_fota_pkg_pages - blk_idx*page_count;
+   if( (blk_idx > FOTA_Package_Ctrl.m_fota_pkg_index) ||
+       ((blk_idx == FOTA_Package_Ctrl.m_fota_pkg_index) && ((page_idx+1) > left_pages)) )
+   {
+      fue_dbg_print("FOTA_ReadPackagePage: read over range:(%d,%d) > (%d,%d)!\n\r", \
+                     blk_idx, page_idx, FOTA_Package_Ctrl.m_fota_pkg_index, pkg_info->m_pkg_valid_pages);
+      ret_code = ERROR_FOTA_OVERRANGE;
+      return ret_code;
+   }
+   else
+   {
+      pkg_read->m_pkg_curr_addr = page_addr;
+      pkg_read->m_pkg_curr_blk = blk_idx;
+      pkg_read->m_pkg_curr_page = page_idx;
+      phy_blk = FOTA_Package_Ctrl.m_fota_pkg_list[blk_idx].m_pkg_block_position;
+      status = fgal->read_page((kal_uint32 *)buff, phy_blk, page_idx+1);/* plus one to bypass header page */
+      if(ERROR_FGAL_NONE == status)
+      {
+         //*page_size = FOTA_Package_Ctrl.m_fota_flash_info.Flash_page_size;
+         *page_size = info.Flash_page_size;
+      }
+      else if(ERROR_FGAL_READ_FAILURE == status)
+      {
+         ret_code = ERROR_FOTA_READ;
+      }
+      else if(ERROR_FGAL_OPERATION_RETRY == status)
+      {
+         ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+      }
+      else if(ERROR_FGAL_INVALID_PARAMETER == status)
+      {
+         ret_code = ERROR_FOTA_INVALID_PARAMETER;
+      }
+   }
+
+   return ret_code;
+}
+
+/* --------------------------------------------------------------------------------- */
+static kal_int32 FOTA_MTD_Read_Buffer(void *Buffer, kal_uint32 read_len)
+{
+   kal_uint32 buff_offset       = 0;
+   kal_int32 left_length        = read_len;
+   kal_int32  result            = 0;
+   kal_uint32 page_size         = 0;
+   kal_uint32 buff_addr         = (kal_uint32)Buffer;
+
+   while(left_length > 0)
+   {
+      result = FOTA_ReadPackagePage((void*)(buff_addr+buff_offset), FOTAData.SpareCurrReadAddr, \
+                                    &page_size);
+
+      if(ERROR_FOTA_SUCCESS == result)
+      {
+         buff_offset += page_size;
+         left_length -= page_size;
+         FOTAData.SpareCurrReadAddr += page_size;
+      }
+      else
+         break;
+   }
+   return result;
+}
+
+/* --------------------------------------------------------------------------------- *
+ * Update package download module
+ * --------------------------------------------------------------------------------- */
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_InitializePackageReservoir
+DESCRIPTION
+   find out whether any update record block exists
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_InitializePackageReservoir(void)
+{
+   kal_uint32               idx         = 0;
+   kal_int32                ret_code    = ERROR_FOTA_SUCCESS;
+
+   /* set package module control to default value */
+   FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_block_session  = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_previous_block = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_block  = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_valid_pages    = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_page   = INVALID_DWORD;
+
+   FOTA_Package_Ctrl.m_fota_pkg_index                     = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_pkg_pages                     = 0;
+
+   FOTA_Package_Ctrl.m_fota_curr_read.m_pkg_curr_addr = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_curr_read.m_pkg_curr_blk = INVALID_DWORD;
+   FOTA_Package_Ctrl.m_fota_curr_read.m_pkg_curr_page = INVALID_DWORD;
+
+   for(idx = 0 ; idx < FOTA_PKG_BLOCKS ; idx++)
+   {
+      FOTA_Package_Ctrl.m_fota_pkg_list[idx].m_pkg_block_order = INVALID_DWORD;
+      FOTA_Package_Ctrl.m_fota_pkg_list[idx].m_pkg_block_position = INVALID_DWORD;
+      FOTA_Package_Ctrl.m_fota_pkg_list[idx].m_pkg_valid_pages = INVALID_DWORD;
+      FOTA_Package_Ctrl.m_fota_pkg_list[idx].m_pkg_block_complete = KAL_FALSE;
+   }
+
+   /* initialize FGAL driver */
+   FOTA_Package_Ctrl.m_pkg_fgal = FOTA_Setup_FGAL();
+
+   /* get initial reserved area information */
+   FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start;
+   FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_end = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end;
+
+   /* get flash information */
+   //FOTA_Package_Ctrl.m_pkg_fgal->query_info(&FOTA_Package_Ctrl.m_fota_flash_info);
+
+   FOTA_Package_Ctrl.m_fota_pkg_state = FOTA_UPDATE_PACKAGE_STATE;
+
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ResumeUpdatePackage
+DESCRIPTION
+   find out whether any valid update package blocks exist
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ResumeUpdatePackage(void)
+{
+   kal_uint32               pkg_blocks  = INVALID_DWORD;
+   kal_uint32               buff_len    = FOTA_FLASH_MAX_PAGE_SIZE;
+   kal_uint32               idx         = 0;
+   kal_uint32               start_idx   = INVALID_DWORD;
+   kal_uint32               blk_order   = 0;
+   FUE_ERROR_CODE           result      = ERROR_FUE_NONE;
+   kal_int32                ret_code    = ERROR_FOTA_SUCCESS;
+   kal_uint32               pkg_pages   = 0;
+   FOTA_Package_List_st     *pkg_list   = NULL;
+   Logical_Flash_info_st    info;
+   Flash_GAL_st             *fgal       = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ret_code = ERROR_FOTA_NOT_INITIALIZED;
+      return ret_code;
+   }
+
+   /* try to resume interrupted download process */
+   /* update current package state to RAM copy   */
+   result = FUE_BlkInfo_Resume_Package_Blocks(&FOTA_Package_Ctrl, &pkg_blocks, g_fota_package_blocks,
+                                              fota_temp_page_buffer, &buff_len,
+                                              fue_dbg_print);
+   if(ERROR_FUE_NONE == result)
+   {
+      if( pkg_blocks )
+      {
+         /* get first element index */
+         for(idx = 0 ; idx < FOTA_PKG_BLOCKS ; idx++)
+         {
+            if( INVALID_DWORD == g_fota_package_blocks[idx].m_pkg_prev_idx )
+            {
+               if( INVALID_DWORD != g_fota_package_blocks[idx].m_pkg_block_order )
+               {
+                  start_idx = idx;
+                  break;
+               }
+            }
+         }
+         #ifdef _FUE_PKG_DEBUG_
+         if( INVALID_DWORD == start_idx )
+         {
+            fue_dbg_print("FOTA_ResumeUpdatePackage: first valid block not found in %d blocks!\n\r", pkg_blocks);
+            #if defined(__FOTA_DEBUG_ASSERT__)
+            ASSERT(0);
+            #endif /* __FOTA_DEBUG_ASSERT__ */
+         }
+         #endif
+
+         pkg_list = FOTA_Package_Ctrl.m_fota_pkg_list;
+         while(blk_order < pkg_blocks)
+         {
+            idx = start_idx;
+            while(1)
+            {
+               if(blk_order == g_fota_package_blocks[idx].m_pkg_block_order)
+               {
+                  pkg_list[blk_order].m_pkg_block_order = g_fota_package_blocks[idx].m_pkg_block_order;
+                  pkg_list[blk_order].m_pkg_block_position = g_fota_package_blocks[idx].m_pkg_block_position;
+                  pkg_list[blk_order].m_pkg_valid_pages = g_fota_package_blocks[idx].m_pkg_valid_pages;
+                  pkg_list[blk_order].m_pkg_block_complete = g_fota_package_blocks[idx].m_pkg_block_complete;
+                  pkg_pages += pkg_list[blk_order].m_pkg_valid_pages;
+                  if( (INVALID_DWORD == pkg_list[blk_order].m_pkg_valid_pages) ||
+                      (0 == pkg_list[blk_order].m_pkg_valid_pages) )
+                  {
+                     #ifdef _FUE_PKG_DEBUG_
+                     fue_dbg_print("FOTA_ResumeUpdatePackage: resume operation failed on %dth blk:%d\n\r", \
+                                   blk_order, pkg_list[blk_order].m_pkg_block_position);
+                     #endif /* _FUE_PKG_DEBUG_ */
+                     #if defined(__FOTA_DEBUG_ASSERT__)
+                     ASSERT(0);
+                     #endif /* __FOTA_DEBUG_ASSERT__ */
+                  }
+                  blk_order++;
+                  break;
+                  /*TODO: remove this element from g_fota_package_blocks to save searching time */
+               }
+               idx = g_fota_package_blocks[idx].m_pkg_next_idx;
+               if(INVALID_DWORD == idx)
+               {
+                  #ifdef _FUE_PKG_DEBUG_
+                  fue_dbg_print("FOTA_ResumeUpdatePackage: downloading sequence is lost!(%d,%d)\n\r", \
+                                blk_order, pkg_blocks);
+                  #if defined(__FOTA_DEBUG_ASSERT__)
+                  ASSERT(0);
+                  #endif /* __FOTA_DEBUG_ASSERT__ */
+                  #endif /* _FUE_PKG_DEBUG_ */
+                  /* package block order is lost, re-download package from the beggining  */
+                  ret_code = ERROR_FOTA_NO_UPDATE_PACKAGE;
+                  break;
+               }
+            }
+         }
+
+         #ifdef _FUE_PKG_DEBUG_
+         #if 0 /* removed since we do not update m_fota_pkg_info during FUE_BlkInfo_Resume_Package_Blocks() */
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+         #endif /* removed */
+         #endif
+         if(INVALID_DWORD != FOTA_Package_Ctrl.m_fota_pkg_list[blk_order-1].m_pkg_block_position)
+         {
+            FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_block = 
+               FOTA_Package_Ctrl.m_fota_pkg_list[blk_order-1].m_pkg_block_position;
+            if(pkg_list[blk_order-1].m_pkg_block_complete)
+            {
+               fgal->query_info(&info);
+               FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_page = 
+               fgal->block_size(FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_block)/info.Flash_page_size;
+            }
+            else
+            {
+            FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_page = pkg_list[blk_order-1].m_pkg_valid_pages+1;
+            }
+
+            FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_valid_pages = pkg_list[blk_order-1].m_pkg_valid_pages;
+            FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_block_session = blk_order-1;
+            FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_previous_block = (blk_order > 1) ? 
+               FOTA_Package_Ctrl.m_fota_pkg_list[blk_order-2].m_pkg_block_position : INVALID_DWORD;
+         }
+         FOTA_Package_Ctrl.m_fota_pkg_index = blk_order-1;
+         FOTA_Package_Ctrl.m_fota_pkg_blocks = pkg_blocks;
+         FOTA_Package_Ctrl.m_fota_pkg_pages = pkg_pages;
+
+         //FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_valid_pages = ;
+         if(pkg_blocks != blk_order)
+         {
+            #ifdef _FUE_PKG_DEBUG_
+            fue_dbg_print("FOTA_ResumeUpdatePackage: blk number:%d <-> blk order:%d!\n\r", \
+                          pkg_blocks, blk_order);
+            #endif /* _FUE_PKG_DEBUG_ */
+            #if defined(__FOTA_DEBUG_ASSERT__)
+            ASSERT(0);
+            #endif /* __FOTA_DEBUG_ASSERT__ */
+            ret_code = ERROR_FOTA_NO_UPDATE_PACKAGE;
+         }
+         #ifdef _FUE_PKG_DEBUG_
+         fue_dbg_print("FOTA_ResumeUpdatePackage: %dth package blk:%d!\n\r",
+                        FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_block_session, \
+                        FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_block);
+         #endif
+      }
+      else
+      {
+         ret_code = ERROR_FOTA_NO_UPDATE_PACKAGE;
+      }
+   }
+   else if((ERROR_FUE_INSUFFICIENT_BUFFER == result) || (ERROR_FUE_INVALID_PARAMETER == result))
+   {
+      ret_code = ERROR_FOTA_INVALID_PARAMETER;
+      FOTA_Package_Ctrl.m_fota_pkg_state = INVALID_DWORD;
+   }
+   else if( (ERROR_FUE_NOT_FOUND == result) || (ERROR_FUE_TOO_MANY_PACKAGE_BLOCKS == result) )
+   {
+      ret_code = ERROR_FOTA_NO_UPDATE_PACKAGE;
+   }
+   else if( (ERROR_FUE_OPERATION_STOP == result) || (ERROR_FUE_READ_FAILURE == result) )
+   {
+      ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+   }
+
+   return ret_code;
+}
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_CheckAvailablePackageBlocks
+DESCRIPTION
+   scan all block in package reservoir area to estimate the available storage size
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_CheckAvailablePackageBlocks(kal_uint32 *available_num)
+{
+   kal_int32  ret_code       = ERROR_FOTA_SUCCESS;
+   kal_uint32 base_blk       = INVALID_DWORD;
+   kal_uint32 end_blk        = INVALID_DWORD;
+   kal_uint32 blk_idx        = 0;
+   kal_uint32 blk_num        = 0;
+   _FGAL_ERROR_CODE   status = ERROR_FGAL_NONE;
+   Flash_GAL_st  *fgal  = NULL;
+   //Logical_Flash_info_st  info;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   base_blk = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base;
+   end_blk  = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_end;
+
+   fgal = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   //fgal->query_info(&info);
+   *available_num = 0;
+
+   for(blk_idx = base_blk ; blk_idx < (end_blk+1) ; blk_idx++)
+   {
+      status = fgal->check_block(blk_idx);
+      if(ERROR_FGAL_NONE == status)
+      {
+         /* check whether it is occupied */
+         if(FUE_NFB_Is_Available_Block(blk_idx, fota_temp_page_buffer, fgal, fue_dbg_print))
+         {
+            blk_num++;
+         }
+      }
+      else if(ERROR_FGAL_READ_FAILURE == status)
+      {
+         ret_code = ERROR_FOTA_READ;
+         break;
+      }
+      else if(ERROR_FGAL_OPERATION_RETRY == status)
+      {
+         ret_code = ERROR_FOTA_FLASH_DEVICE;
+         break;
+      }
+   }
+   if(blk_idx == (end_blk+1))
+      *available_num = blk_num;
+
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ClearPackageReservoir
+DESCRIPTION
+   clear downloaded update package
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+        ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ClearPackageReservoir(void)
+{
+   kal_int32  ret_code         = ERROR_FOTA_SUCCESS;
+   kal_uint32 base_blk         = INVALID_DWORD;
+   kal_uint32 end_blk          = INVALID_DWORD;
+   kal_uint32 index            = 0;
+   kal_uint32 blk_idx          = 0;
+   kal_uint32 erase_round      = 0;
+   kal_uint32 pkg_num          = FOTA_PKG_BLOCKS;
+   kal_uint32 erased_blk       = 0;
+   FUE_ERROR_CODE  result      = ERROR_FUE_NOT_FOUND;
+   _FGAL_ERROR_CODE       status   = ERROR_FGAL_NONE;
+   Flash_GAL_st           *fgal    = NULL;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   base_blk = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base;
+   end_blk  = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_end;
+
+   fgal = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   /* try to erase all blocks occupied by update package */
+   for( blk_idx = base_blk ; blk_idx <= end_blk ; blk_idx++ )
+   {
+       status = fgal->check_block(blk_idx);
+       if(ERROR_FGAL_NONE == status)
+       {
+           result = FUE_BlkInfo_Is_Update_Block(&FOTA_Update_Ctrl, blk_idx, fue_dbg_print);
+           if(ERROR_FUE_NOT_FOUND == result) /* in this flash space, only package or update blocks exist */
+           {
+               /* erase block */
+               status = fgal->erase_block(blk_idx);
+               if(ERROR_FGAL_ERASE_FAILURE == status)
+               {
+                   fgal->mark_bad(blk_idx);
+                   #ifdef _FUE_PKG_DEBUG_
+                   fue_dbg_print("FOTA_ClearPackageReservoir: erase failed on block:%d!\n\r", blk_idx);
+                   #endif
+               }
+               else if(ERROR_FGAL_OPERATION_RETRY == status)
+               {
+                   #ifdef _FUE_PKG_DEBUG_
+                   fue_dbg_print("FOTA_ClearPackageReservoir: erase operation stopped on block:%d!\n\r", blk_idx);
+                   #endif
+                   ret_code = ERROR_FOTA_FLASH_DEVICE;
+                   break;
+               }
+               erased_blk++;
+           }
+           else if( (ERROR_FUE_OPERATION_STOP == result) || (ERROR_FUE_OVER_DESIGN == result) )
+           {
+               #ifdef _FUE_PKG_DEBUG_
+               fue_dbg_print("FOTA_ClearPackageReservoir: read operation stopped on block:%d!\n\r", blk_idx);
+               #endif
+               ret_code = ERROR_FOTA_FLASH_DEVICE;
+               break;
+           }
+           else if(ERROR_FUE_NONE == result)
+           {
+               continue;
+           }
+           else
+           {
+               #ifdef _FUE_PKG_DEBUG_
+               fue_dbg_print("FOTA_ClearPackageReservoir: unexpected error on block:%d!\n\r", blk_idx);
+               #endif
+               ret_code = ERROR_FOTA_UNSUPPORTED_CASES;
+               break;
+           }
+       }
+       else if(ERROR_FGAL_READ_FAILURE == status)
+       {
+           ret_code = ERROR_FOTA_READ;
+           break;
+       }
+       else if(ERROR_FGAL_OPERATION_RETRY == status)
+       {
+           ret_code = ERROR_FOTA_FLASH_DEVICE;
+           break;
+       }
+   }
+   #ifdef _FUE_PKG_DEBUG_
+   fue_dbg_print("FOTA_ClearPackageReservoir: clear %d in %d blocks!\n\r", erased_blk, blk_idx-base_blk);
+   #endif
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Get_TotalPackageBlock
+DESCRIPTION
+   return current package block number
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Get_TotalPackageBlock(kal_uint32 *pkg_blks, kal_uint32* pkg_pages)
+{
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   if(INVALID_DWORD != FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_valid_pages)
+   {
+      *pkg_blks = FOTA_Package_Ctrl.m_fota_pkg_blocks-1;
+      *pkg_pages = FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_valid_pages;
+   }
+   else
+   {
+      *pkg_blks = FOTA_Package_Ctrl.m_fota_pkg_blocks;
+      *pkg_pages = 0;
+   }
+   
+   return ERROR_FOTA_SUCCESS;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Get_CurrentPackagePosition
+DESCRIPTION
+   return current package block position
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Get_CurrentPackagePosition(kal_uint32 *curr_blk, kal_uint32* curr_page)
+{
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   *curr_blk = FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_block;
+   *curr_page = FOTA_Package_Ctrl.m_fota_pkg_info.m_pkg_current_page;
+   
+   return ERROR_FOTA_SUCCESS;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Get_AvailablePackageSpace
+DESCRIPTION
+   return currently downloaded package size
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Get_AvailablePackageSpace(kal_uint32 *avail_size)
+{
+   Logical_Flash_info_st   info;
+   kal_int32               ret_code  = ERROR_FOTA_SUCCESS;
+   kal_uint32              page_size;
+   kal_uint32              blk_idx   = 0;
+   kal_uint32              start_blk = 0;
+   kal_uint32              end_blk   = 0;
+   kal_uint32              free_size = 0;
+   _FGAL_ERROR_CODE        status    = ERROR_FGAL_NONE;
+   Flash_GAL_st            *fgal     = NULL;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   fgal = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   fgal->query_info(&info);
+   page_size = info.Flash_page_size;
+   start_blk = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base;
+   end_blk  = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_end;
+
+   /* try to erase all blocks occupied by update package */
+   for( blk_idx = start_blk ; blk_idx <= end_blk ; blk_idx++ )
+   {
+      status = fgal->check_block(blk_idx);
+      if(ERROR_FGAL_NONE == status)
+      {
+         /* check whether it is occupied */
+         if( FUE_NFB_Is_Available_Block(blk_idx, fota_temp_page_buffer, fgal, fue_dbg_print) ||
+         	   FUE_BlkInfo_Is_Package_Block(&FOTA_Package_Ctrl, blk_idx, fue_dbg_print) )
+         {
+            free_size += fgal->block_size(blk_idx)-3*page_size;/* header and end mark pages are reserved */
+         }
+      }
+      else if(ERROR_FGAL_READ_FAILURE == status)
+      {
+         ret_code = ERROR_FOTA_READ;
+         break;
+      }
+      else if(ERROR_FGAL_OPERATION_RETRY == status)
+      {
+         ret_code = ERROR_FOTA_FLASH_DEVICE;
+         break;
+      }
+   }
+
+   FOTA_Get_CurrentPackagePosition(&start_blk, &end_blk);
+   if(INVALID_DWORD != start_blk)
+   {
+      /* header, end mark and current valid pages are excluded */
+      free_size += fgal->block_size(start_blk)-(end_blk+3)*page_size; 
+   }
+
+   *avail_size = free_size;
+
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Get_TotalPackageSpace
+DESCRIPTION
+   return currently downloaded package size
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Get_TotalPackageSpace(kal_uint32 *avail_size)
+{
+   Logical_Flash_info_st   info;
+   kal_int32               ret_code  = ERROR_FOTA_SUCCESS;
+   kal_uint32              page_size;
+   kal_uint32              blk_idx   = 0;
+   kal_uint32              start_blk = 0;
+   kal_uint32              end_blk   = 0;
+   kal_uint32              free_size = 0;
+   _FGAL_ERROR_CODE        status    = ERROR_FGAL_NONE;
+   Flash_GAL_st            *fgal     = NULL;
+
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   fgal = FOTA_Package_Ctrl.m_pkg_fgal;
+
+   fgal->query_info(&info);
+   page_size = info.Flash_page_size;
+   start_blk = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_base;
+   end_blk  = FOTA_Package_Ctrl.m_fota_pkg_area.FOTA_pkg_area_end;
+
+   /* try to erase all blocks occupied by update package */
+   for( blk_idx = start_blk ; blk_idx <= end_blk ; blk_idx++ )
+   {
+      status = fgal->check_block(blk_idx);
+      if(ERROR_FGAL_NONE == status)
+      {
+         /* check whether it is occupied */
+         if( (ERROR_FUE_NONE == FUE_NFB_Is_Available_Block(blk_idx, fota_temp_page_buffer, fgal, fue_dbg_print)) ||
+             (ERROR_FUE_NONE == FUE_BlkInfo_Is_Package_Block(&FOTA_Package_Ctrl, blk_idx, fue_dbg_print)) )
+         {
+            free_size += fgal->block_size(blk_idx)-3*page_size;/* header and end mark pages are reserved */
+         }
+      }
+      else if(ERROR_FGAL_READ_FAILURE == status)
+      {
+         ret_code = ERROR_FOTA_READ;
+         break;
+      }
+      else if(ERROR_FGAL_OPERATION_RETRY == status)
+      {
+         ret_code = ERROR_FOTA_FLASH_DEVICE;
+         break;
+      }
+   }
+
+   /* one block is reserved for update state record replacement */
+   *avail_size = free_size-(fgal->block_size(start_blk)-3*page_size);/* header and end mark pages are reserved */
+
+   return ret_code;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Get_DownloadedPackageSize
+DESCRIPTION
+   return currently downloaded package size
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Get_DownloadedPackageSize(kal_uint32 *curr_size)
+{
+   Logical_Flash_info_st   info;
+   if(FOTA_UPDATE_PACKAGE_STATE != FOTA_Package_Ctrl.m_fota_pkg_state)
+   {
+      ASSERT(0);
+      return ERROR_FOTA_NOT_INITIALIZED;
+   }
+
+   FOTA_Package_Ctrl.m_pkg_fgal->query_info(&info);
+   if(INVALID_DWORD != FOTA_Package_Ctrl.m_fota_pkg_pages)
+      *curr_size = FOTA_Package_Ctrl.m_fota_pkg_pages*info.Flash_page_size;
+   else
+       *curr_size = 0;
+  
+   return ERROR_FOTA_SUCCESS;
+}
+
+#if 0
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#endif
+/* --------------------------------------------------------------------------------- *
+ * Update staus record control module
+ * --------------------------------------------------------------------------------- */
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_InitializeUpdateRecord
+DESCRIPTION
+   create an update record block or find out the existing update record block 
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_InitializeUpdateRecord(void)
+{
+   kal_uint32              start_block = INVALID_DWORD;
+   kal_uint32              end_block   = INVALID_DWORD;
+   FUE_ERROR_CODE          result      = ERROR_FUE_NONE;
+   _FGAL_ERROR_CODE        status      = ERROR_FGAL_NONE;
+
+   /* initialize FGAL driver */
+   FOTA_Update_Ctrl.m_update_fgal = FOTA_Setup_FGAL();
+
+   /* get initial reserved area information */
+   start_block = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start;
+   end_block = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end;
+   //FOTA_Update_Ctrl.m_update_fgal->query_info(&FOTA_Update_Ctrl.m_nand_flash_info);
+
+   /* set up update record module */
+   result = FUE_InitializeUpdateRecord(start_block, end_block, \
+                                       FOTA_Update_Ctrl.m_update_fgal/*&FOTA_Nand_Fgal*/,\
+                                       fue_dbg_print);
+   if(ERROR_FUE_NO_AVAILABLE_BLOCK == result)
+   {
+      status = ERROR_FOTA_NO_AVAILABLE_BLOCK;
+   }
+   else if(ERROR_FUE_OPERATION_STOP == result)
+   {
+      status = ERROR_FOTA_FLASH_DEVICE;
+   }
+   else if(ERROR_FUE_OVER_DESIGN == result)
+   {
+      status = ERROR_FOTA_UNSUPPORTED_CASES;
+   }
+   else
+   {
+      FOTA_Update_Ctrl.FOTA_UPDATE_ID = UPDATE_STATE_RECORD_ID;
+   }
+
+   return status;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_WriteUpdateRecord
+DESCRIPTION
+   FOTA update state information write API
+   download client and update agent use this information to communicate with each other
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_WriteUpdateRecord(FOTA_Custom_Update_Info* record)
+{
+   kal_int32 ret            = ERROR_FOTA_SUCCESS;
+   FUE_ERROR_CODE  result   = ERROR_FUE_NONE;
+
+   /* check whether FOTA is initialized */
+   if(UPDATE_STATE_RECORD_ID != FOTA_Update_Ctrl.FOTA_UPDATE_ID)
+   {
+      ret = ERROR_FOTA_NOT_INITIALIZED;
+   }
+   else
+   {
+      result = FUE_NFB_Flush_Update_Record(record, fue_dbg_print);
+
+      if(ERROR_FUE_NONE == result )
+      {
+         ret = ERROR_FOTA_SUCCESS;
+      }
+      else if(ERROR_FUE_OPERATION_STOP == result)
+      {
+         #ifdef FOTA_DEBUG
+         ASSERT(0);
+         #endif
+         ret = ERROR_FOTA_FLASH_DEVICE;
+      }
+   }
+   return ret;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_ReadUpdateRecord
+DESCRIPTION
+   FOTA update state information read API
+   download client and update agent use this information to communicate with each other
+PARAMETER
+   NULL
+RETURN
+   0: means pass initialization step (ERROR_FOTA_SUCCESS)
+   < 0: means fail
+      ERROR_FOTA_CUSTOMIZATION: wrong customization
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_ReadUpdateRecord(FOTA_Custom_Update_Info* record)
+{
+   kal_int32       ret     = ERROR_FOTA_SUCCESS;
+   FUE_ERROR_CODE  result  = ERROR_FUE_NONE;
+
+   /* check whether FOTA is initialized */
+   if(UPDATE_STATE_RECORD_ID != FOTA_Update_Ctrl.FOTA_UPDATE_ID)
+   {
+      ret = ERROR_FOTA_NOT_INITIALIZED;
+   }
+   else
+   {
+      result = FUE_NFB_Get_Update_Record(record, fue_dbg_print);
+
+      if(ERROR_FUE_UNRECOVERABLE_ECC == result)
+      {
+         ret = ERROR_FOTA_READ;
+      }
+      else if(ERROR_FUE_OPERATION_STOP == result)
+      {
+        ret = ERROR_FOTA_FLASH_DEVICE;
+      }
+   }
+   return ret;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Inform_Update_State
+DESCRIPTION
+   Download client use this function to query the result of update process
+PARAMETER
+   NULL
+RETURN
+--------------------------------------------------------------------------------- */
+FOTA_update_result  FOTA_Inform_Update_State(void)
+{
+   FOTA_update_result  ret     = FOTA_UPDATE_NONE;
+   FUE_ERROR_CODE      result  = ERROR_FUE_NONE;
+   FOTA_Custom_Update_Info   upt_info;
+
+   /* check whether FOTA is initialized */
+   if(UPDATE_STATE_RECORD_ID != FOTA_Update_Ctrl.FOTA_UPDATE_ID)
+   {
+      ret = FOTA_UPDATE_NONE;
+   }
+   else
+   {
+      result = FOTA_ReadUpdateRecord(&upt_info);
+
+      if(ERROR_FUE_NONE == result)
+      {
+         /* check customer's state */
+         if( FUE_UA_COMPLETE_PHASE == upt_info.FOTA_test_info1 )
+         {
+            ret = FOTA_UPDATE_SUCCEEDED;
+         }
+         else
+         {
+#if 0 
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+#endif
+            {
+               ret = FOTA_UPDATE_FAILED;
+            }
+         }
+      }
+      else
+      {
+         ret = FOTA_UPDATE_NONE;
+      }
+   }
+   
+   return ret;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Start_Download_State
+DESCRIPTION
+   Download client use this function to query the result of update process
+PARAMETER
+   NULL
+RETURN
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Start_Download_State(void)
+{
+   kal_int32           ret     = ERROR_FOTA_SUCCESS;
+   FOTA_Custom_Update_Info   upt_info;
+
+   if(UPDATE_STATE_RECORD_ID != FOTA_Update_Ctrl.FOTA_UPDATE_ID)
+   {
+      ret = ERROR_FOTA_NOT_INITIALIZED;
+   }
+   else
+   {
+      kal_mem_set(&upt_info,0xff,sizeof(FOTA_Custom_Update_Info));
+      FUE_Start_Download_State();
+      ret = FOTA_WriteUpdateRecord(&upt_info);
+   }
+
+   return ret;
+}
+
+/* ---------------------------------------------------------------------------------
+FUNCTION
+   FOTA_Start_Update_State
+DESCRIPTION
+   Download client use this function to query the result of update process
+PARAMETER
+   NULL
+RETURN
+--------------------------------------------------------------------------------- */
+kal_int32 FOTA_Start_Update_State(void)
+{
+   kal_int32           ret     = ERROR_FOTA_SUCCESS;
+   FOTA_Custom_Update_Info   upt_info;
+
+   if(UPDATE_STATE_RECORD_ID != FOTA_Update_Ctrl.FOTA_UPDATE_ID)
+   {
+      ret = ERROR_FOTA_NOT_INITIALIZED;
+   }
+   else
+   {
+      kal_mem_set(&upt_info,0xff,sizeof(FOTA_Custom_Update_Info));
+      FUE_Start_Package_Verification_State();
+      ret = FOTA_WriteUpdateRecord(&upt_info);
+   }
+
+   return ret;
+}
+
+
+/* --------------------------------------------------------------------------------- *
+ * Flash Generic Access Layer 
+ * --------------------------------------------------------------------------------- */
+#define FOTA_FGAL_READY   (0x59445246)
+kal_uint32 g_FOTA_fgal_state;
+
+#if defined(_NAND_FLASH_BOOTING_) || (defined(__UP_PKG_ON_NAND__) && defined(NAND_SUPPORT))
+
+#if !defined(__NAND_FDM_50__)
+#include "NAND_FDM.h"
+#include "nand_mtd.h"
+#include "nand_mtd_internal.h"
+#else
+#include "NAND_MTD_FDM50.h"
+#include "NAND_DAL.h"
+#include "NAND_MTD_FDM50_internal.h"
+#include "NAND_DAL_internal.h"
+
+extern kal_uint8 IsGoodBlock(void* D, void * Spare);
+#endif /* !__NAND_FDM_50__ */
+
+/* Following functions and variables are located in NAND_MTD.c */
+extern int NFB_ReadPhysicalPage(kal_uint32 PhyBlock, kal_uint32 PhyPage, void * Data);
+extern int NFB_ReadPhysicalSpare(kal_uint32 PhyBlock, kal_uint32 PhyPage, void * Data, kal_bool chksum);
+extern int NFB_ProgramPhysicalPage(kal_uint32 PhyBlock, kal_uint32 PhyPage, void * Data, kal_bool DALRemap);
+extern int NFB_ProgramPhysicalSpare(kal_uint32 PhyBlock, kal_uint32 PhyPage, void * Data, kal_bool chksum, kal_bool DALRemap);
+extern int NFB_ErasePhysicalBlock(kal_uint32 PhyBlock, kal_bool DALRemap);
+extern void get_NFI_bus(void);
+extern void free_NFI_bus(void);
+
+extern int NFBPageSize;
+extern int NFBBlockSize;
+
+#if defined(__NAND_FDM_50__)
+
+extern flash_info_2 Flash_Info;
+
+#else /* NAND FDM 4.x */
+
+extern NAND_FLASH_DRV_DATA  NANDFlashDriveData;
+
+#endif
+
+/* Forward declaration */
+_FGAL_ERROR_CODE FOTA_NAND_Init_func(void);
+_FGAL_ERROR_CODE FOTA_NAND_Page_Read_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NAND_Query_Info_func(Logical_Flash_info_st* info);
+_FGAL_ERROR_CODE FOTA_NAND_Page_Program_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NAND_Is_Good_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NAND_Mark_Bad_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NAND_Erase_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NAND_Is_Page_Empty_func(kal_uint32 *buff, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NAND_Lock_Block_func(kal_uint32 blk, kal_bool locked);
+kal_uint32 FOTA_NAND_Block_Size_func(kal_uint32 blk);
+kal_uint32 FOTA_NAND_Block_Index_func(kal_uint32 blk_addr);
+
+/*
+ * Macro definition
+ */
+#define FOTA_NAND_STATE_VALID   (0x5644544D)
+
+#define FOTA_MAX_SPARE_SIZE      (64)
+
+/*
+ * Global variable definition
+ */
+kal_uint32 g_FOTA_NAND_MTD_STATE;
+
+kal_uint32 g_fota_spare_buffer[FOTA_MAX_SPARE_SIZE>>2];
+
+/* For flash generic access layer */
+Flash_GAL_st          FOTA_Nand_Fgal;
+
+/*****************************************************************
+Description : wait for a specific period counted by 32Khz tick.
+Input       : 
+Output      : None
+******************************************************************/
+static void delay32KHzTick(kal_uint32 count)
+{
+	kal_uint32 begin_time = 0;
+	kal_uint32 current_time = 0;
+	
+	begin_time = INT_GetCurrentTime();
+	do
+	{
+	   current_time = INT_GetCurrentTime();
+	   if(current_time > begin_time)
+	   {
+	      if( (current_time-begin_time) > count )
+	         break;
+	   }
+	   else
+	   {
+	      if( (0xFFFFFFFF - begin_time + current_time + 1) > count)
+	         break;
+	   }
+	}while(1);
+}
+
+/*****************************************************************
+Description : set up FGAL structure.
+Input       : 
+Output      : None
+******************************************************************/
+
+
+Flash_GAL_st *FOTA_Setup_FGAL(void)
+{
+   if(FOTA_FGAL_READY == g_FOTA_fgal_state)
+      return &FOTA_Nand_Fgal;
+
+   /* set up FGAL */
+   FOTA_Nand_Fgal.init_drv = FOTA_NAND_Init_func;
+   FOTA_Nand_Fgal.query_info = FOTA_NAND_Query_Info_func;
+   FOTA_Nand_Fgal.read_page = FOTA_NAND_Page_Read_func;
+   FOTA_Nand_Fgal.write_page = FOTA_NAND_Page_Program_func;
+   FOTA_Nand_Fgal.check_block = FOTA_NAND_Is_Good_Block_func;
+   FOTA_Nand_Fgal.mark_bad = FOTA_NAND_Mark_Bad_Block_func;
+   FOTA_Nand_Fgal.erase_block = FOTA_NAND_Erase_Block_func;
+   FOTA_Nand_Fgal.check_empty_page = FOTA_NAND_Is_Page_Empty_func;
+   FOTA_Nand_Fgal.block_size = FOTA_NAND_Block_Size_func;
+   FOTA_Nand_Fgal.block_index = FOTA_NAND_Block_Index_func;
+   FOTA_Nand_Fgal.lock_block = FOTA_NAND_Lock_Block_func;
+
+   /* initialize FGAL driver */
+   FOTA_Nand_Fgal.init_drv();
+
+   g_FOTA_fgal_state = FOTA_FGAL_READY;
+   return &FOTA_Nand_Fgal;
+}
+
+/*****************************************************************
+Description : check whether the provided buffer comes from empty page.
+Input       : 
+Output      : None
+******************************************************************/
+kal_bool FOTA_NAND_MTD_Check_Page_Empty(kal_uint8* page_buffer, kal_uint8* spare_buffer)
+{
+   kal_uint32   spare_len  = 0;
+   kal_uint32   idx = 0, j = 0;
+   kal_uint32*  long_ptr   = NULL;
+   kal_int32    byte_count = 0;
+   kal_int32    long_len   = 0;
+   kal_uint32   page_size  = NFBPageSize;
+
+   switch(page_size)
+   {
+      case 4096:
+         spare_len = 128;
+      break;    
+      case 2048:
+         spare_len = 64;
+      break;
+      case 512:
+         spare_len = 16;
+      break;
+      default:
+         ASSERT(0);
+   }
+   /* compare with 0xFF */
+   if(page_buffer)
+   {
+      long_ptr = (kal_uint32 *)(((kal_uint32)page_buffer+3) & ~(0x03));
+      long_len = ((((kal_uint32)page_buffer+page_size) & ~(0x03)) - (kal_uint32)long_ptr) >> 2;
+      byte_count = (kal_uint32)long_ptr - (kal_uint32)page_buffer;
+      /* chech page content */
+      if(byte_count > 0)
+      {
+         for(j = 0 ; j < byte_count ; j++)
+         {
+            if(page_buffer[j] != 0xFF)
+               return KAL_FALSE;
+         }
+      }
+      for(idx = 0 ; idx < long_len ; idx++)
+      {
+         if(long_ptr[idx] != 0xFFFFFFFF)
+            return KAL_FALSE;
+      }
+      byte_count = page_size - byte_count - (long_len<<2);
+      if(byte_count > 0)
+      {
+         for(j = byte_count ; j > 0 ; j--)
+         {
+            if(page_buffer[page_size-j] != 0xFF)
+               return KAL_FALSE;
+         }
+      }
+   }
+
+   if(spare_buffer)
+   {
+      /* check spare content */
+      long_ptr = (kal_uint32 *)(((kal_uint32)spare_buffer+3) & ~(0x03));
+      long_len = ((((kal_uint32)spare_buffer+spare_len) & ~(0x03)) - (kal_uint32)long_ptr) >> 2;
+      byte_count = (kal_uint32)long_ptr - (kal_uint32)spare_buffer;
+      if(byte_count > 0)
+      {
+         for(j = 0 ; j < byte_count ; j++)
+         {
+            if(spare_buffer[j] != 0xFF)
+               return KAL_FALSE;
+         }
+      }
+      for(idx = 0 ; idx < long_len ; idx++)
+      {
+         if(long_ptr[idx] != 0xFFFFFFFF)
+            return KAL_FALSE;
+      }
+      byte_count = spare_len - byte_count - (long_len<<2);
+      if(byte_count > 0)
+      {
+         for(j = byte_count ; j > 0 ; j--)
+         {
+            if(spare_buffer[page_size-j] != 0xFF)
+               return KAL_FALSE;
+         }
+      }
+   }
+   return KAL_TRUE;;
+}
+
+/*****************************************************************
+Description : check whether the provided buffer comes from spare area of bad block.
+Input       : 
+Output      : None
+******************************************************************/
+void FOTA_NAND_MTD_Set_Spare_Bad_Mark(kal_uint8* spare_buffer)
+{
+   kal_uint8          *byte_ptr  = spare_buffer;
+   kal_bool            word_flag = KAL_FALSE;
+#if !defined(__NAND_FDM_50__)
+   flash_info_struct  *nand_info = &NANDFlashDriveData.flash_info;
+
+   if(IO_ACCESS_16BIT == nand_info->io_width)
+   {
+      word_flag = KAL_TRUE;
+   }
+
+#else
+
+   if(Flash_Info.deviceInfo_CE[0].IOWidth == 16)
+   {
+      word_flag = KAL_TRUE;
+   }
+
+#endif /* __NAND_FDM_50__ */
+
+   if(512 == NFBPageSize)
+   {
+      if(!word_flag)
+      {
+         byte_ptr[5] = 0x0B;
+      }
+      else
+      {
+         byte_ptr[0] = 0x0B;
+         byte_ptr[10] = 0x0B;
+      }
+   }
+   else if((2048 == NFBPageSize)||(4096 == NFBPageSize))
+   {
+      if(!word_flag)
+      {
+         byte_ptr[0] = 0x0B;
+      }
+      else
+      {
+         byte_ptr[0] = 0x0B;
+         byte_ptr[1] = 0x0B;
+      }
+   }
+}
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Init_func
+*
+* DESCRIPTION
+* Initialze NAND flash MTD driver
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Init_func(void)
+{
+   kal_int32   status = -1;
+
+   status = NFB_ReadPhysicalPage(0xFFFFFFFF, 0xFFFFFFFF, NULL);
+
+   g_FOTA_NAND_MTD_STATE = FOTA_NAND_STATE_VALID;
+
+   #if defined(__NAND_FDM_50__)
+   NFBPageSize = Flash_Info.pageSize;
+   //NFBBlockSize = Flash_Info.pageSize*Flash_Info.blockPage;
+   #endif /* __NAND_FDM_50__ */
+
+   #if defined(__UP_PKG_ON_NAND__)
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start = FOTA_NAND_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE);
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end = FOTA_NAND_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE+FOTA_PACKAGE_STORAGE_SIZE)-1;
+   #endif /* __UP_PKG_ON_NAND__ */
+
+   return ERROR_FGAL_NONE;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Page_Read_func
+*
+* DESCRIPTION
+* Read one page from NAND flash
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Page_Read_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page)
+{
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   kal_int32          status = 0;
+   #if !defined(__NFI_VERSION2__) && !defined(__NFI_VERSION3_1__)
+   static kal_uint32  empty_spare[64>>2];
+   #endif /* !__NFI_VERSION2__ && !__NFI_VERSION3_1__*/
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   status = NFB_ReadPhysicalPage(blk, page, ptr);
+
+   switch(status)
+   {
+      case ERROR_NFB_BAD_BLOCK:
+         result = ERROR_FGAL_BAD_BLOCK;
+         /* should not happen */
+         EXT_ASSERT(0, 0, 0, 0);
+         break;
+      case ERROR_NFB_READ:
+         #if !defined(__NFI_VERSION2__) && !defined(__NFI_VERSION3_1__)
+         /* empty page read will generate ECC failure on NFI version1 */
+         kal_mem_set(empty_spare, 0xFF, 64);
+         NFB_ReadPhysicalSpare(blk, page, empty_spare, KAL_FALSE);
+         if(FOTA_NAND_MTD_Check_Page_Empty((kal_uint8 *)ptr, (kal_uint8 *)empty_spare))
+         {
+            result = ERROR_FGAL_NONE;
+         }
+         else
+         {
+            result = ERROR_FGAL_ECC_FAILURE;
+         }
+         #else /* __NFI_VERSION2__ || __NFI_VERSION3_1__*/
+         result = ERROR_FGAL_ECC_FAILURE;
+         #endif /* !__NFI_VERSION2__ && !__NFI_VERSION3_1__*/
+         break;
+      default:
+         if(NFBPageSize == status)
+            result = ERROR_FGAL_NONE;
+         else
+         {
+            ASSERT(0);
+            result = ERROR_FGAL_OPERATION_RETRY;
+         }
+   }
+   
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Query_Info_func
+*
+* DESCRIPTION
+* Query NAND flash device information
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Query_Info_func(Logical_Flash_info_st* info)
+{
+   _FGAL_ERROR_CODE   result      = ERROR_FGAL_NONE;
+   kal_uint32         page_size   = 0;
+   kal_uint32         offset      = 0;
+   kal_uint32         pages_per_block = 0;
+   kal_uint32         page_shift = 0;
+#if !defined(__NAND_FDM_50__)
+   flash_info_struct  *nand_info  = &NANDFlashDriveData.flash_info;
+#endif /* __NAND_FDM_50__ */
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+#if defined(__NAND_FDM_50__)
+
+   page_size = Flash_Info.pageSize;
+   if(4096 == page_size)
+   {
+      page_shift = 12;
+   }
+   else if(2048 == page_size)
+   {
+      page_shift = 11;
+   }
+   else if(512 == page_size)
+   {
+      page_shift = 9;
+   }
+   else
+   {
+      /* incorrect device configuration */
+      ASSERT(0);
+   }
+
+   pages_per_block = Flash_Info.blockPage;
+
+   info->Flash_page_size = page_size;
+   info->Flash_block_size = page_size*pages_per_block;
+   info->Flash_io_width = Flash_Info.deviceInfo_CE[0].IOWidth;
+
+#else /* NAND FDM 4 */
+
+   if(PAGE_2K == nand_info->page_type)
+   {
+      page_size = 2048;
+      page_shift = 11;
+   }
+   else if(PAGE_512 == nand_info->page_type)
+   {
+      page_size = 512;
+      page_shift = 9;
+   }
+   else
+   {
+      /* incorrect device configuration */
+      ASSERT(0);
+   }
+
+   pages_per_block = nand_info->pages_per_block;
+
+   info->Flash_page_size = page_size;
+   info->Flash_block_size = page_size*nand_info->pages_per_block;
+   info->Flash_io_width = nand_info->io_width;
+
+#endif
+
+   /* Assumptions: pages per block is power of 2 */
+   info->Flash_offset_shift = INVALID_DWORD;
+   for( offset = 0 ; offset < 32 ; offset++)
+   {
+      if( (1 << offset) == pages_per_block )
+      {
+         info->Flash_offset_shift = offset;
+         info->Flash_block_shift = offset+page_shift;
+         break;
+      }
+   }
+   if(INVALID_DWORD == info->Flash_offset_shift)
+      ASSERT(0); /* incorrect device configuration */
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Page_Program_func
+*
+* DESCRIPTION
+* Write one page to NAND flash
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Page_Program_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page)
+{
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   kal_int32          status = 0;
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   status = NFB_ProgramPhysicalPage(blk, page, ptr, KAL_TRUE);
+
+   switch(status)
+   {
+      case ERROR_NFB_BAD_BLOCK:
+         result = ERROR_FGAL_BAD_BLOCK;
+         /* should not happen */
+         EXT_ASSERT(0, 0, 0, 0);
+         break;
+      case ERROR_NFB_PROGRAM:
+         result = ERROR_FGAL_WRITE_FAILURE;
+         break;
+      default:
+         if(NFBPageSize == status)
+            result = ERROR_FGAL_NONE;
+         else
+         {
+            ASSERT(0);
+            result = ERROR_FGAL_OPERATION_RETRY;
+         }
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Is_Good_Block_func
+*
+* DESCRIPTION
+* Check whether block is good or bad.
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Is_Good_Block_func(kal_uint32 blk)
+{
+   _FGAL_ERROR_CODE   result    = ERROR_FGAL_NONE;
+   kal_int32          status    = 0;
+   kal_uint8          *byte_ptr = (kal_uint8 *)g_fota_spare_buffer;
+#if !defined(__NAND_FDM_50__)
+   void *nand_info = (void *)&NANDFlashDriveData;
+#else /* !__NAND_FDM_50__ */
+   void *nand_info = (void *)&Flash_Info;
+#endif 
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   status = NFB_ReadPhysicalSpare(blk, 0, g_fota_spare_buffer, KAL_FALSE);
+   if(ERROR_NFB_SUCCESS == status)
+   {
+      if(IsGoodBlock(nand_info, byte_ptr) > 0)
+      {
+         status = NFB_ReadPhysicalSpare(blk, 1, g_fota_spare_buffer, KAL_FALSE);
+         if(ERROR_NFB_SUCCESS == status)
+         {
+            if(IsGoodBlock(nand_info, byte_ptr) > 0)
+            {
+               result = ERROR_FGAL_NONE;
+            }
+            else
+            {
+               result = ERROR_FGAL_BAD_BLOCK;
+            }
+         }
+      }
+      else
+      {
+         result = ERROR_FGAL_BAD_BLOCK;
+      }
+   }
+   else
+   {
+      if(ERROR_NFB_READ == status)
+         result = ERROR_FGAL_READ_FAILURE;
+      else
+         ASSERT(0);
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Mark_Bad_Block_func
+*
+* DESCRIPTION
+* Read one page from NAND flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Mark_Bad_Block_func(kal_uint32 blk)
+{
+   _FGAL_ERROR_CODE   result    = ERROR_FGAL_NONE;
+   kal_int32          status    = 0;
+   kal_uint8          *byte_ptr = (kal_uint8 *)g_fota_spare_buffer;
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   NFB_ErasePhysicalBlock(blk, KAL_TRUE);
+
+   kal_mem_set(g_fota_spare_buffer, 0xFF, FOTA_MAX_SPARE_SIZE);
+   FOTA_NAND_MTD_Set_Spare_Bad_Mark(byte_ptr);
+   
+   status = NFB_ProgramPhysicalSpare(blk, 0, byte_ptr, KAL_FALSE, KAL_TRUE);
+   if(ERROR_NFB_SUCCESS == status)
+   {
+      status = NFB_ProgramPhysicalSpare(blk, 1, byte_ptr, KAL_FALSE, KAL_TRUE);
+   }
+
+   switch(status)
+   {
+      case ERROR_NFB_BAD_BLOCK:
+         result = ERROR_FGAL_BAD_BLOCK;
+         /* should not happen */
+         EXT_ASSERT(0, 0, 0, 0);
+         break;
+      case ERROR_NFB_PROGRAM:
+         result = ERROR_FGAL_WRITE_FAILURE;
+         break;
+      case ERROR_NFB_SUCCESS:
+         result = ERROR_FGAL_NONE;
+         break;
+      default:
+         ASSERT(0);
+         result = ERROR_FGAL_OPERATION_RETRY;
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Erase_Block_func
+*
+* DESCRIPTION
+* Erase one block on NAND flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Erase_Block_func(kal_uint32 blk)
+{
+   kal_uint32         trial = 0;
+   kal_int32          status = -1;
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   for(trial = 0 ; trial < 3 ; trial++)
+   {
+      status = NFB_ErasePhysicalBlock(blk, KAL_TRUE);
+      if(ERROR_NFB_ERASE != status)
+         break;
+      delay32KHzTick(1000);
+   }
+
+   switch(status)
+   {
+      case ERROR_NFB_BAD_BLOCK:
+         result = ERROR_FGAL_BAD_BLOCK;
+         /* should not happen */
+         EXT_ASSERT(0, 0, 0, 0);
+         break;
+      case ERROR_NFB_ERASE:
+         result = ERROR_FGAL_ERASE_FAILURE;
+         break;
+      case ERROR_NFB_SUCCESS:
+         result = ERROR_FGAL_NONE;
+         break;
+      default:
+         ASSERT(0);
+         result = ERROR_FGAL_OPERATION_RETRY;
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Is_Page_Empty_func
+*
+* DESCRIPTION
+* Read one page from NAND flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Is_Page_Empty_func(kal_uint32 *buff, kal_uint32 blk, kal_uint32 page)
+{
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   kal_int32          status = ERROR_NFB_READ;
+   kal_int32          status2 = ERROR_NFB_READ;
+
+   ASSERT( FOTA_NAND_STATE_VALID == g_FOTA_NAND_MTD_STATE);
+
+   kal_mem_set(g_fota_spare_buffer, 0x0, FOTA_MAX_SPARE_SIZE);
+   kal_mem_set(buff, 0x0, NFBPageSize);
+
+   status = NFB_ReadPhysicalPage(blk, page, buff);
+   status2 = NFB_ReadPhysicalSpare(blk, page, g_fota_spare_buffer, KAL_FALSE);
+
+   if( (NFBPageSize == status) && (ERROR_NFB_SUCCESS == status2) )
+   {
+      status = ERROR_NFB_SUCCESS;
+   }
+   else
+   {
+      status = ERROR_NFB_READ;
+   }
+
+   switch(status)
+   {
+      case ERROR_NFB_BAD_BLOCK:
+         result = ERROR_FGAL_BAD_BLOCK;
+         /* should not happen */
+         EXT_ASSERT(0, 0, 0, 0);
+         break;
+      case ERROR_NFB_READ: /* empty page in 28/29 is covered here */
+         if(!FOTA_NAND_MTD_Check_Page_Empty((kal_uint8 *)buff, (kal_uint8 *)g_fota_spare_buffer))
+            result = ERROR_FGAL_NON_EMPTY;
+         break;
+      case ERROR_NFB_SUCCESS:
+         if(!FOTA_NAND_MTD_Check_Page_Empty((kal_uint8 *)buff, (kal_uint8 *)g_fota_spare_buffer))
+            result = ERROR_FGAL_NON_EMPTY_CHECK;
+         break;
+      default:
+         ASSERT(0);
+         result = ERROR_FGAL_OPERATION_RETRY;
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Lock_Block_func
+*
+* DESCRIPTION
+* Lock one block on NAND flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NAND_Lock_Block_func(kal_uint32 blk, kal_bool locked)
+{
+   return ERROR_FGAL_NONE;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Block_Size_func
+*
+* DESCRIPTION
+* Erase one block on NAND flash
+ *************************************************************************/
+kal_uint32 FOTA_NAND_Block_Size_func(kal_uint32 blk)
+{
+   kal_uint32          blk_size   = 0;
+#if !defined(__NAND_FDM_50__)
+   flash_info_struct  *nand_info  = &NANDFlashDriveData.flash_info;
+
+   if(PAGE_2K == nand_info->page_type)
+   {
+      blk_size = 2048*nand_info->pages_per_block;
+   }
+   else if(PAGE_512 == nand_info->page_type)
+   {
+      blk_size = 512*nand_info->pages_per_block;
+   }
+   else
+      ASSERT(0); /* incorrect configuration */
+
+#else
+
+   blk_size = Flash_Info.pageSize*Flash_Info.blockPage;
+
+#endif
+
+   return blk_size;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NAND_Block_Index_func
+*
+* DESCRIPTION
+* Erase one block on NAND flash
+ *************************************************************************/
+kal_uint32 FOTA_NAND_Block_Index_func(kal_uint32 blk_addr)
+{
+   kal_uint32          blk_size   = 0;
+#if !defined(__NAND_FDM_50__)
+   flash_info_struct  *nand_info  = &NANDFlashDriveData.flash_info;
+
+   if(PAGE_2K == nand_info->page_type)
+   {
+      blk_size = 2048*nand_info->pages_per_block;
+   }
+   else if(PAGE_512 == nand_info->page_type)
+   {
+      blk_size = 512*nand_info->pages_per_block;
+   }
+   else
+      ASSERT(0); /* incorrect configuration */
+
+#else
+
+   blk_size = Flash_Info.pageSize*Flash_Info.blockPage;
+
+#endif
+
+   ASSERT(blk_size);/* incorrect device configuration */
+
+   return blk_addr/blk_size;
+}
+
+#elif defined(__EMMC_BOOTING__)
+
+/* For flash generic access layer */
+Flash_GAL_st          FOTA_eMMC_Fgal;
+
+Flash_GAL_st *FOTA_Setup_FGAL(void)
+{
+   if(FOTA_FGAL_READY == g_FOTA_fgal_state)
+      return &FOTA_eMMC_Fgal;
+
+   /* set up FGAL */
+   FOTA_eMMC_Fgal.init_drv = FGAL2FTL_Init;
+   FOTA_eMMC_Fgal.query_info = FGAL2FTL_Query_Info;
+   FOTA_eMMC_Fgal.read_page = FGAL2FTL_Read_Page;
+   FOTA_eMMC_Fgal.write_page = FGAL2FTL_Write_Page;
+   FOTA_eMMC_Fgal.check_block = FGAL2FTL_Is_Good_Block;
+   FOTA_eMMC_Fgal.mark_bad = FGAL2FTL_Mard_Bad_Block;
+   FOTA_eMMC_Fgal.erase_block = FGAL2FTL_Erase_Block;
+   FOTA_eMMC_Fgal.check_empty_page = FGAL2FTL_Is_Empty_Page;
+   FOTA_eMMC_Fgal.block_size = FGAL2FTL_Block_Size;
+   FOTA_eMMC_Fgal.block_index = FGAL2FTL_Block_Index;
+   FOTA_eMMC_Fgal.lock_block = FGAL2FTL_Lock_Block;
+
+   /* initialize FGAL driver */
+   FOTA_eMMC_Fgal.init_drv();
+
+   g_FOTA_fgal_state = FOTA_FGAL_READY;
+   return &FOTA_eMMC_Fgal;
+}
+
+
+#else /* !_NAND_FLASH_BOOTING_ */
+
+#include "custom_MemoryDevice.h"
+#include "DrvFlash.h"
+#include "reg_base.h"
+#include "fue_init.h"
+
+/* Forward declaration */
+_FGAL_ERROR_CODE FOTA_NOR_Init_func(void);
+_FGAL_ERROR_CODE FOTA_NOR_Page_Read_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NOR_Query_Info_func(Logical_Flash_info_st* info);
+_FGAL_ERROR_CODE FOTA_NOR_Page_Program_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NOR_Is_Good_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NOR_Mark_Bad_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NOR_Erase_Block_func(kal_uint32 blk);
+_FGAL_ERROR_CODE FOTA_NOR_Is_Page_Empty_func(kal_uint32 *buff, kal_uint32 blk, kal_uint32 page);
+_FGAL_ERROR_CODE FOTA_NOR_Lock_Block_func(kal_uint32 blk, kal_bool locked);
+kal_uint32 FOTA_NOR_Block_Size_func(kal_uint32 blk);
+kal_uint32 FOTA_NOR_Block_Index_func(kal_uint32 blk_addr);
+
+/* Following functions and variables are located in custom_blconfig.c */
+extern kal_uint32 custom_Block_Size(kal_uint32 nor_addr);
+extern kal_uint32 custom_get_NORFLASH_ROMSpace(void);
+extern kal_uint32 custom_get_NORFLASH_Base(void);
+
+/*
+ * Macro definition
+ */
+#define FOTA_NOR_STATE_VALID   (0x5644544D)
+
+#define FOTA_MAX_SPARE_SIZE      (64)
+
+/*
+ * Global variable definition
+ */
+kal_uint32 g_FOTA_NOR_MTD_STATE;
+/* 
+ * For flash generic access layer 
+ */
+Flash_GAL_st          FOTA_Nor_Fgal;
+
+NOR_FLASH_DRV_Data    NORFlashDriveData;
+NOR_Flash_MTD_Data    FOTA_nor_mtdflash;
+
+
+/* 
+ * External variable reference
+ */
+
+extern NOR_MTD_Driver NORFlashMtd;
+
+
+/*****************************************************************
+Description : acquire FDM synchronization lock.
+Input       : 
+Output      : None
+******************************************************************/
+void retrieve_FDM_lock(void)
+{
+   #if   defined(__NOR_FDM5__)
+
+   extern void nFDM_LOCK(void);
+   nFDM_LOCK();
+
+   #else
+
+   extern void FDM_LOCK(void);
+   FDM_LOCK();
+
+   #endif
+}
+
+/*****************************************************************
+Description : relieve FDM synchronization lock.
+Input       : 
+Output      : None
+******************************************************************/
+void release_FDM_lock(void)
+{
+   #if   defined(__NOR_FDM5__)
+
+   extern void nFDM_UNLOCK(void);
+   nFDM_UNLOCK();
+
+   #else
+
+   extern void FDM_UNLOCK(void);
+   FDM_UNLOCK();
+
+   #endif
+}
+
+/*****************************************************************
+Description : Wait device ready before operation
+Input       : 
+Output      : None
+******************************************************************/
+void FOTA_WaitEraseDone(void)
+{
+   #if defined(__NOR_FDM5__)
+
+   return;
+
+   #else // !__SINGLE_BANK_NOR_FLASH_SUPPORT__ && __NOR_FDM4__
+
+   extern NOR_FLASH_DRV_Data FlashDriveData;
+   extern void WaitEraseDone(NOR_FLASH_DRV_Data * D, kal_uint32 frame_tick);
+   //#define INVALID_BLOCK_INDEX   0xFFFFFFFF
+   if( FlashDriveData.ReclaimBlockID != 0xFFFFFFFF )
+   { 
+      WaitEraseDone(&FlashDriveData,70);
+   }
+   #endif
+}
+
+/*****************************************************************
+Description : set up FGAL structure.
+Input       : 
+Output      : None
+******************************************************************/
+#define FOTA_FGAL_READY   (0x59445246)
+kal_uint32 g_FOTA_fgal_state;
+extern kal_uint8 RandomNum;
+
+Flash_GAL_st *FOTA_Setup_FGAL(void)
+{
+
+   if(FOTA_FGAL_READY == g_FOTA_fgal_state)
+      return &FOTA_Nor_Fgal;
+
+  /* set up FGAL */
+   FOTA_Nor_Fgal.init_drv = FOTA_NOR_Init_func;
+   FOTA_Nor_Fgal.query_info = FOTA_NOR_Query_Info_func;
+   FOTA_Nor_Fgal.read_page = FOTA_NOR_Page_Read_func;
+   FOTA_Nor_Fgal.write_page = FOTA_NOR_Page_Program_func;
+   FOTA_Nor_Fgal.check_block = FOTA_NOR_Is_Good_Block_func;
+   FOTA_Nor_Fgal.mark_bad = FOTA_NOR_Mark_Bad_Block_func;
+   FOTA_Nor_Fgal.erase_block = FOTA_NOR_Erase_Block_func;
+   FOTA_Nor_Fgal.check_empty_page = FOTA_NOR_Is_Page_Empty_func;
+   FOTA_Nor_Fgal.block_size = FOTA_NOR_Block_Size_func;
+   FOTA_Nor_Fgal.block_index = FOTA_NOR_Block_Index_func;
+   FOTA_Nor_Fgal.lock_block = FOTA_NOR_Lock_Block_func;
+
+   /* initialize FGAL driver */
+   FOTA_Nor_Fgal.init_drv();
+
+   g_FOTA_fgal_state = FOTA_FGAL_READY;
+
+
+   return &FOTA_Nor_Fgal;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Init_func
+*
+* DESCRIPTION
+* Initialze NOR flash MTD driver
+ ************************************************************************/
+
+#if defined(__SERIAL_FLASH__)
+
+extern FlashRegionInfo CMEM_FOTA_NORRegionInfo[];
+
+_FGAL_ERROR_CODE FOTA_NOR_Init_func(void)
+{
+
+   if( (FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE) &&
+       (~((kal_uint32)CMEM_FOTA_NORRegionInfo) == ((NOR_Flash_MTD_Data*)(NORFlashDriveData.MTDData))->Signature) )
+      return ERROR_FGAL_NONE;
+
+   g_FOTA_NOR_MTD_STATE = FOTA_NOR_STATE_VALID;
+
+   /* Initialize MTD data table */
+   CMEM_Init_FOTA();
+
+   /* prepare update package area information */
+   // RegionInfo must be assigned before invoke FOTA_NOR_Block_Index_func
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE);
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE+FOTA_PACKAGE_STORAGE_SIZE)-1;
+
+   NORFlashDriveData.FlashInfo.baseUnlockBlock = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start;
+   NORFlashDriveData.FlashInfo.endUnlockBlock = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end;
+
+   NORFlashDriveData.MTDDriver->MountDevice(NORFlashDriveData.MTDData, (void*)&NORFlashDriveData.FlashInfo);
+   /* prepare update package area information */
+   //FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE);
+   //FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE+FOTA_PACKAGE_STORAGE_SIZE)-1;
+   /* TODO: unlock all blocks reserved for update package */
+   return ERROR_FGAL_NONE;
+}
+
+#else // !__COMBO_MEMORY_SUPPORT__ && !__SERIAL_FLASH__
+_FGAL_ERROR_CODE FOTA_NOR_Init_func(void)
+{
+   if( (FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE) &&
+       (~((kal_uint32)NORRegionInfo) == FOTA_nor_mtdflash.Signature) )
+      return ERROR_FGAL_NONE;
+
+   g_FOTA_NOR_MTD_STATE = FOTA_NOR_STATE_VALID;
+   /* Initialize MTD data table */
+   FOTA_nor_mtdflash.Signature = ~((kal_uint32)NORRegionInfo);
+
+   NORFlashDriveData.MTDDriver = &NORFlashMtd;
+   NORFlashDriveData.MTDData = &FOTA_nor_mtdflash;
+
+#ifdef __MTK_TARGET__
+   FOTA_nor_mtdflash.BaseAddr = (BYTE *)INT_RetrieveFlashBaseAddr();
+#endif /* __MTK_TARGET__ */
+
+   FOTA_nor_mtdflash.RegionInfo = (FlashRegionInfo *)NORRegionInfo;
+   /* prepare update package area information */
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE);
+   FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE+FOTA_PACKAGE_STORAGE_SIZE)-1;
+
+   NORFlashDriveData.FlashInfo.baseUnlockBlock = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start;
+   NORFlashDriveData.FlashInfo.endUnlockBlock = FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end;
+
+   NORFlashDriveData.MTDDriver->MountDevice(NORFlashDriveData.MTDData, (void*)&NORFlashDriveData.FlashInfo);
+   /* prepare update package area information */
+   //FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_start = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE);
+   //FOTA_NFB_Area_Info.m_fota_pkg_area.m_pkg_area_end = FOTA_NOR_Block_Index_func(FOTA_PACKAGE_STORAGE_BASE+FOTA_PACKAGE_STORAGE_SIZE)-1;
+   /* TODO: unlock all blocks reserved for update package */
+   return ERROR_FGAL_NONE;
+}
+#endif //__COMBO_MEMORY_SUPPORT__ || __SERIAL_FLASH__
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Page_Read_func
+*
+* DESCRIPTION
+* Read one page from NOR flash
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Page_Read_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page)
+{
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   kal_int32          status = 0;
+   kal_uint32         blk_size = 0;
+   kal_uint32         src_addr = 0;
+
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+   retrieve_FDM_lock();
+
+   FOTA_WaitEraseDone();
+
+   blk_size = BlockSize(mtdflash, blk);
+   ASSERT(page < (blk_size/FOTA_FLASH_MAX_PAGE_SIZE));
+   src_addr = (kal_uint32)BlockAddress(mtdflash, blk) + page*FOTA_FLASH_MAX_PAGE_SIZE;
+   kal_mem_cpy(ptr, (void *)src_addr, FOTA_FLASH_MAX_PAGE_SIZE);
+
+   release_FDM_lock();
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Query_Info_func
+*
+* DESCRIPTION
+* Query NOR flash device information
+* The information is specific for flash area reserved for update package 
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Query_Info_func(Logical_Flash_info_st* info)
+{
+   _FGAL_ERROR_CODE   result      = ERROR_FGAL_NONE;
+   #if 0
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+/* under construction !*/
+   #else
+   info->Flash_page_size = FOTA_FLASH_MAX_PAGE_SIZE;
+   info->Flash_io_width = 16;
+   #endif
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Page_Program_func
+*
+* DESCRIPTION
+* Write one page to NOR flash
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Page_Program_func(kal_uint32* ptr, kal_uint32 blk, kal_uint32 page)
+{
+   _FGAL_ERROR_CODE   result    = ERROR_FGAL_NONE;
+   kal_int32          status    = 0;
+   kal_uint32         blk_size  = 0;
+   kal_uint32         dst_addr  = 0;
+   kal_uint32         src_addr  = (kal_uint32)ptr;
+   kal_uint32         left_len  = FOTA_FLASH_MAX_PAGE_SIZE;
+   kal_uint32         write_len = 0;
+   kal_uint32         pbp_len   = 0;
+   NOR_MTD_Driver     *mtd_drv  = NORFlashDriveData.MTDDriver;
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+   blk_size = BlockSize(mtdflash, blk);
+   ASSERT(page < (blk_size/FOTA_FLASH_MAX_PAGE_SIZE));
+
+   MapWindow(mtdflash, blk, 0);
+   //mtdflash->CurrAddr = (BYTE *)BlockAddress(mtdflash, blk);
+
+   dst_addr = (kal_uint32)mtdflash->CurrAddr + page*FOTA_FLASH_MAX_PAGE_SIZE;
+
+   retrieve_FDM_lock();
+
+   FOTA_WaitEraseDone();
+
+
+
+   if(BUFFER_PROGRAM_ITERATION_LENGTH)
+   {
+      pbp_len = BUFFER_PROGRAM_ITERATION_LENGTH<<1;
+   }
+   else
+   {
+      pbp_len = 2;
+   }
+
+   while(left_len)
+   {
+      if(left_len > pbp_len)
+      {
+         write_len = pbp_len;
+      }
+      else
+      {
+         write_len = left_len;
+      }
+
+      status = mtd_drv->ProgramData(mtdflash, (void *)dst_addr, (void *)src_addr, write_len);
+      if(RESULT_FLASH_FAIL == status)
+      {
+         break;
+      }
+      else
+      {
+         left_len -= write_len;
+         dst_addr += write_len;
+         src_addr += write_len;
+      }
+   }
+
+
+   release_FDM_lock();
+
+   if(RESULT_FLASH_FAIL == status)
+   {
+      result = ERROR_FGAL_WRITE_FAILURE;
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Is_Good_Block_func
+*
+* DESCRIPTION
+* Check whether block is good or bad.
+* Always return good since no bad block is allowed in NOR flash
+ ************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Is_Good_Block_func(kal_uint32 blk)
+{
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+
+   return ERROR_FGAL_NONE;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Mark_Bad_Block_func
+*
+* DESCRIPTION
+* mark a block as bad, should not be called on NOR flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Mark_Bad_Block_func(kal_uint32 blk)
+{
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+
+   /* should not happen */
+   EXT_ASSERT(0, 0, 0, 0);
+
+   return ERROR_FGAL_OPERATION_RETRY;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Erase_Block_func
+*
+* DESCRIPTION
+* Erase one block on NOR flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Erase_Block_func(kal_uint32 blk)
+{
+   kal_uint32         trial = 0;
+   kal_int32          status = -1;
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   NOR_MTD_Driver     *mtd_drv  = NORFlashDriveData.MTDDriver;
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+
+   MapWindow(mtdflash, blk, 0);
+
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+   retrieve_FDM_lock();
+
+   FOTA_WaitEraseDone();
+
+
+
+   status = mtd_drv->EraseBlock(mtdflash, blk);
+
+
+   release_FDM_lock();
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Is_Page_Empty_func
+*
+* DESCRIPTION
+* Read one page from NOR flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Is_Page_Empty_func(kal_uint32 *buff, kal_uint32 blk, kal_uint32 page)
+{
+   kal_uint32         *page_ptr = NULL;
+   kal_uint32         blk_size  = 0;
+   kal_uint32           idx     = 0;
+   _FGAL_ERROR_CODE   result    = ERROR_FGAL_NONE;
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+   blk_size = BlockSize(mtdflash, blk);
+   ASSERT(page < (blk_size/FOTA_FLASH_MAX_PAGE_SIZE));
+
+   mtdflash->CurrAddr = (BYTE *)BlockAddress(mtdflash, blk);
+   page_ptr = (kal_uint32 *)((kal_uint32)mtdflash->CurrAddr + page*FOTA_FLASH_MAX_PAGE_SIZE);
+
+   retrieve_FDM_lock();
+
+   FOTA_WaitEraseDone();  
+
+   for(idx = 0 ; idx < (FOTA_NOR_FLASH_PAGE_SIZE>>2) ; idx++)
+   {
+      if(*(page_ptr+idx) != INVALID_DWORD)
+      {
+         result = ERROR_FGAL_NON_EMPTY_CHECK;
+         break;
+      }
+   }
+
+   release_FDM_lock();
+
+   if(ERROR_FGAL_NON_EMPTY_CHECK == result)
+   {
+      kal_mem_cpy(buff, page_ptr, FOTA_FLASH_MAX_PAGE_SIZE);
+   }
+
+   return result;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Lock_Block_func
+*
+* DESCRIPTION
+* Erase one block on NOR flash
+ *************************************************************************/
+_FGAL_ERROR_CODE FOTA_NOR_Lock_Block_func(kal_uint32 blk, kal_bool locked)
+{
+   _FGAL_ERROR_CODE   result = ERROR_FGAL_NONE;
+   kal_uint32         blk_addr = 0;
+   kal_uint32         blk_action = 0;
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+   NOR_MTD_Driver     *mtd_drv  = NORFlashDriveData.MTDDriver;
+
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+   blk_addr = (kal_uint32)BlockAddress(mtdflash, blk);
+   if(locked)
+   {
+      blk_action = ACTION_LOCK;
+   }
+   else
+   {
+      blk_action = ACTION_UNLOCK;
+   }
+
+   retrieve_FDM_lock();
+
+   FOTA_WaitEraseDone();
+
+   mtd_drv->LockEraseBlkAddr(mtdflash, (void *)blk_addr, blk_action);
+
+   release_FDM_lock();
+   return ERROR_FGAL_NONE;
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Block_Size_func
+*
+* DESCRIPTION
+* Erase one block on NAND flash
+ *************************************************************************/
+kal_uint32 FOTA_NOR_Block_Size_func(kal_uint32 blk)
+{
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+
+   return BlockSize((void *)mtdflash, blk);
+}
+
+/*************************************************************************
+* FUNCTION
+*  FOTA_NOR_Block_Index_func
+*
+* DESCRIPTION
+* Erase one block on NAND flash
+ *************************************************************************/
+kal_uint32 FOTA_NOR_Block_Index_func(kal_uint32 blk_addr)
+{
+   NOR_Flash_MTD_Data *mtdflash = (NOR_Flash_MTD_Data *)NORFlashDriveData.MTDData;
+   ASSERT( FOTA_NOR_STATE_VALID == g_FOTA_NOR_MTD_STATE);
+
+   return BlockIndex((void *)mtdflash, blk_addr & (~((kal_uint32)mtdflash->BaseAddr)));
+   //return BlockIndex((void *)mtdflash, blk_addr - FOTA_PACKAGE_STORAGE_BASE);
+}
+
+#endif /* NAND_FLASH_BOOTING */
+
+
+#endif /* __FOTA_DM__ */