//
// Copyright (c) Microsoft Corporation.  All rights reserved.
//
//
// Use of this source code is subject to the terms of the Microsoft end-user
// license agreement (EULA) under which you licensed this SOFTWARE PRODUCT.
// If you did not accept the terms of the EULA, you are not authorized to use
// this source code. For a copy of the EULA, please see the LICENSE.RTF on your
// install media.
//

#include <bootpart.h>
#include "bppriv.h"
#include <fmd.h>
//#include "../MMCboot/hs_mmc.h"
#include "image_cfg.h"
#include <hsmmcdrv.h>

extern "C"
{
    extern UINT32 g_dwSectorCount;
    extern UINT32 g_dwIsSDHC;
    extern ADDRESSINFOSECTOR g_AddressInfoSector;
}

LPBYTE g_pbMBRSector = NULL;
LPBYTE g_pbBlock = NULL;
DWORD g_dwMBRSectorNum = INVALID_ADDR;
FlashInfo g_FlashInfo;
PARTSTATE g_partStateTable[NUM_PARTS];
PSectorInfo g_pSectorInfoBuf;
DWORD g_dwLastLogSector;          // Stores the last valid logical sector
DWORD g_dwDataBytesPerBlock;
DWORD g_dwLastWrittenLoc;  // Stores the byte address of the last physical flash address written to


LPBYTE g_pbStorageMBRSector = NULL;
DWORD g_dwStorageMBRSectorNum = INVALID_ADDR;
FlashInfo g_StorageFlashInfo;
DWORD g_dwStorageLastLogSector;          // Stores the last valid logical sector
DWORD g_dwStorageDataBytesPerBlock;
DWORD g_dwStorageLastWrittenLoc;  // Stores the byte address of the last physical flash address written to




#define MAX_WRITE_SECTOR 512
#define SECTOR_PER_SECTOR 512

//extern void SDHC_READ(UINT32 dwStartSector, UINT32 dwSector, UINT32 dwAddr);
//extern void SDHC_WRITE(UINT32 dwStartSector, UINT32 dwSector, UINT32 dwAddr);

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static Addr LBAtoCHS(FlashInfo *pFlashInfo, Addr lba)
{
    if(lba.type == CHS)
        return lba;

    Addr chs;
    DWORD tmp = pFlashInfo->dwNumBlocks * pFlashInfo->wSectorsPerBlock;

    chs.type = CHS;
    chs.chs.cylinder = (WORD)(lba.lba / tmp);
    tmp = lba.lba % tmp;
    chs.chs.head = (WORD)(tmp / pFlashInfo->wSectorsPerBlock);
    chs.chs.sector = (WORD)((tmp % pFlashInfo->wSectorsPerBlock) + 1);

    return chs;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static Addr CHStoLBA(FlashInfo *pFlashInfo, Addr chs)
{
    Addr lba;

    if(chs.type == LBA)
        return chs;

    lba.type = LBA;
    lba.lba = ((chs.chs.cylinder * pFlashInfo->dwNumBlocks + chs.chs.head)
        * pFlashInfo->wSectorsPerBlock)+ chs.chs.sector - 1;

    return lba;
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static DWORD GetMBRSectorNum ()
{
    return g_AddressInfoSector.dwFlashImageStartSector;    
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL WriteMBR()
{
    DWORD dwMBRBlockNum = g_dwMBRSectorNum / g_FlashInfo.wSectorsPerBlock;

    RETAILMSG(1, (TEXT("WriteMBR: MBR block = 0x%x.\r\n"), MBRSTARTSECTOR));

    memset (g_pbBlock, 0xff, g_dwDataBytesPerBlock);
    memcpy (g_pbBlock , g_pbMBRSector, g_FlashInfo.wDataBytesPerSector);

    RETAILMSG(1, (TEXT("KSH WirteMBR 0x%x,0x%x,0x%x,\r\n"),g_pbBlock[0],g_pbBlock[1],g_pbBlock[2] ));
    SDHC_WRITE(MBRSTARTSECTOR,SECTOROFMBR, (UINT32)g_pbBlock);
    return TRUE;
    
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL CreateMBR() 
{
    // This, plus a valid partition table, is all the CE partition manager needs to recognize 
    // the MBR as valid. It does not contain boot code.
    RETAILMSG (1, (TEXT("CreateMBR: ++\r\n")));
    RETAILMSG (1, (TEXT("CreateMBR: g_pbMBRSector= 0x%x\r\n"), g_pbMBRSector));
    RETAILMSG (1, (TEXT("CreateMBR: g_pbBlock= 0x%x\r\n"), g_pbBlock));
    RETAILMSG (1, (TEXT("CreateMBR: wDataBytesPerSector= %d\r\n"), g_FlashInfo.wDataBytesPerSector));

    memset (g_pbMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);
    g_pbMBRSector[0] = 0xE9;
    g_pbMBRSector[1] = 0xfd;
    g_pbMBRSector[2] = 0xff;
    g_pbMBRSector[SECTOR_SIZE-2] = 0x55;
    g_pbMBRSector[SECTOR_SIZE-1] = 0xAA;

    // Zero out partition table so that mspart treats entries as empty.
    memset (g_pbMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);

    RETAILMSG (1, (TEXT("CreateMBR: --\r\n")));
    return WriteMBR();

}  

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL IsValidMBR() 
{
#if 0
    RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x 0x%x\r\n"), g_AddressInfoSector.dwFlashImageStartSector,g_dwSectorCount));

    SDHC_READ(g_AddressInfoSector.dwFlashImageStartSector, 1, (UINT32)g_pbMBRSector);
#else
    RETAILMSG(1, (TEXT("[BP:INF] IsValidMBR: MBR sector = 0x%x\r\n"), MBRSTARTSECTOR));

	SDHC_READ(MBRSTARTSECTOR, SECTOROFMBR, (UINT32)g_pbMBRSector);
#endif
    RETAILMSG(1, (TEXT("KSH IsValidMBR 0x%x,0x%x,0x%x,\r\n"),g_pbMBRSector[0],g_pbMBRSector[1],g_pbMBRSector[2] ));
    return ((g_pbMBRSector[0] == 0xE9) &&
         (g_pbMBRSector[1] == 0xfd) &&
         (g_pbMBRSector[2] == 0xff) &&
         (g_pbMBRSector[SECTOR_SIZE-2] == 0x55) &&
         (g_pbMBRSector[SECTOR_SIZE-1] == 0xAA));
}  


//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL WriteStorageMBR()
{

    RETAILMSG(1, (TEXT("WriteStorageMBR: MBR block = 0x%x.\r\n"), 0));

//    SDHC_WRITE(0,SECTOROFMBR, (UINT32)g_pbStorageMBRSector);
    SDHC_WRITE(0,1, (UINT32)g_pbStorageMBRSector);
    return TRUE;
    
}

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL CreateStorageMBR() 
{
    // This, plus a valid partition table, is all the CE partition manager needs to recognize 
    // the MBR as valid. It does not contain boot code.
    RETAILMSG (1, (TEXT("CreateStorageMBR: ++\r\n")));
    RETAILMSG (1, (TEXT("CreateStorageMBR: g_pbStorageMBRSector= 0x%x\r\n"), g_pbStorageMBRSector));

    memset (g_pbStorageMBRSector, 0xff, g_FlashInfo.wDataBytesPerSector);
    g_pbStorageMBRSector[0] = 0xE9;
    g_pbStorageMBRSector[1] = 0xfd;
    g_pbStorageMBRSector[2] = 0xff;
    g_pbStorageMBRSector[SECTOR_SIZE-2] = 0x55;
    g_pbStorageMBRSector[SECTOR_SIZE-1] = 0xAA;

    // Zero out partition table so that mspart treats entries as empty.
    memset (g_pbStorageMBRSector+PARTTABLE_OFFSET, 0, sizeof(PARTENTRY) * NUM_PARTS);

    RETAILMSG (1, (TEXT("CreateStorageMBR: --\r\n")));
    return WriteStorageMBR();

}  

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL IsValidStorageMBR() 
{
    RETAILMSG (1, (TEXT("IsValidMBR: MBR sector = 0x%x 0x%x\r\n"), g_AddressInfoSector.dwFlashImageStartSector,g_dwSectorCount));

    SDHC_READ(0, 1, (UINT32)g_pbStorageMBRSector);

    return ((g_pbStorageMBRSector[0] == 0xE9) &&
         (g_pbStorageMBRSector[1] == 0xfd) &&
         (g_pbStorageMBRSector[2] == 0xff) &&
         (g_pbStorageMBRSector[SECTOR_SIZE-2] == 0x55) &&
         (g_pbStorageMBRSector[SECTOR_SIZE-1] == 0xAA));
}  

//------------------------------------------------------------------------------
//------------------------------------------------------------------------------
static BOOL IsValidPart (PPARTENTRY pPartEntry)
{
    return (pPartEntry->Part_FileSystem != 0xff) && (pPartEntry->Part_FileSystem != 0);
}


/*  AddPartitionTableEntry
 *
 *  Generates the partition entry for the partition table and copies the entry 
 *  into the MBR that is stored in memory.
 *  
 *
 *  ENTRY
 *      entry - index into partition table
 *      startSector - starting logical sector
 *      totalSectors - total logical sectors
 *      fileSystem - type of partition
 *      bootInd - byte in partition entry that stores various flags such as
 *          active and read-only status.
 *
 *  EXIT
 */
 
static void AddPartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd)
{
    PARTENTRY partentry = {0};
    Addr startAddr;
    Addr endAddr;

    ASSERT(entry < 4);
    // no checking with disk info and start/total sectors because we allow
    // bogus partitions for testing purposes

    RETAILMSG(1,(TEXT("AddPartitionTableEntry startsector : %d:\n"),startSector));

    // initially known partition table entry
    partentry.Part_BootInd = bootInd;
    partentry.Part_FileSystem = fileSystem;
    partentry.Part_StartSector = startSector;
    partentry.Part_TotalSectors = totalSectors;

    // logical block addresses for the first and final sector (start on the second head)
    startAddr.type = LBA;
    startAddr.lba = partentry.Part_StartSector;
    endAddr.type = LBA;
    endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;

    // translate the LBA addresses to CHS addresses
    startAddr = LBAtoCHS(&g_FlashInfo, startAddr);
    endAddr = LBAtoCHS(&g_FlashInfo, endAddr);

    // starting address
    partentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);
    partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);
    // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
    partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));

    // ending address:
    partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);
    partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);
    // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
    partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));

    partentry.Part_FirstHead = 0x6;
    partentry.Part_FirstSector = 0x1;
    partentry.Part_FirstTrack = 0x0;
    partentry.Part_LastHead = 0x5;
    partentry.Part_LastSector = 0x21;
    partentry.Part_LastTrack = 0x1;
    
    memcpy(g_pbMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));
    RETAILMSG(1,(TEXT("PART_BINFS flag is 0x%x\n"),PART_BINFS));
    RETAILMSG(1,(TEXT("partentry.Part_BootInd 0x%x\n"),partentry.Part_BootInd));    
    RETAILMSG(1,(TEXT("partentry.Part_FileSystem 0x%x\n"),partentry.Part_FileSystem));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstHead 0x%x\n"),partentry.Part_FirstHead));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstSector 0x%x\n"),partentry.Part_FirstSector));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstTrack 0x%x\n"),partentry.Part_FirstTrack));     
    RETAILMSG(1,(TEXT("partentry.Part_LastHead 0x%x\n"),partentry.Part_LastHead));    
    RETAILMSG(1,(TEXT("partentry.Part_LastSector 0x%x\n"),partentry.Part_LastSector));    
    RETAILMSG(1,(TEXT("partentry.Part_StartSector 0x%x\n"),partentry.Part_StartSector));        
    RETAILMSG(1,(TEXT("partentry.Part_TotalSectors 0x%x\n"),partentry.Part_TotalSectors));            
}


/*  GetPartitionTableIndex
 *
 *  Get the partition index for a particular partition type and active status. 
 *  If partition is not found, then the index of the next free partition in the
 *  partition table of the MBR is returned.
 *  
 *
 *  ENTRY
 *      dwPartType - type of partition 
 *      fActive - TRUE indicates the active partition.  FALSE indicates inactive.
 *
 *  EXIT
 *      pdwIndex - Contains the index of the partition if found.  If not found,
 *          contains the index of the next free partition
 *      returns TRUE if partition found. FALSE if not found.
 */

static BOOL GetPartitionTableIndex (DWORD dwPartType, BOOL fActive, PDWORD pdwIndex)
{
    PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET);
    DWORD iEntry = 0;

/*

    RETAILMSG(1,(TEXT("partentry.Part_BootInd 0x%x\n"),pPartEntry->Part_BootInd));    
    RETAILMSG(1,(TEXT("partentry.Part_FileSystem 0x%x\n"),pPartEntry->Part_FileSystem));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstHead 0x%x\n"),pPartEntry->Part_FirstHead));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstSector 0x%x\n"),pPartEntry->Part_FirstSector));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstTrack 0x%x\n"),pPartEntry->Part_FirstTrack));     
    RETAILMSG(1,(TEXT("partentry.Part_LastHead 0x%x\n"),pPartEntry->Part_LastHead));    
    RETAILMSG(1,(TEXT("partentry.Part_LastSector 0x%x\n"),pPartEntry->Part_LastSector));    
    RETAILMSG(1,(TEXT("partentry.Part_StartSector 0x%x\n"),pPartEntry->Part_StartSector));        
    RETAILMSG(1,(TEXT("partentry.Part_TotalSectors 0x%x\n"),pPartEntry->Part_TotalSectors));       
*/
    RETAILMSG(1, (TEXT("GetPartitionTableIndex: ++ 0x%x\r\n"),dwPartType));
    for (iEntry = 0; iEntry < NUM_PARTS; iEntry++, pPartEntry++) {
        //RETAILMSG(1, (TEXT("GetPartitionTableIndex: pPartEntry->Part_FileSystem : 0x%x\r\n"), pPartEntry->Part_FileSystem));
        
    RETAILMSG(1,(TEXT("partentry.Part_BootInd 0x%x\n"),pPartEntry->Part_BootInd));    
    RETAILMSG(1,(TEXT("partentry.Part_FileSystem 0x%x\n"),pPartEntry->Part_FileSystem));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstHead 0x%x\n"),pPartEntry->Part_FirstHead));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstSector 0x%x\n"),pPartEntry->Part_FirstSector));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstTrack 0x%x\n"),pPartEntry->Part_FirstTrack));     
    RETAILMSG(1,(TEXT("partentry.Part_LastHead 0x%x\n"),pPartEntry->Part_LastHead));    
    RETAILMSG(1,(TEXT("partentry.Part_LastSector 0x%x\n"),pPartEntry->Part_LastSector));    
    RETAILMSG(1,(TEXT("partentry.Part_StartSector 0x%x\n"),pPartEntry->Part_StartSector));        
    RETAILMSG(1,(TEXT("partentry.Part_TotalSectors 0x%x\n"),pPartEntry->Part_TotalSectors));       
        
        if ((pPartEntry->Part_FileSystem == dwPartType) /*&& (((pPartEntry->Part_BootInd & PART_IND_ACTIVE) != 0) == fActive)*/) {
            *pdwIndex = iEntry;
            return TRUE;
        }
        if (!IsValidPart (pPartEntry)) {
            *pdwIndex = iEntry;
            RETAILMSG(1, (TEXT("GetPartitionTableIndex: IsValidPart error\r\n")));
            return FALSE;
        }
    }

    RETAILMSG(1, (TEXT("GetPartitionTableIndex: -- error\r\n")));
    return FALSE;
}

static void AddStoragePartitionTableEntry(DWORD entry, DWORD startSector, DWORD totalSectors, BYTE fileSystem, BYTE bootInd)
{
    PARTENTRY partentry = {0};
    Addr startAddr;
    Addr endAddr;

    ASSERT(entry < 4);
    // no checking with disk info and start/total sectors because we allow
    // bogus partitions for testing purposes

    // initially known partition table entry
    partentry.Part_BootInd = bootInd;
    partentry.Part_FileSystem = fileSystem;
    partentry.Part_StartSector = startSector;
    partentry.Part_TotalSectors = totalSectors;

    // logical block addresses for the first and final sector (start on the second head)
    startAddr.type = LBA;
    startAddr.lba = partentry.Part_StartSector;
    endAddr.type = LBA;
    endAddr.lba = partentry.Part_StartSector + partentry.Part_TotalSectors-1;

    // translate the LBA addresses to CHS addresses
    startAddr = LBAtoCHS(&g_FlashInfo, startAddr);
    endAddr = LBAtoCHS(&g_FlashInfo, endAddr);

    // starting address
    partentry.Part_FirstTrack = (BYTE)(startAddr.chs.cylinder & 0xFF);
    partentry.Part_FirstHead = (BYTE)(startAddr.chs.head & 0xFF);
    // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
    partentry.Part_FirstSector = (BYTE)((startAddr.chs.sector & 0x3F) | ((startAddr.chs.cylinder & 0x0300) >> 2));

    // ending address:
    partentry.Part_LastTrack = (BYTE)(endAddr.chs.cylinder & 0xFF);
    partentry.Part_LastHead = (BYTE)(endAddr.chs.head & 0xFF);
    // lower 6-bits == sector, upper 2-bits = cylinder upper 2-bits of 10-bit cylinder #
    partentry.Part_LastSector = (BYTE)((endAddr.chs.sector & 0x3F) | ((endAddr.chs.cylinder & 0x0300) >> 2));

    partentry.Part_FirstHead = 0x6;
    partentry.Part_FirstSector = 0x1;
    partentry.Part_FirstTrack = 0x0;
    partentry.Part_LastHead = 0x5;
    partentry.Part_LastSector = 0x21;
    partentry.Part_LastTrack = 0x1;
    
    memcpy(g_pbStorageMBRSector+PARTTABLE_OFFSET+(sizeof(PARTENTRY)*entry), &partentry, sizeof(PARTENTRY));
    RETAILMSG(1,(TEXT("PART_BINFS flag is 0x%x\n"),PART_BINFS));
    RETAILMSG(1,(TEXT("partentry.Part_BootInd 0x%x\n"),partentry.Part_BootInd));    
    RETAILMSG(1,(TEXT("partentry.Part_FileSystem 0x%x\n"),partentry.Part_FileSystem));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstHead 0x%x\n"),partentry.Part_FirstHead));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstSector 0x%x\n"),partentry.Part_FirstSector));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstTrack 0x%x\n"),partentry.Part_FirstTrack));     
    RETAILMSG(1,(TEXT("partentry.Part_LastHead 0x%x\n"),partentry.Part_LastHead));    
    RETAILMSG(1,(TEXT("partentry.Part_LastSector 0x%x\n"),partentry.Part_LastSector));    
    RETAILMSG(1,(TEXT("partentry.Part_StartSector 0x%x\n"),partentry.Part_StartSector));        
    RETAILMSG(1,(TEXT("partentry.Part_TotalSectors 0x%x\n"),partentry.Part_TotalSectors));            
}


/*  GetPartitionTableIndex
 *
 *  Get the partition index for a particular partition type and active status. 
 *  If partition is not found, then the index of the next free partition in the
 *  partition table of the MBR is returned.
 *  
 *
 *  ENTRY
 *      dwPartType - type of partition 
 *      fActive - TRUE indicates the active partition.  FALSE indicates inactive.
 *
 *  EXIT
 *      pdwIndex - Contains the index of the partition if found.  If not found,
 *          contains the index of the next free partition
 *      returns TRUE if partition found. FALSE if not found.
 */

static BOOL GetStoragePartitionTableIndex (DWORD dwPartType, BOOL fActive, PDWORD pdwIndex)
{
    PPARTENTRY pPartEntry = (PPARTENTRY)(g_pbStorageMBRSector + PARTTABLE_OFFSET);
    DWORD iEntry = 0;

    RETAILMSG(1, (TEXT("GetPartitionTableIndex: ++ 0x%x\r\n"),dwPartType));
    for (iEntry = 0; iEntry < NUM_PARTS; iEntry++, pPartEntry++) {
        RETAILMSG(1, (TEXT("GetPartitionTableIndex: pPartEntry->Part_FileSystem : 0x%x\r\n"), pPartEntry->Part_FileSystem));
        
        if ((pPartEntry->Part_FileSystem == dwPartType) /*&& (((pPartEntry->Part_BootInd & PART_IND_ACTIVE) != 0) == fActive)*/) {
            *pdwIndex = iEntry;
            return TRUE;
        }
        if (!IsValidPart (pPartEntry)) {
            *pdwIndex = iEntry;
            RETAILMSG(1, (TEXT("GetPartitionTableIndex: IsValidPart error\r\n")));
            return FALSE;
        }
    }

    RETAILMSG(1, (TEXT("GetPartitionTableIndex: -- error\r\n")));
    return FALSE;
}


/* WriteLogicalNumbers
 *
 *  Writes a range of logical sector numbers
 *
 *  ENTRY
 *      dwStartSector - starting logical sector
 *      dwNumSectors - number of logical sectors to mark
 *      fReadOnly - TRUE indicates to mark read-only.  FALSE to mark not read-only
 *
 *  EXIT
 *      TRUE on success
 */


static BOOL WriteLogicalNumbers (DWORD dwStartSector, DWORD dwNumSectors, BOOL fReadOnly)
{
    DWORD dwNumSectorsWritten = 0;

    DWORD dwPhysSector = Log2Phys (dwStartSector);
    DWORD dwBlockNum = dwPhysSector / g_FlashInfo.wSectorsPerBlock;
    DWORD dwOffset = dwPhysSector % g_FlashInfo.wSectorsPerBlock;
    
    while (dwNumSectorsWritten < dwNumSectors) {

    break;
    }
    
    return TRUE;
}




static DWORD Log2Phys (DWORD dwLogSector)
{
    return dwLogSector;    
}



/*  CreatePartition 
 *
 *  Creates a new partition.  If it is a boot section partition, then it formats
 *  flash.
 *
 *  ENTRY
 *      dwStartSector - Logical sector to start the partition.  NEXT_FREE_LOC if  
 *          none specified.  
 *      dwNumSectors - Number of logical sectors of the partition.  USE_REMAINING_SPACE 
 *          to indicate to take up the rest of the space on the flash for that partition.
 *      dwPartType - Type of partition to create.
 *      fActive - TRUE indicates to create the active partition.  FALSE for
 *          inactive.
 *      dwPartIndex - Index of the partition entry on the MBR
 *
 *  EXIT
 *      Handle to the partition on success.  INVALID_HANDLE_VALUE on error.
 */

static HANDLE CreatePartition (DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwPartIndex)
{
    DWORD dwBootInd = 0;

    if (fActive)
        dwBootInd |= PART_IND_ACTIVE;
    if (dwPartType == PART_BOOTSECTION || dwPartType == PART_BINFS || dwPartType == PART_XIP)
        dwBootInd |= PART_IND_READ_ONLY;       

    RETAILMSG(1, (TEXT("CreatePartition: Enter CreatePartition for 0x%x.\r\n"), dwPartType));

    RETAILMSG(1, (TEXT("CreatePartition: Start = 0x%x, Num = 0x%x.\r\n"), dwStartSector, dwNumSectors));

    AddPartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);

    RETAILMSG(1,(TEXT("Write MBR start.\n")));
    if (!WriteMBR())
        return INVALID_HANDLE_VALUE;
    RETAILMSG(1,(TEXT("Write MBR End.\n")));
    g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
    g_partStateTable[dwPartIndex].dwDataPointer = 0;


    RETAILMSG(1, (TEXT("CreatePartition Finished \r\n\n\n\n")));
    return (HANDLE)&g_partStateTable[dwPartIndex];            
}


static HANDLE CreateStoragePartition (DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwPartIndex)
{
    DWORD dwBootInd = 0;

    if (fActive)
        dwBootInd |= PART_IND_ACTIVE;
    if (dwPartType == PART_BOOTSECTION || dwPartType == PART_BINFS || dwPartType == PART_XIP)
        dwBootInd |= PART_IND_READ_ONLY;       

    RETAILMSG(1, (TEXT("CreateStoragePartition: Enter CreatePartition for 0x%x.\r\n"), dwPartType));

    RETAILMSG(1, (TEXT("CreateStoragePartition: Start = 0x%x, Num = 0x%x.\r\n"), dwStartSector, dwNumSectors));
    
    AddStoragePartitionTableEntry (dwPartIndex, dwStartSector, dwNumSectors, (BYTE)dwPartType, (BYTE)dwBootInd);

    RETAILMSG(1,(TEXT("Write MBR start.\n")));
    if (!WriteStorageMBR())
        return INVALID_HANDLE_VALUE;

    RETAILMSG(1,(TEXT("Write MBR End.\n")));
    g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbStorageMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
    g_partStateTable[dwPartIndex].dwDataPointer = 0;

    return (HANDLE)&g_partStateTable[dwPartIndex];            
}


/*  BP_ReadData
 *
 *  Reads data from the partition starting at the data pointer.  Call fails
 *  if length of the buffer is too long (i.e. trying to read past the end
 *  of the partition)
 *
 *  ENTRY
 *      hPartition - handle to the partition
 *      pbBuffer - pointer to buffer of data to read
 *      dwLength - number of bytes to read
 *
 *  EXIT
 *      TRUE on success
 */

BYTE g_BufTemp[BUF_TEMP_SIZE];

BOOL BP_ReadData(HANDLE hPartition, LPBYTE pbBuffer, DWORD dwLength)
{
#if 1
    if (hPartition == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }

    static LPBYTE pbSector = g_pbBlock;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;
	DWORD dwStartSector, dwSectors, i, dwSecTemp;

    if (!pbBuffer || !pbSector || dwLength == 0)
    {
        return(FALSE);
    }

    RETAILMSG(1, (TEXT("[BP:INF] ReadData: Start = 0x%x, Length = 0x%x.\r\n"), pPartState->dwDataPointer, dwLength));

    // Check to make sure buffer size is within limits of partition
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors) {
        RETAILMSG(1, (TEXT("[BP:ERR] ReadData: trying to read past end of partition.\r\n")));
        return FALSE;
    }

    if ( pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector != 0 )
    {
    	dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + 1;
    }
    else
    {
    	dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector;
    }

    if ( dwLength % g_FlashInfo.wDataBytesPerSector != 0 )
    {
    	dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector + 1;
    }
    else
    {
    	dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector;
    }

	RETAILMSG(1,(TEXT("[BP:INF] Load Image to 0x%x from sector 0x%x  to sector 0x%x\n"),
					pbBuffer,dwStartSector+IMAGESTARTSECTOR, dwSectors));
#if 0
	if (!SDHC_READ(dwStartSector+IMAGESTARTSECTOR, dwSectors, (UINT32)pbBuffer))
	{
    	RETAILMSG(_ERR_,(TEXT("[BP:ERR] Failed to Load Image from SDMMC\n")));
        return (FALSE);
	}

#else
	if (dwSectors < 512)
	{
		SDHC_READ(dwStartSector+IMAGESTARTSECTOR, dwSectors, (UINT32)pbBuffer);
	}
	else
	{
		for ( i = 0 ,  dwSecTemp = dwSectors; dwSecTemp >= MAX_WRITE_SECTOR ; i++ , dwSecTemp -= MAX_WRITE_SECTOR)
		{
			SDHC_READ(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), MAX_WRITE_SECTOR, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));
		}

		if ( dwSecTemp != 0 )
		{
			SDHC_READ(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), dwSecTemp, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));
		}
	}
#endif

    pPartState->dwDataPointer = dwNextPtrValue;
    return (TRUE);
#else
    if (hPartition == INVALID_HANDLE_VALUE)
    {
        return FALSE;
    }
    
    DWORD dwSectors;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;
    UINT8 pTemp[SDMMC_SECTOR_SIZE];
    DWORD dwTotalRead,dwOriLength = dwLength;

    if (!pbBuffer || dwLength == 0)
    {
        RETAILMSG(1, (TEXT("ReadData: Start = 0x%x, Length = 0x%x.\r\n"), pPartState->dwDataPointer, dwLength));
        return(FALSE);
    }

    //RETAILMSG(1,(TEXT("BP_ReadData: Start = 0x%x, Length = 0x%x.\r\n"), pPartState->dwDataPointer, dwLength));

    // Check to make sure buffer size is within limits of partition
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors) 
    {
        RETAILMSG(1, (TEXT("ReadData: trying to read past end of partition.\r\n")));
        return FALSE;
    }

    // Get the starting physical sector
    DWORD dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + pPartState->pPartEntry->Part_StartSector;

    // If current pointer is not on a sector boundary, copy bytes up to the first sector boundary
    DWORD dwOffsetSector = pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector;
    if (dwOffsetSector)
    {
        if (!SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector, 1*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)pTemp))
        {
            RETAILMSG(1, (TEXT("ReadData: failed to read sector (0x%x).\r\n"), dwStartSector));
            return(FALSE);
        }
        
        DWORD dwNumBytesRead = g_FlashInfo.wDataBytesPerSector - dwOffsetSector;
        if (dwNumBytesRead > dwLength)
        {
            dwNumBytesRead = dwLength;
        }
        
        memcpy(pbBuffer, pTemp + dwOffsetSector, dwNumBytesRead);
        dwLength -= dwNumBytesRead;
        pbBuffer += dwNumBytesRead;
        dwStartSector++;
        dwTotalRead = dwNumBytesRead;
    }

    // Compute sector length.
    dwSectors = (dwLength / g_FlashInfo.wDataBytesPerSector);

    if (dwSectors)
    {
        if ( (UINT32)pbBuffer % 4 != 0 )// if it is not aligned by 4byte. 
        {                                // SDHC_READ function can not accept that buffer not aligned.
            DWORD dwTemp;
            //RETAILMSG(1,(TEXT("### BP_ReadData()::It is not aligned by 4 dwSectors = %d 0x%x 0x%x\r\n"),dwSectors,pbBuffer,pbBuffer));

            DWORD dwTempBufSectors = (BUF_TEMP_SIZE / g_FlashInfo.wDataBytesPerSector);
            for ( dwTemp = 0 ; (dwTemp+1) * dwTempBufSectors < dwSectors  ; dwTemp++ )
            {
                SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector + dwTemp * dwTempBufSectors * (g_FlashInfo.wDataBytesPerSector>>9), 
                                    dwTempBufSectors*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)g_BufTemp);
                memcpy ( pbBuffer, g_BufTemp, BUF_TEMP_SIZE );
                pbBuffer += BUF_TEMP_SIZE;                
            }

            //RETAILMSG(1,(TEXT("### BP_ReadData()::It is not aligned by 4 dwTemp = %d\r\n"),dwTemp));
            if ( dwTemp * dwTempBufSectors < dwSectors )
            {
                DWORD dwReadOffset = (dwSectors - (dwTemp * dwTempBufSectors)) * g_FlashInfo.wDataBytesPerSector ; 
                SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector + dwTemp * dwTempBufSectors * (g_FlashInfo.wDataBytesPerSector>>9), 
                                    (dwSectors - (dwTemp * dwTempBufSectors)*(g_FlashInfo.wDataBytesPerSector>>9)), (UINT32)g_BufTemp);
                memcpy ( pbBuffer, g_BufTemp, dwReadOffset);                    
                pbBuffer += dwReadOffset;            
            }
        }
        else
        {
            SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector, dwSectors*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)pbBuffer);
            pbBuffer += (dwSectors * g_FlashInfo.wDataBytesPerSector);
        }
    }

    DWORD dwNumExtraBytes = (dwLength % g_FlashInfo.wDataBytesPerSector);
    if (dwNumExtraBytes)
    {
        dwStartSector += (dwLength / g_FlashInfo.wDataBytesPerSector);
        SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector, 
                            1*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)g_BufTemp);
        memcpy(pbBuffer, g_BufTemp, dwNumExtraBytes);
        dwTotalRead+=dwNumExtraBytes;
    }

    pPartState->dwDataPointer = dwNextPtrValue;
    return (TRUE);

#if 0    
    if (hPartition == INVALID_HANDLE_VALUE)
        return FALSE;

//    DWORD dwNumSects, dwBlockAddress;
    static LPBYTE pbSector = g_pbBlock;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;
    DWORD dwStartSector, dwSectors;
    UINT8 pTemp[SDMMC_SECTOR_SIZE];
    
     
    if (!pbBuffer || !pbSector || dwLength == 0)
        return(FALSE);

    //RETAILMSG (1, (TEXT("ReadData: Start = 0x%x, Length = 0x%x. PartStart = 0x%x\r\n"), pPartState->dwDataPointer, dwLength, pPartState->pPartEntry->Part_StartSector));

    // Check to make sure buffer size is within limits of partition
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors) {
        RETAILMSG (1, (TEXT("ReadData: trying to read past end of partition.\r\n")));
        return FALSE;
    }

#if 0
    RETAILMSG(1,(TEXT("PART_BINFS flag is 0x%x\n"),PART_BINFS));
    RETAILMSG(1,(TEXT("partentry.Part_BootInd 0x%x\n"),pPartState->pPartEntry->Part_BootInd));    
    RETAILMSG(1,(TEXT("partentry.Part_FileSystem 0x%x\n"),pPartState->pPartEntry->Part_FileSystem));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstHead 0x%x\n"),pPartState->pPartEntry->Part_FirstHead));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstSector 0x%x\n"),pPartState->pPartEntry->Part_FirstSector));    
    RETAILMSG(1,(TEXT("partentry.Part_FirstTrack 0x%x\n"),pPartState->pPartEntry->Part_FirstTrack));     
    RETAILMSG(1,(TEXT("partentry.Part_LastHead 0x%x\n"),pPartState->pPartEntry->Part_LastHead));    
    RETAILMSG(1,(TEXT("partentry.Part_LastSector 0x%x\n"),pPartState->pPartEntry->Part_LastSector));    
    RETAILMSG(1,(TEXT("partentry.Part_StartSector 0x%x\n"),pPartState->pPartEntry->Part_StartSector));        
    RETAILMSG(1,(TEXT("partentry.Part_TotalSectors 0x%x\n"),pPartState->pPartEntry->Part_TotalSectors));            
#endif    

    DWORD dwOffsetSector = pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector;
    DWORD dwByteRead = g_FlashInfo.wDataBytesPerSector - dwOffsetSector;
    DWORD dwRemainByte = 0;
    DWORD dwNewlenght = dwLength;
    PBYTE    pbNewbuf = pbBuffer;
    DWORD dwTemp;

    dwStartSector = (pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector) + 
                    pPartState->pPartEntry->Part_StartSector;


    // if Datapointer is not from start of the sector ( it means it is not divided by Sector size )
    // We should copy it as belows.
    if ( dwOffsetSector != 0 )
    {
        SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector, 1*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)pTemp);
        if (dwByteRead > dwNewlenght )
            dwByteRead = dwNewlenght;
        memcpy(pbNewbuf, pTemp+dwOffsetSector, dwByteRead );
        pbNewbuf += dwByteRead;
        dwNewlenght -= dwByteRead;
        dwStartSector++;
    }

    //RETAILMSG(1,(TEXT("dwlength 0x%x from dwbyteread 0x%x dwstartsector  0x%x\n"),
    //                        dwLength, dwByteRead,dwStartSector));
    
    dwSectors =  dwNewlenght / g_FlashInfo.wDataBytesPerSector;

       dwRemainByte = dwNewlenght % g_FlashInfo.wDataBytesPerSector;

    //RETAILMSG(1,(TEXT("dwSectors 0x%x from dwRemainByte 0x%x \n"),
    //                        dwSectors, dwRemainByte));


    if ( (UINT32)pbNewbuf % 4 != 0 )// if it is not aligned by 4byte. 
    {                                // SDHC_READ function can not accept that buffer not aligned.
        RETAILMSG(1,(TEXT("### BP_ReadData()::It is not aligned by 4 dwSectors = %d 0x%x 0x%x\r\n"),dwSectors,pbBuffer,pbNewbuf));
        if ( dwSectors > 0 )
        {
            DWORD dwTempBufSectors = (BUF_TEMP_SIZE / g_FlashInfo.wDataBytesPerSector);
            for ( dwTemp = 0 ; (dwTemp+1) * dwTempBufSectors < dwSectors  ; dwTemp++ )
            {
                SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector + dwTemp * dwTempBufSectors * (g_FlashInfo.wDataBytesPerSector>>9), 
                                    dwTempBufSectors*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)g_BufTemp);
                memcpy ( pbNewbuf, g_BufTemp, BUF_TEMP_SIZE );
                pbNewbuf += BUF_TEMP_SIZE;                
            }

            //RETAILMSG(1,(TEXT("### BP_ReadData()::It is not aligned by 4 dwTemp = %d\r\n"),dwTemp));
            if ( dwTemp * dwTempBufSectors < dwSectors )
            {
                DWORD dwReadOffset = (dwSectors - (dwTemp * dwTempBufSectors)) * g_FlashInfo.wDataBytesPerSector ; 
                SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector + dwTemp * dwTempBufSectors * (g_FlashInfo.wDataBytesPerSector>>9), 
                                    (dwSectors - (dwTemp * dwTempBufSectors)*(g_FlashInfo.wDataBytesPerSector>>9)), (UINT32)g_BufTemp);
                memcpy ( pbNewbuf, g_BufTemp, dwReadOffset);                    
                pbNewbuf += dwReadOffset;            
            }
            
        }
    }
    else
    {
        if ( dwSectors > 0 )
        {
            SDHC_READ((dwStartSector*(g_FlashInfo.wDataBytesPerSector>>9))+g_AddressInfoSector.dwFlashImageStartSector, dwSectors*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)pbNewbuf);
            pbNewbuf += (dwSectors * g_FlashInfo.wDataBytesPerSector);
        }
    }
    
    if ( dwRemainByte > 0 )
    {
        SDHC_READ((dwStartSector+dwSectors)*(g_FlashInfo.wDataBytesPerSector>>9)+g_AddressInfoSector.dwFlashImageStartSector, 1*(g_FlashInfo.wDataBytesPerSector>>9), (UINT32)pTemp);
        memcpy( pbNewbuf, pTemp, dwRemainByte );                            
    }

    RETAILMSG(1,(TEXT(".")));

    pPartState->dwDataPointer = dwNextPtrValue;
    return(TRUE);
#endif

#endif
}

/*  BP_WriteData
 *
 *  Writes data to the partition starting at the data pointer.  Call fails
 *  if length of the buffer is too long (i.e. trying to write past the end
 *  of the partition)
 *
 *  ENTRY
 *      hPartition - handle to the partition
 *      pbBuffer - pointer to buffer of data to write
 *      dwLength - length in bytes of the buffer
 *
 *  EXIT
 *      TRUE on success
 */

BOOL BP_WriteData(HANDLE hPartition, LPBYTE pbBuffer, DWORD dwLength)
{
#if 1
 if (hPartition == INVALID_HANDLE_VALUE)
        return FALSE;

    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;
    DWORD dwStartSector;
    DWORD dwSectors;
    DWORD i,dwSecTemp;

    RETAILMSG(1, (TEXT("[BP:INF] WriteData: Start = 0x%x, Length = 0x%x.\r\n"), pPartState->dwDataPointer, dwLength));

    if (!pbBuffer || !g_pbBlock || dwLength == 0)
    {
        RETAILMSG(1,(TEXT("[BP:ERR] BP_WriteData Fails.  pbBuffer = 0x%x, g_pbBlock = 0x%x, dwLength = 0x%x\r\n"), pbBuffer, g_pbBlock, dwLength));
        return(FALSE);
    }

    // Check to make sure buffer size is within limits of partition
    RETAILMSG(1, (TEXT("[BP:INF] WriteData: writing sector number = 0x%x.\r\n"),((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector)));
    RETAILMSG(1, (TEXT("[BP:INF] WriteData: partition total sector number = 0x%x.\r\n"), pPartState->pPartEntry->Part_TotalSectors));
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors)
    {
        RETAILMSG(1, (TEXT("[BP:ERR] WriteData: trying to write past end of partition.\r\n")));
        return FALSE;
    }

    if ( pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector != 0 )
    {
    	dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + 1;
        RETAILMSG(1, (TEXT("[BP:INF] WriteData: dwDataPointer is not divided by 512 #1 dwStartSector 0x%x\r\n"),dwStartSector));
    }
    else
    {
    	dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector;
		RETAILMSG(1, (TEXT("[BP:INF] WriteData: dwDataPointer is divided by 512 #1 dwStartSector 0x%x\r\n"),dwStartSector));
	}

    if ( dwLength % g_FlashInfo.wDataBytesPerSector != 0 )
    {
    	dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector + 1;
        RETAILMSG(1, (TEXT("[BP:INF] WriteData: dwLength is not divided by 512 #1 dwSectors 0x%x\r\n"),dwSectors));
    }
    else
    {
    	dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector;
    	dwNextPtrValue = pPartState->dwDataPointer + dwSectors * 512;
		RETAILMSG(1, (TEXT("[BP:INF] WriteData: dwLength is divided by 512 #1 dwSectors 0x%x\r\n"),dwSectors));
	}

    g_dwLastWrittenLoc = (dwStartSector+IMAGESTARTSECTOR) * 512;

	RETAILMSG(1, (TEXT("[BP:INF] WriteData: dwStartsector 0x%x, sectors 0x%x, pbBuffer 0x%x\n"),dwStartSector,dwSectors,pbBuffer));

	if (dwSectors < 512)
	{
		SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR, dwSectors, (UINT32)pbBuffer);
	}
	else
	{
		for ( i = 0 ,  dwSecTemp = dwSectors; dwSecTemp >= MAX_WRITE_SECTOR ; i++ , dwSecTemp -= MAX_WRITE_SECTOR)
		{
			SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), MAX_WRITE_SECTOR, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));
		}

		if ( dwSecTemp != 0 )
		{
			SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), dwSecTemp, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));
		}
	}

    pPartState->dwDataPointer = dwNextPtrValue;
    return(TRUE);
#else
    if (hPartition == INVALID_HANDLE_VALUE)
        return FALSE;
    
    //DWORD dwNumBlocks;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;
    DWORD dwNextPtrValue = pPartState->dwDataPointer + dwLength;
    DWORD dwStartSector;
    DWORD dwSectors;
    DWORD i,dwSecTemp;

    RETAILMSG (1, (TEXT("++BP_WriteData: Start = 0x%x, Length = 0x%x.\r\n"), pPartState->dwDataPointer, dwLength));

    if (!pbBuffer || !g_pbBlock || dwLength == 0) {
        RETAILMSG(1,(TEXT("BP_WriteData Fails.  pbBuffer = 0x%x, g_pbBlock = 0x%x, dwLength = 0x%x\r\n"), pbBuffer, g_pbBlock, dwLength));
        return(FALSE);
    }

    // Check to make sure buffer size is within limits of partition
    RETAILMSG (1, (TEXT("WriteData: writing sector number = 0x%x.\r\n"),((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector)));
    RETAILMSG (1, (TEXT("WriteData: partition total sector number = 0x%x.\r\n"), pPartState->pPartEntry->Part_TotalSectors));
    if (((dwNextPtrValue - 1) / g_FlashInfo.wDataBytesPerSector) >= pPartState->pPartEntry->Part_TotalSectors) {
        RETAILMSG (1, (TEXT("WriteData: trying to write past end of partition.\r\n")));
        return FALSE;
    }


    if ( pPartState->dwDataPointer % g_FlashInfo.wDataBytesPerSector != 0 )
    {
        dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector + 1;
        //RETAILMSG (1, (TEXT("dwDataPointer is not divided by 512 #1 dwStartSector 0x%x\r\n"),dwStartSector));        
    }
    else
    {
        dwStartSector = pPartState->dwDataPointer / g_FlashInfo.wDataBytesPerSector;
        //RETAILMSG (1, (TEXT("dwDataPointer is divided by 512 #1 dwStartSector 0x%x\r\n"),dwStartSector));        
    }

    if ( dwLength % g_FlashInfo.wDataBytesPerSector != 0 )
    {
        dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector + 1;
        //RETAILMSG (1, (TEXT("dwLength is not divided by 512 #1 dwSectors 0x%x\r\n"),dwSectors));                
    }
    else
    {
        dwSectors = dwLength / g_FlashInfo.wDataBytesPerSector;
        dwNextPtrValue = pPartState->dwDataPointer + dwSectors * 512;
        //RETAILMSG (1, (TEXT("dwLength is divided by 512 #1 dwSectors 0x%x\r\n"),dwSectors));                
    }

   //g_dwLastWrittenLoc = dwStartSector+(g_AddressInfoSector.dwFlashImageStartSector+1) * 512;
      g_dwLastWrittenLoc = (dwStartSector+IMAGESTARTSECTOR) * 512;
      
    RETAILMSG (1, (TEXT("KSH partition total sector number = 0x%x 0x%x 0x%x.\r\n"), pbBuffer[0],pbBuffer[1],pbBuffer[2]));
    if (dwSectors < 512 )
    {
        SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR, dwSectors, (UINT32)pbBuffer);    
    }
    else
    {
        for ( i = 0 ,  dwSecTemp = dwSectors; dwSecTemp >= MAX_WRITE_SECTOR ; i++ , dwSecTemp -= MAX_WRITE_SECTOR)
        {
            SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), MAX_WRITE_SECTOR, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));        
        }

        if ( dwSecTemp != 0 )
        {
            SDHC_WRITE(dwStartSector+IMAGESTARTSECTOR+(i*MAX_WRITE_SECTOR), dwSecTemp, (UINT32)pbBuffer+(UINT32)(i*SECTOR_PER_SECTOR*MAX_WRITE_SECTOR));
        }
    }
    
    
    pPartState->dwDataPointer = dwNextPtrValue;

#endif
    RETAILMSG(1,(TEXT(".")));    
    return(TRUE);
}

/*  BP_OpenPartition 
 *
 *  Opens/creates a partition depending on the creation flags.  If it is opening
 *  and the partition has already been opened, then it returns a handle to the
 *  opened partition.  Otherwise, it loads the state information of that partition
 *  into memory and returns a handle.  
 *
 *  ENTRY
 *      dwStartSector - Logical sector to start the partition.  NEXT_FREE_LOC if none 
 *          specified.  Ignored if opening existing partition.
 *      dwNumSectors - Number of logical sectors of the partition.  USE_REMAINING_SPACE 
 *          to indicate to take up the rest of the space on the flash for that partition (should
 *          only be used when creating extended partitions).  This parameter is ignored
 *          if opening existing partition.
 *      dwPartType - Type of partition to create/open.
 *      fActive - TRUE indicates to create/open the active partition.  FALSE for
 *          inactive.
 *      dwCreationFlags - PART_CREATE_NEW to create only.  Fail if it already 
 *          exists.  PART_OPEN_EXISTING to open only.  Fail if it doesn't exist.
 *          PART_OPEN_ALWAYS creates if it does not exist and opens if it
 *          does exist.
 *
 *  EXIT
 *      Handle to the partition on success.  INVALID_HANDLE_VALUE on error.
 */

HANDLE BP_OpenPartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
{
        DWORD dwPartIndex;
        BOOL fExists;
//        INT32 nErr;
    
        ASSERT (g_pbMBRSector);
        
        if(dwPartType == PART_BINFS)
                    RETAILMSG(1, (TEXT("++BP_OpenPartition(PART_BINFS) :PART TYPE: %d\r\n"),dwPartType));
          else
                     RETAILMSG(1, (TEXT("++BP_OpenPartition(PART_DOS32) :PART TYPE: %d\r\n"),dwPartType));
            
        if (!IsValidMBR()) {
            DWORD dwFlags = 0;

            if (dwCreationFlags == PART_OPEN_EXISTING) {
                RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Cannot open existing partition 0x%x.\r\n"), dwPartType));
                return INVALID_HANDLE_VALUE;
            }
            
            RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Create a new MBR for moviBoot.\r\n")));

            BP_LowLevelFormat (0, 0, 0); // It does not format. just for creating MBR.
            dwPartIndex = 0;
            fExists = FALSE;
        }
        else {
            fExists = GetPartitionTableIndex(dwPartType, fActive, &dwPartIndex);        
        }

        RETAILMSG(1, (TEXT("OpenPartition: Partition Exists=0x%x for part 0x%x.\r\n"), fExists, dwPartType));
        if (fExists) {

            // Partition was found.  
            if (dwCreationFlags == PART_CREATE_NEW)
                return INVALID_HANDLE_VALUE;
            
            if (g_partStateTable[dwPartIndex].pPartEntry == NULL) {
                
                // Open partition.  If this is the boot section partition, then file pointer starts after MBR
                g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
                g_partStateTable[dwPartIndex].dwDataPointer = 0;
            }
            return (HANDLE)&g_partStateTable[dwPartIndex];            
        }
        else {

            // If there are already 4 partitions, or creation flag specified OPEN_EXISTING, fail.
            if ((dwPartIndex == NUM_PARTS) || (dwCreationFlags == PART_OPEN_EXISTING))
                return INVALID_HANDLE_VALUE;

            // Create new partition
            RETAILMSG(1,(TEXT("Can not find appropriate partition\n")));
            RETAILMSG(1,(TEXT("Create partition from 0x%x to 0x%x\n"),dwStartSector,dwNumSectors));
            return CreatePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
        }

        return INVALID_HANDLE_VALUE;
        
}
BOOL BP_LowLevelStorageFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
{

    RETAILMSG(1,(TEXT("BP_LowLevelFormat: moviNAND does not need to be erased before fusing IMAGE\r\n")));
    // MBR goes in the first sector of the starting block.  This will be logical sector 0.
    g_dwStorageMBRSectorNum = 0;

    // Create an MBR.
    CreateStorageMBR();

    RETAILMSG (1, (TEXT("MBR is written successfully.\r\n\r\n")));
    return(TRUE);
}




HANDLE BP_OpenStoragePartition(DWORD dwStartSector, DWORD dwNumSectors, DWORD dwPartType, BOOL fActive, DWORD dwCreationFlags)
{
        DWORD dwPartIndex;
        BOOL fExists;
//        INT32 nErr;
    
        ASSERT (g_pbStorageMBRSector);
        
        if (!IsValidStorageMBR()) {
            DWORD dwFlags = 0;

            if (dwCreationFlags == PART_OPEN_EXISTING) {
                RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Cannot open existing partition 0x%x.\r\n"), dwPartType));
                return INVALID_HANDLE_VALUE;
            }
            
            RETAILMSG(1, (TEXT("OpenPartition: Invalid MBR.  Create a new MBR for moviBoot.\r\n")));

            BP_LowLevelStorageFormat (0, 0, 0); // It does not format. just for creating MBR.
            dwPartIndex = 0;
            fExists = FALSE;
        }
        else {
            fExists = GetStoragePartitionTableIndex(dwPartType, fActive, &dwPartIndex);        
        }

        RETAILMSG(1, (TEXT("OpenPartition: Partition Exists=0x%x for part 0x%x.\r\n"), fExists, dwPartType));
        if (fExists) {

            // Partition was found.  
            if (dwCreationFlags == PART_CREATE_NEW)
                return INVALID_HANDLE_VALUE;
            
            if (g_partStateTable[dwPartIndex].pPartEntry == NULL) {
                
                // Open partition.  If this is the boot section partition, then file pointer starts after MBR
                g_partStateTable[dwPartIndex].pPartEntry = (PPARTENTRY)(g_pbStorageMBRSector + PARTTABLE_OFFSET + sizeof(PARTENTRY)*dwPartIndex);
                g_partStateTable[dwPartIndex].dwDataPointer = 0;
            }
            return (HANDLE)&g_partStateTable[dwPartIndex];            
        }
        else {

            // If there are already 4 partitions, or creation flag specified OPEN_EXISTING, fail.
            if ((dwPartIndex == NUM_PARTS) || (dwCreationFlags == PART_OPEN_EXISTING))
                return INVALID_HANDLE_VALUE;

            // Create new partition
            RETAILMSG(1,(TEXT("Can not find appropriate partition\n")));
            RETAILMSG(1,(TEXT("Create partition from 0x%x to 0x%x\n"),dwStartSector,dwNumSectors));
            return CreateStoragePartition (dwStartSector, dwNumSectors, dwPartType, fActive, dwPartIndex);
        }

        return INVALID_HANDLE_VALUE;
        
}


/*  BP_SetDataPointer 
 *
 *  Sets the data pointer of a particular partition.  Data pointer stores the logical
 *  byte address where the next read or write will occur.
 *
 *  ENTRY
 *      hPartition - handle to the partition
 *      dwAddress - Address to set data pointer to
 *
 *  EXIT
 *      TRUE on success
 */

BOOL BP_SetDataPointer (HANDLE hPartition, DWORD dwAddress)
{
    if (hPartition == INVALID_HANDLE_VALUE)
        return FALSE;

    PPARTSTATE pPartState = (PPARTSTATE) hPartition;

    if (dwAddress >= pPartState->pPartEntry->Part_TotalSectors * (SDMMC_SECTOR_SIZE))
        return FALSE;
    
    pPartState->dwDataPointer = dwAddress;
    return TRUE;
   
}


/*  BP_GetPartitionInfo
 *
 *  Get the partition entry for an open partition.
 *
 *  ENTRY
 *      hPartition - handle to the partition
 *
 *  EXIT
 *      The partition entry
 */

PPARTENTRY BP_GetPartitionInfo (HANDLE hPartition)
{
    if (!hPartition)
        return NULL;
    
    return ((PPARTSTATE)hPartition)->pPartEntry;
}


/*  BP_Storage_Init 
 *
 *  Sets up locations for various objects in memory provided by caller
 *
 *  ENTRY
 *      pMemory - pointer to memory for storing objects
 *      dwSize - size of the memory
 *      lpActiveReg - used by FMD_Init. NULL if not needed.
 *      pRegIn - used by FMD_Init. NULL if not needed.
 *      pRegOut - used by FMD_Init. NULL if not needed.
 *
 *  EXIT
 *      TRUE on success
 */

BOOL BP_Storage_Init (LPBYTE pMemory, DWORD dwSize, LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
    DWORD dwBufferSize;

    RETAILMSG(1,(TEXT("BP_Storage_Init++\r\n")));

    if (!pMemory) {
        RETAILMSG(1,(TEXT("BP_Storage_Init Fails No memory fails!!!\r\n")));
        return FALSE;
    }
    else {
        RETAILMSG(1,(TEXT("BP_Storage_Init] pMemory=0x%x\r\n"),pMemory));
    }
    
    // Check to make sure size is enough for one sector, one block, and sectorinfo buffer for one block
    g_pbStorageMBRSector = pMemory;  //size = g_FlashInfo.wDataBytesPerSector;
    g_dwLastLogSector = 0;

    RETAILMSG(1,(TEXT("BP_Storage_Init] g_pbMBRSector=0x%x\r\n"),g_pbStorageMBRSector));

    RETAILMSG(1,(TEXT("BP_Storage_Init--\r\n")));

    return TRUE;
}


/*  BP_Init 
 *
 *  Sets up locations for various objects in memory provided by caller
 *
 *  ENTRY
 *      pMemory - pointer to memory for storing objects
 *      dwSize - size of the memory
 *      lpActiveReg - used by FMD_Init. NULL if not needed.
 *      pRegIn - used by FMD_Init. NULL if not needed.
 *      pRegOut - used by FMD_Init. NULL if not needed.
 *
 *  EXIT
 *      TRUE on success
 */

BOOL BP_Init (LPBYTE pMemory, DWORD dwSize, LPCTSTR lpActiveReg, PPCI_REG_INFO pRegIn, PPCI_REG_INFO pRegOut)
{
    DWORD dwBufferSize;

    RETAILMSG(1,(TEXT("BP_Init++\r\n")));

    if (!pMemory) {
        RETAILMSG(1,(TEXT("BP_Init Fails No memory fails!!!\r\n")));
        return FALSE;
    }
    else {
        RETAILMSG(1,(TEXT("BP_Init] pMemory=0x%x\r\n"),pMemory));
    }
    
    // Check to make sure size is enough for one sector, one block, and sectorinfo buffer for one block

    g_FlashInfo.flashType = NAND;
    g_FlashInfo.dwNumBlocks = g_AddressInfoSector.dwFlashImageTotalSector/1024;        // to sync bootpart
    g_FlashInfo.wSectorsPerBlock = 128;
    g_FlashInfo.wDataBytesPerSector = SDMMC_SECTOR_SIZE;
    g_FlashInfo.dwBytesPerBlock = (g_FlashInfo.wSectorsPerBlock)*(g_FlashInfo.wDataBytesPerSector);    
    
    g_dwDataBytesPerBlock = g_FlashInfo.wDataBytesPerSector * g_FlashInfo.wSectorsPerBlock;
    dwBufferSize = g_FlashInfo.wDataBytesPerSector + g_dwDataBytesPerBlock + 
        g_FlashInfo.wSectorsPerBlock * sizeof(SectorInfo);

/* it dose not mean anything. SDMMC card dose not need any BLOCK buffer.
    if (dwSize < dwBufferSize) {
        RETAILMSG(1,(TEXT("BP_Init Fails buffer size = %x < required = %x!!!\r\n"),dwSize,dwBufferSize));
        return FALSE;
    }
*/
    
    for (int i = 0; i < NUM_PARTS; i++) {
        g_partStateTable[i].pPartEntry= NULL;
        g_partStateTable[i].dwDataPointer = 0;
    }
   
    g_pbMBRSector = pMemory;  //size = g_FlashInfo.wDataBytesPerSector;
    g_pbBlock = pMemory + g_FlashInfo.wDataBytesPerSector;  //size = g_dwDataBytesPerBlock;
    g_pSectorInfoBuf = (PSectorInfo)(g_pbBlock + g_dwDataBytesPerBlock);  //size = g_FlashInfo.wSectorsPerBlock * sizeof(SectorInfo);
    g_dwLastLogSector = 0;

    RETAILMSG(1,(TEXT("BP_Init] g_pbMBRSector=0x%x\r\n"),g_pbMBRSector));
    RETAILMSG(1,(TEXT("BP_Init] g_pbBlock=0x%x\r\n"),g_pbBlock));
    RETAILMSG(1,(TEXT("BP_Init] g_pSectorInfoBuf=0x%x\r\n"),g_pSectorInfoBuf));

    RETAILMSG(1,(TEXT("BP_Init--\r\n")));

    return TRUE;
}



/*  BP_LowLevelFormat 
 *
 *  Called when preparing flash for a multiple-BIN download. 
 *  Erases, verifies, and writes logical sector numbers in the range to be written.
 *
 *  ENTRY
 *      dwStartBlock - starting physical block for format
 *      dwNumBlocks - number of physical blocks to format
 *      dwFlags - Flags used in formatting.
 *
 *  EXIT
 *      TRUE returned on success and FALSE on failure.
 */

BOOL BP_LowLevelFormat(DWORD dwStartBlock, DWORD dwNumBlocks, DWORD dwFlags)
{
#if 0
    RETAILMSG(1,(TEXT("BP_LowLevelFormat: moviNAND does not need to be erased before fusing IMAGE\r\n")));
    // MBR goes in the first sector of the starting block.  This will be logical sector 0.
    g_dwMBRSectorNum = g_AddressInfoSector.dwFlashImageStartSector;

    // Create an MBR.
    CreateMBR();

    RETAILMSG (1, (TEXT("MBR is written successfully.\r\n\r\n")));
#else
    RETAILMSG(1,(TEXT("\n\n\n[BP:INF] BP_LowLevelFormat: SD/MMC card does not need to be erased before fusing IMAGE\r\n")));
    // MBR goes in the first sector of the starting block.  This will be logical sector 0.
    g_dwMBRSectorNum = MBRSTARTSECTOR;

	// Create an MBR.
    CreateMBR();

    RETAILMSG (1, (TEXT("[BP:INF] MBR is written successfully.\r\n\n\n")));
#endif
    return(TRUE);
}




typedef struct
{
    GUID guidReserved;
    DWORD dwReserved1;
    DWORD dwReserved2;
    DWORD dwReserved3;
    DWORD dwReserved4;
    DWORD dwReserved5;
    DWORD dwReserved6;
    DWORD dwReserved7;
    DWORD dwReserved8;
    DWORD dwReserved9;
    DWORD dwReserved10;
    DWORD dwUpdateModeFlag;

} IMGFS_BOOT_SECTOR, *PIMGFS_BOOT_SECTOR;

// These two functions below are in Fallite.lib, and they are called by iplcommon.lib
// Because SMDKV210 iROM SDMMC BSP is not use falite.lib, these functions are added here.
// --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOL BP_ReadLogicalSector(HANDLE hPartition, DWORD dwSector, LPBYTE lpBuffer)
{
    static PVOID hFAL = NULL;
    PPARTSTATE pPartState = (PPARTSTATE) hPartition;   
    if (INVALID_HANDLE_VALUE == hPartition) {
        return FALSE;
    }
    return SDHC_READ(g_AddressInfoSector.dwFlashImageStartSector + ((dwSector + pPartState->pPartEntry->Part_StartSector)*(SDMMC_SECTOR_SIZE>>9))
                        , 1*(SDMMC_SECTOR_SIZE>>9), (UINT32)lpBuffer);
}

// --------------------------------------------------------------------
// --------------------------------------------------------------------
BOOL BP_GetUpdateModeFlag(BOOL *pfUpdateMode)
{
    // sectors will be 4KB at the most
    static BYTE sector[SDMMC_SECTOR_SIZE];

    if (NULL == pfUpdateMode) {
        return FALSE;
    }

    // open the imgfs partition
    HANDLE hPartition = BP_OpenPartition(0, 0, PART_IMGFS, FALSE, PART_OPEN_EXISTING);
    if (INVALID_HANDLE_VALUE == hPartition) {
        // try again with fActive = TRUE
        hPartition = BP_OpenPartition(0, 0, PART_IMGFS, TRUE, PART_OPEN_EXISTING);
    }

    if (INVALID_HANDLE_VALUE == hPartition) {
        // there is probably no IMGFS partition
        RETAILMSG(1, (TEXT("BP_GetUpdateModeFlag: failed to open IMGFS partition\r\n")));
        return FALSE;
    }

    // read logical sector zero of the imgfs partition
    if (!BP_ReadLogicalSector(hPartition, 0, sector)) {
        RETAILMSG(1, (TEXT("BP_GetUpdateModeFlag: failed to read bootsector of IMGFS partition\r\n")));
        return FALSE;
    }

    *pfUpdateMode = ((PIMGFS_BOOT_SECTOR)sector)->dwUpdateModeFlag;
    RETAILMSG(1, (L"BP_GetUpdateModeFlag: fUpdateMode=%d\r\n", *pfUpdateMode));
    //if(*pfUpdateMode!=1) *pfUpdateMode=0;
    
    return TRUE;
}


