/**************************************************************************//**
 * @file     Demo_CommandShell.c
 * @brief    Demonstrate how to use the APIs of NVTFAT library
 *           and how to link different medias
 *
 * SPDX-License-Identifier: Apache-2.0
 * @copyright (C) 2020 Nuvoton Technology Corp. All rights reserved.
*****************************************************************************/

#ifdef ECOS
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
#include "drv_api.h"
#include "wbtypes.h"
#include "wbio.h"
#else
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "N9H26.h"
#endif


#define UART_BAUD_RATE      115200
#define RESERVED_SIZE       (10240*1024)            //10MB

#if defined(ENABLE_RAM)
void FormatRamDisk(void);
INT32  InitRAMDisk(UINT32 uStartAddr, UINT32 uDiskSize);
INT32 RemoveRAMDisk(void);
#endif

#ifdef ENABLE_GNAND
static NDISK_T ptNDisk;
#endif
// select use UART output or MULTI-ICE
#undef getchar
#ifdef ECOS
#define getchar     diag_getc
#define printf      diag_printf
#else
#define getchar     sysGetChar
#define printf      sysprintf
#endif

#ifdef ECOS
#define get_timer_ticks()   cyg_current_time()
#define sysprintf   diag_printf
#else
#define get_timer_ticks()   sysGetTicks(TIMER0)
#endif

#ifdef ENABLE_GNAND
NDRV_T _nandDiskDriver0 =
{
    nandInit0,
    nandpread0,
    nandpwrite0,
    nand_is_page_dirty0,
    nand_is_valid_block0,
    nand_ioctl,
    nand_block_erase0,
    nand_chip_erase0,
    0
};
#endif

UINT32 g_u32TotalSize;

extern VOID  fsGetErrorDescription(INT nErrCode, CHAR *szDescription, INT bIsPrint);
extern INT   fsBIG5toUnicode(VOID *bstr, VOID *ustr);
extern void  FAT_dump_sector_cache(void);


#define RAM_DISK_SIZE   ((1024*1024)*8)

/* imported from WBFILE_DISK.C */
extern PDISK_T      *_fs_ptPDiskList;

#define DUMMY_BUFFER_SIZE       (64 * 1024)


#if defined(__GNUC__)
INT8 i8RamDisk[RAM_DISK_SIZE] __attribute__((aligned (32)));
static UINT8  _pucDummy[DUMMY_BUFFER_SIZE] __attribute__((aligned (32)));
#else
__align(32) INT8 i8RamDisk[RAM_DISK_SIZE];
__align(32) static UINT8  _pucDummy[DUMMY_BUFFER_SIZE];
#endif


static CHAR *_pcFileCommads[] =
{
    "?",    "HELP", "DIR",    "TYPE",  "CD",    "DEL",
    "COPYFILE", "MKDIR","MD",     "RMDIR", "RD",    "RENAME",
    "CMP",  "DS",   "RDTST",  "WRTST", "APTST", "RAWRD",
    "DISK", "DF",   "FORMAT", "DELA",  "DIRS",
    "RAWWD",
    NULL
};

enum  EnumerateCommandList
{
    QQ=0,   HELP,   DIR,    TYPE,   CD,     DEL,
    COPYFILE,   MKDIR,  MD,     RMDIR,  RD,     RENAME,
    CMP,    DUMP,   RDTST,  WRTST,  APTST,  RAWRD,
    DISK,   DF,     FORMAT, DELA,   DIRS,   RAWWD,
    CHANGE
};

static CHAR _szCommandLine[512];

static CHAR _pszCommandShellHelp[] =
{
    "WBFile Command Shell Command List -\n"
    "    <HELP/?>    command help\n"
    "    <DIR>       list files under the current directory\n"
    "    <TYPE>      print file contents on console\n"
    "    <CD>        change directory\n"
    "    <DEL>       delete a file\n"
    "    <COPYFILE>  copy a file\n"
    "    <MKDIR/MD>  build an empty directory\n"
    "    <RMDIR/RD>  remove an empty directory\n"
    "    <RENAME>    rename a file\n"
    "    <CMP>       compare two file\n"
    "    <DS>        dump current disk sector\n"
    "    <RDTST>     read speed test\n"
    "    <WRTST>     write speed test\n"
    "    <APTST>     file append test\n"
    "    <DISK>      print disk information\n"
    "    <x:>        change working drive, where x is the drive character\n"
    "\n\n"
};


static INT   _nCurrentDrive;
static CHAR  _pszWorkingDirectory[24][300] =
{
    "C:",
    "D:",
    "E:",
    "F:",
    "G:",
    "H:",
    "I:",
    "J:",
    "K:",
    "L:",
    "M:",
    "N:",
    "O:",
    "P:",
    "Q:",
    "R:",
    "S:",
    "T:",
    "U:",
    "V:",
    "W:",
    "X:",
    "Y:",
    "Z:",
};

static volatile BOOL _bIsCardInserted = FALSE;

#if defined(ENABLE_SD_ONE_PART)||defined(ENABLE_SD_TWO_PART)||defined(ENABLE_SD_FOUR_PART)
void sd_removed(VOID *ptr)
{
    PDISK_T  *ptPDisk = (PDISK_T *)ptr;
    sysprintf("\nSD card removed! (%d)\n", (INT)ptPDisk);
    fsPhysicalDiskDisconnected(ptPDisk);
}


void sd_inserted()
{
    sysprintf("\nSD card instered!\n");
    _bIsCardInserted = TRUE;
}
#endif



static INT  get_command_code(CHAR *szCmd)
{
    INT     nIdx = 0;

    if ((szCmd[1] == ':') && (szCmd[2] == 0))
        return CHANGE;      /* change drive */

    while (1)
    {
        if (_pcFileCommads[nIdx] == NULL)
            return -1;      /* command not found */

        if (!strcmp(_pcFileCommads[nIdx], szCmd))
            return nIdx;

        nIdx++;
    }
}


static CHAR  *get_token(CHAR *szString, CHAR *pcSepCharList, INT nMaxLen)
{
    CHAR    *pcParsePtr = szString;
    CHAR    *pcPtr;
    INT     nLen = 0;

    if (pcParsePtr == NULL)
        return NULL;

    while (*pcParsePtr)
    {
        pcPtr = pcSepCharList;
        while (*pcPtr)
        {
            if (*pcParsePtr == *pcPtr)
            {
                *pcParsePtr++ = 0;
                return pcParsePtr;
            }
            pcPtr++;
        }
        pcParsePtr++;
        if (++nLen >= nMaxLen)
            return NULL;        /* string too long!! */
    }

    return pcParsePtr;        /* reach end of the input string */
}



static VOID  accept_string(CHAR *pcString, INT nLength)
{
    CHAR    chr;
    INT     nCount;

    nCount = 0;

    while (1)
    {
        chr = getchar();
        if (chr == 0)               /* control character pressed */
        {
            chr = getchar();
            if (chr == 0x4b)        /* left arrow key */
            {
                if (nCount > 0)      /* have characters in pcString */
                {
                    nCount--;        /* delete a character */
                    sysprintf("%c%c%c", 0x08, 0x20, 0x08);
                }
            }
        }
        else if (chr == 0x08)       /* backspace */
        {
            if (nCount > 0)          /* have characters in pcString */
            {
                nCount--;            /* delete a character */
                sysprintf("%c%c%c", 0x08, 0x20, 0x08);
            }
        }
        else if (chr == 10)
            ;
        else
        {
            if ((chr == 0xd) || (chr == '!'))
            {
                if (nCount == 0)
                    sysprintf("\n");
                pcString[nCount] = 0;
                return;
            }

            sysprintf("%c", chr);
            pcString[nCount] = chr;            // read in a character
            nCount++;
            if (nCount >= nLength)
            {
                nCount--;
                sysprintf("%c", 0x08);            // backspace
            }
        }
    }
}





INT  fsFourPartAndFormatAll(PDISK_T *ptPDisk, INT firstPartSize, INT secondPartSize,
                            INT threePartSize, INT fourPartSize)
{
    PARTITION_T *ptPartition;
    UINT32      uSizeList[5];
    INT         nStatus = 0;

    /*
     * Create two partitions for ptPDisk
     */
    uSizeList[0] = firstPartSize;   // K Bytes;
    uSizeList[1] = secondPartSize;  //  K Bytes;
    uSizeList[2] = threePartSize;
    uSizeList[3] = fourPartSize;
    uSizeList[4] = 0;
    nStatus = fsCreateDiskPartition(ptPDisk, uSizeList, 4);
    if (nStatus < 0)
        return nStatus;

    ptPartition = ptPDisk->ptPartList;

    /*
     * Format all partitions of ptPDisk
     */
    while (ptPartition != NULL)
    {
        nStatus = fs_fat_format_partition(ptPDisk, ptPartition, 0);
        if (nStatus < 0)
            return -1;
        ptPartition  = ptPartition->ptNextPart;
    }
    return FS_OK;
}

static INT  Action_DIR(CHAR *suDirName)
{
    INT             i, nStatus;
    CHAR            szMainName[12], szExtName[8], *pcPtr;
    CHAR            szLongName[MAX_FILE_NAME_LEN/2];
    FILE_FIND_T     tFileInfo;
    UINT32          uBlockSize, uFreeSize, uDiskSize;

    memset((UINT8 *)&tFileInfo, 0, sizeof(tFileInfo));
    nStatus = fsFindFirst(suDirName, NULL, &tFileInfo);
    if (nStatus < 0)
        return nStatus;

    do
    {
        pcPtr = tFileInfo.szShortName;
        if ((tFileInfo.ucAttrib & A_DIR) &&
                (!strcmp(pcPtr, ".") || !strcmp(pcPtr, "..")))
            strcat(tFileInfo.szShortName, ".");

        memset(szMainName, 0x20, 9);
        szMainName[8] = 0;
        memset(szExtName, 0x20, 4);
        szExtName[3] = 0;
        i = 0;
        while (*pcPtr && (*pcPtr != '.'))
            szMainName[i++] = *pcPtr++;
        if (*pcPtr++)
        {
            i = 0;
            while (*pcPtr)
                szExtName[i++] = *pcPtr++;
        }

        fsUnicodeToAscii(tFileInfo.suLongName, szLongName, 1);

        if (tFileInfo.ucAttrib & A_DIR)
        {
#if 0
            sysprintf("%s %s      <DIR>  %02d-%02d-%04d  %02d:%02d  %s\n",
                      szMainName, szExtName,
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
#else   /* There is an C library issue on Keil V5.24 */
            sysprintf("%s %s     <DIR>     ",
                      szMainName, szExtName);
            sysprintf(" %02d-%02d-%04d ",
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100);

            sysprintf("%02d:%02d  %s\n",
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
#endif
        }
        else
        {
            volatile UINT32 u32Var=0;
#if 0
            sysprintf("%s %s %10d  %02d-%02d-%04d  %02d:%02d  %s\n",
                      szMainName, szExtName, tFileInfo.n64FileSize,
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
#else   /* There is an C library issue on Keil V5.24 */
            sysprintf("%s %s    ",
                      szMainName, szExtName);
#if 0
            sysprintf("%10d ", tFileInfo.n64FileSize);
#else
            u32Var = tFileInfo.n64FileSize;
            sysprintf("%10d ", u32Var);
#endif

            sysprintf(" %02d-%02d-%04d ",
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100);

            sysprintf("%02d:%02d  %s\n",
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
#endif
        }
    }
    while (!fsFindNext(&tFileInfo));

    fsFindClose(&tFileInfo);

    fsDiskFreeSpace(suDirName[0], &uBlockSize, &uFreeSize, &uDiskSize);

    sysprintf("\nDisk Size: %d Kbytes, Free Space: %d KBytes\n", (INT)uDiskSize, (INT)uFreeSize);

    return 0;
}


static INT  Action_DIRS(CHAR *suDirName)
{
    INT     nFileCnt, nDirCnt;
    UINT64  uTotalSize;
    INT     nStatus;

    nStatus = fsGetDirectoryInfo(suDirName, NULL, &nFileCnt, &nDirCnt, &uTotalSize, TRUE);
    sysprintf("File = %d, Dir = %d, Total Size = %d\n", nFileCnt, nDirCnt, (INT)uTotalSize);
    return nStatus;
}


static INT  Action_DIR2(CHAR *suDirName)
{
    INT             i, nStatus;
    CHAR            szMainName[12], szExtName[8], *pcPtr;
    CHAR            szLongName[MAX_FILE_NAME_LEN/2];
    CHAR            suLongName[MAX_FILE_NAME_LEN];
    CHAR            suSlash[6] = { '\\', 0, 0, 0 };
    FILE_FIND_T     tFileInfo;
    UINT32          uBlockSize, uFreeSize, uDiskSize;

    memset((UINT8 *)&tFileInfo, 0, sizeof(tFileInfo));
    sysprintf("DIR => %s\n", fsDebugUniStr(suDirName));
    nStatus = fsFindFirst(suDirName, NULL, &tFileInfo);
    if (nStatus < 0)
    {
        sysprintf("fsFindFirst <%s> error = %x\n\n\n", fsDebugUniStr(suDirName), nStatus);
        return nStatus;
    }

    do
    {
        pcPtr = tFileInfo.szShortName;
        if ((tFileInfo.ucAttrib & A_DIR) &&
                (!strcmp(pcPtr, ".") || !strcmp(pcPtr, "..")))
            strcat(tFileInfo.szShortName, ".");

        memset(szMainName, 0x20, 9);
        szMainName[8] = 0;
        memset(szExtName, 0x20, 4);
        szExtName[3] = 0;
        i = 0;
        while (*pcPtr && (*pcPtr != '.'))
            szMainName[i++] = *pcPtr++;
        if (*pcPtr++)
        {
            i = 0;
            while (*pcPtr)
                szExtName[i++] = *pcPtr++;
        }

        fsUnicodeToAscii(tFileInfo.suLongName, szLongName, 1);

        if (tFileInfo.ucAttrib & A_DIR)
        {
            sysprintf("%s %s      <DIR>  %02d-%02d-%04d  %02d:%02d  %s\n",
                      szMainName, szExtName,
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
            fsUnicodeCopyStr(suLongName, suDirName);
            if (fsUnicodeStrLen(suDirName) > 6)
                fsUnicodeStrCat(suLongName, suSlash);   /* not C:\ */
            fsUnicodeStrCat(suLongName, tFileInfo.suLongName);
            if ((tFileInfo.szShortName[0] != '.') &&
                    (strncmp(tFileInfo.szShortName, "RECYCLED", 8)))
                Action_DIR2(suLongName);
        }
#if 0
        else
            sysprintf("%s %s %10d  %02d-%02d-%04d  %02d:%02d  %s\n",
                      szMainName, szExtName, tFileInfo.n64FileSize,
                      tFileInfo.ucWDateMonth, tFileInfo.ucWDateDay, (tFileInfo.ucWDateYear+80)%100 ,
                      tFileInfo.ucWTimeHour, tFileInfo.ucWTimeMin, szLongName);
#endif
    }
    while (!fsFindNext(&tFileInfo));

    fsFindClose(&tFileInfo);

    fsDiskFreeSpace(suDirName[0], &uBlockSize, &uFreeSize, &uDiskSize);

    sysprintf("Disk Size: %d Kbytes, Free Space: %d KBytes\n", (INT)uDiskSize, (INT)uFreeSize);

    return 0;
}


static  UINT8  _ucLine[128];
static INT  Action_TYPE(CHAR *suFileName, CHAR *szAsciiName)
{
    INT     hFile;
    INT     nLen, nIdx, nStatus;

    hFile = fsOpenFile(suFileName, szAsciiName, O_RDONLY);
    if (hFile < 0)
        return hFile;

    nStatus = 0;
    while (1)
    {
        nStatus = fsReadFile(hFile, _ucLine, 128, &nLen);
        if (nStatus < 0)
            break;

        for (nIdx = 0; nIdx < nLen; nIdx++)
        {
            if (_ucLine[nIdx] < 127)
                sysprintf("%c", _ucLine[nIdx]);
        }
    }

    fsCloseFile(hFile);

    return nStatus;
}



static INT  Action_ReadSpeedTest(CHAR *suFileName, CHAR *szAsciiName)
{
    INT      hFile;
    INT      nReadLen, nTime0, nStatus;
    UINT32   uKBCnt;

    uKBCnt = 0;
    hFile = fsOpenFile(suFileName, szAsciiName, O_RDONLY);
    if (hFile < 0)
        return hFile;

    nStatus = 0;
    nTime0 = get_timer_ticks();
    while (1)
    {
        nReadLen = 0;
        nStatus = fsReadFile(hFile, (UINT8 *)_pucDummy, DUMMY_BUFFER_SIZE, &nReadLen);
        if ((nStatus < 0) || (nReadLen == 0))
            break;

        uKBCnt += nReadLen / 1024;

        if (uKBCnt % 8192 == 0)
            sysprintf("%d MB\n", uKBCnt/1024);
    }
    nTime0 = get_timer_ticks() - nTime0;
    if (nTime0 == 0) nTime0 = 1;

    sysprintf("Read speed: %d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);

    fsCloseFile(hFile);
    return nStatus;
}



static INT  Action_WriteSpeedTest(CHAR *suFileName, CHAR *szAsciiName)
{
    INT      hFile;
    INT      i, j, nWriteLen, nTime0, nStatus;
    UINT32   uKBCnt = 0;

    hFile = fsOpenFile(suFileName, szAsciiName, O_CREATE | O_TRUNC);
    if (hFile < 0)
        return hFile;

    for (i = 0, j = 0; i < DUMMY_BUFFER_SIZE; i += 2, j++)
    {
        _pucDummy[i] = (j >> 8) & 0xff;
        _pucDummy[i + 1] = j & 0xff;
    }
    memset((UINT8 *)_pucDummy + 0x7e0, 0x97, 32);

    nStatus = 0;
    nTime0 = get_timer_ticks();

    while (1)
    {
        nStatus = fsWriteFile(hFile, (UINT8 *)_pucDummy, DUMMY_BUFFER_SIZE, &nWriteLen);
        if (nStatus < 0)
            break;

        uKBCnt += nWriteLen / 1024;

        if (uKBCnt % 1024 == 0)
            sysprintf("%d MB\r", uKBCnt);

        if (uKBCnt >= 40*1024)
            break;
    }
    nTime0 = get_timer_ticks() - nTime0;
    if (nTime0 == 0) nTime0 = 1;

    sysprintf("Write speed: %d KB/sec\n", (INT)(uKBCnt * 100) / nTime0);

    fsCloseFile(hFile);

    return nStatus;
}


static INT  Action_FileAppendTest(CHAR *suFileName, CHAR *szAsciiName)
{
    INT     hFile;
    CHAR    szPattern[128];
    INT     i, nWriteLen, nStatus;
    INT     nWriteCnt = 15 * 1024;

    hFile = fsOpenFile(suFileName, szAsciiName, O_APPEND);
    if (hFile < 0)
        return hFile;

    for (i =0 ; i < 26; i++)
        szPattern[i] = 'A' + i;

    while (nWriteCnt > 0)
    {
        nStatus = fsWriteFile(hFile, (UINT8 *)szPattern, 26, &nWriteLen);
        if (nStatus < 0)
        {
            fsGetErrorDescription(nStatus, NULL, 1);
            break;
        }
        nWriteCnt -= nWriteLen;
    }
    nStatus = fsCloseFile(hFile);
    return nStatus;
}



static INT  Action_Compare(CHAR *suFileName1, CHAR *szAsciiName1,
                           CHAR *suFileName2, CHAR *szAsciiName2)
{
    INT     hFile1, hFile2;
    INT     nLen1, nLen2, nCount, nStatus1, nStatus2;
    UINT8   buffer1[8192], buffer2[8192];

    hFile1 = fsOpenFile(suFileName1, szAsciiName1, O_RDONLY);
    if (hFile1 < 0)
        return hFile1;

    hFile2 = fsOpenFile(suFileName2, szAsciiName2, O_RDONLY);
    if (hFile2 < 0)
        return hFile2;

    sysprintf("\nComparing file ...\n");
    nCount = 0;
    while (1)
    {
        nStatus1 = fsReadFile(hFile1, buffer1, 1024, &nLen1);
        nStatus2 = fsReadFile(hFile2, buffer2, 1024, &nLen2);

        if ((nStatus1 == ERR_FILE_EOF) && (nStatus2 == ERR_FILE_EOF))
        {
            sysprintf("\nFile Compare length %x pass\n", nCount * 1024+nLen1);
            fsCloseFile(hFile1);
            fsCloseFile(hFile2);
            return Successful;
        }

        if (nLen1 != nLen2)
        {
            sysprintf("Compare different length \n");
            break;
        }
        if (memcmp(buffer1, buffer2, nLen1))
        {
            sysprintf("File Compare failed at offset %x\n", nCount * 1024 + nLen1);
            break;
        }
        if(nLen1<1024)
        {
            sysprintf("\nFile Compare length %x pass\n", nCount * 1024+nLen1);
            fsCloseFile(hFile1);
            fsCloseFile(hFile2);
            return Successful;
        }
        if(nLen1==1024)
            nCount++;
    }


    fsCloseFile(hFile1);
    fsCloseFile(hFile2);
    return -1;
}



static INT  Action_PrintDiskInfo()
{
    PDISK_T     *pDiskList, *ptPDiskPtr;
    PARTITION_T *ptPartition;
    INT         nDiskIdx = 0;
    INT         nPartIdx;

    ptPDiskPtr = pDiskList = fsGetFullDiskInfomation();

    while (ptPDiskPtr != NULL)
    {
        sysprintf("\n\n=== Disk %d (%s) ======================\n", nDiskIdx++, (ptPDiskPtr->nDiskType & DISK_TYPE_USB_DEVICE) ? "USB" : "IDE");
        sysprintf("    name:     [%s%s]\n", ptPDiskPtr->szManufacture, ptPDiskPtr->szProduct);
        sysprintf("    head:     [%d]\n", ptPDiskPtr->nHeadNum);
        sysprintf("    sector:   [%d]\n", ptPDiskPtr->nSectorNum);
        sysprintf("    cylinder: [%d]\n", ptPDiskPtr->nCylinderNum);
        sysprintf("    size:     [%d MB]\n", ((INT)ptPDiskPtr->uDiskSize / 1024));

        ptPartition = ptPDiskPtr->ptPartList;
        nPartIdx = 1;
        while (ptPartition != NULL)
        {
            sysprintf("\n    --- Partition %d --------------------\n", nPartIdx++);
            sysprintf("        active: [%s]\n", (ptPartition->ucState & 0x80) ? "Yes" : "No");
            sysprintf("        size:   [%d MB]\n", (INT)(ptPartition->uTotalSecN / 1024) / 2);
            sysprintf("        start:  [%d]\n", (INT)ptPartition->uStartSecN);
            sysprintf("        type:   ");
            if (ptPartition->ptLDisk == NULL)
                sysprintf("[Unknown]\n");
            else
            {
                switch (ptPartition->ptLDisk->ucFileSysType)
                {
                case FILE_SYSTEM_FAT12:
                    sysprintf("[FAT12]\n");
                    break;
                case FILE_SYSTEM_FAT16:
                    sysprintf("[FAT16]\n");
                    break;
                case FILE_SYSTEM_FAT32:
                    sysprintf("[FAT32]\n");
                    break;
                case FILE_SYSTEM_NTFS:
                    sysprintf("[NTFS]\n");
                    break;
                default:
                    sysprintf("[???????]\n");
                    break;
                }
                sysprintf("        drive:  [%c]\n", ptPartition->ptLDisk->nDriveNo);
            }
            ptPartition = ptPartition->ptNextPart;
        }
        ptPDiskPtr = ptPDiskPtr->ptPDiskAllLink;
    }
    fsReleaseDiskInformation(pDiskList);
    return 0;
}



INT  build_full_path(CHAR *szFullPath, CHAR *szPath)
{
    INT     nDriveNo;
    CHAR    *pcPtr;

    if (szPath[1] == ':')
    {
        nDriveNo = szPath[0];
        if ((nDriveNo >= 'a') && (nDriveNo <= 'z'))
            nDriveNo -= ('a' - 'A');
        pcPtr = szPath + 2;
    }
    else
    {
        nDriveNo = _nCurrentDrive;
        pcPtr = szPath;
    }

    if ((nDriveNo < 'C') || (nDriveNo > 'Z'))
        return -1;

    if (pcPtr[0] == '\\')
        strcpy(szFullPath, szPath);
    else
    {
        strcpy(szFullPath, _pszWorkingDirectory[nDriveNo - 'C']);
        strcat(szFullPath, "\\");
        strcat(szFullPath, pcPtr);
    }

    return 0;
}


void Create_File_Test(void)
{
    CHAR    szAsciiStr[128], suFileName[512];
    INT     nIdx, hFile, nWriteLen;
    INT     t0, t_create, t_write, t_close;

    memset(szAsciiStr, 0, sizeof(szAsciiStr));
    sprintf(szAsciiStr, "C:\\Test");
    fsAsciiToUnicode(szAsciiStr, suFileName, TRUE);
    fsMakeDirectory(suFileName, NULL);

    for (nIdx = 1; nIdx < 1000; nIdx++)
    {
        sprintf(szAsciiStr, "C:\\Test\\%04d", nIdx);
        fsAsciiToUnicode(szAsciiStr, suFileName, TRUE);

        t0 = get_timer_ticks();
        hFile = fsOpenFile(suFileName, NULL, O_CREATE | O_IOC_VER2);
        t_create = get_timer_ticks() - t0;

        t0 = get_timer_ticks();
        fsWriteFile(hFile, (UINT8 *)_pucDummy, 1024, &nWriteLen);
        t_write = get_timer_ticks() - t0;

        t0 = get_timer_ticks();
        fsCloseFile(hFile);
        t_close = get_timer_ticks() - t0;

        sysprintf("%04d --- %d, %d, %d\n", nIdx, t_create, t_write, t_close);
    }
    fsFlushIOCache();
}


void  delay_ticks(int ticks)
{
    int  t0;

    t0 = get_timer_ticks();
    while (get_timer_ticks() - t0 < ticks)
        ;
}


#ifdef SW_REMOVE
void USB_PhyPowerDown_Test()
{
    LDISK_T  *ptLDisk;
    PDISK_T  *ptPDisk;
    int      t_start, t;
    int      i, tloop, sec;

    if (get_vdisk('C', &ptLDisk) < 0)
    {
        sysprintf("Disk C not found, USB test aborted!!\n");
        return;
    }
    ptPDisk = ptLDisk->ptPDisk;

    t_start = get_timer_ticks();

    // 24 hours test loop
    //
    for (tloop = 0; tloop < 24*60*60; tloop++)
    {
        sec = (get_timer_ticks() - t_start) / 100;
        sysprintf("**** Test loop %d elapsed: %02d:%02d:%02d\n", tloop, sec/3600, (sec/60) % 60, sec % 60);

        sysprintf("Before suspend: %x\n", inpw(UPSCR1));

        outpw(UPSCR1, inpw(UPSCR1) | PORT_SUSPEND);
        for (i = 0; i < 0x10000; i++);
        sysprintf("After set suspend: %x\n", inpw(UPSCR1));

        outpw(UCMDR, (inpw(UCMDR) & ~CMD_RUN));
        sysprintf("After clear RUN: %x\n", inpw(UPSCR1));
        sysprintf("After suspend completed: %x\n", inpw(UPSCR1));

        outpw(0xB00050C4, 0xEC);
        outpw(0xB00050C8, 0xEC);

        // wait 1 minute
        //
        t = get_timer_ticks();
        while (get_timer_ticks() - t < 6000) ;

        outpw(0xB00050C4, 0x160);
        outpw(0xB00050C8, 0x520);

        outpw(UCMDR, (inpw(UCMDR) | CMD_RUN));
        for (i = 0; i < 0x10000; i++);
        sysprintf("After enable RUN: %x\n", inpw(UPSCR1));

        outpw(UPSCR1, inpw(UPSCR1) | PORT_RESUME);
        for (i = 0; i < 0x100000; i++);
        sysprintf("After set resume: %x\n", inpw(UPSCR1));

        outpw(UPSCR1, inpw(UPSCR1) &~ (PORT_RESUME | PORT_SUSPEND));
        for (i = 0; i < 0x10000; i++);
        sysprintf("After resume completed: %x\n", inpw(UPSCR1));

        // read 128 sectors from disk
        if (ptPDisk->ptDriver->read(ptPDisk, 0, 128, (UINT8 *)_pucDummy) < 0)
        {
            sysprintf("Read disk failed!!\n");
            return;
        }
        else
            sysprintf("Test passed.\n");
    }
}
#endif

#ifdef ECOS
void CommandShell(cyg_addrword_t data)
#else
void  CommandShell()
#endif
{
    INT         nCmdCode;
    CHAR        *szCmd, *szArgum1, *szArgum2, *pcPtr; //*szArgum3,
    CHAR        szPath1[MAX_PATH_LEN], szPath2[MAX_PATH_LEN];
    CHAR        suFullName1[MAX_PATH_LEN], suFullName2[MAX_PATH_LEN];
    INT         hFile, nStatus;

#if 0
    /* USB open close test */
    while (1)
    {
        delay_ticks(100);

#ifndef ECOS
        Hub_CheckIrqEvent();
        delay_ticks(20);
        Hub_CheckIrqEvent();
#endif

        sysprintf("\n\nClose =>\n\n");

        DeInitUsbSystem();

        sysprintf("\n\nClose done.\n\n");

#ifndef ECOS
        Hub_CheckIrqEvent();
        delay_ticks(20);
        Hub_CheckIrqEvent();
#endif

        delay_ticks(100);

#ifndef ECOS
        Hub_CheckIrqEvent();
        delay_ticks(20);
        Hub_CheckIrqEvent();
#endif

        sysprintf("\n\nOpen =>\n\n");

        InitUsbSystem();

        sysprintf("\n\nOpen done.\n\n");

#ifndef ECOS
        Hub_CheckIrqEvent();
        delay_ticks(20);
        Hub_CheckIrqEvent();
#endif

        sysprintf("Free - %d\n", USB_available_memory());
        delay_ticks(50);

    }
#endif

    //Create_File_Test();

    _nCurrentDrive = 'C';

    while (1)
    {
#if defined(ENABLE_USB_HOST) && !defined(ECOS)
        Hub_CheckIrqEvent();
        //UMAS_ScanAllDevice();
#endif
        //sysprintf("memory: %d\n", USB_available_memory());

        strcpy(szPath1, _pszWorkingDirectory[_nCurrentDrive - 'C']);
        if (strlen(_pszWorkingDirectory[_nCurrentDrive - 'C']) == 2)
            sysprintf("%s\\>", szPath1);
        else
            sysprintf("%s>", szPath1);


        accept_string(_szCommandLine, 256);

        if (strlen(_szCommandLine) == 0)
            continue;

        sysprintf("\n");

        /*- get command tokens */
        szCmd = &_szCommandLine[0];
        szArgum1 = get_token(szCmd, " \t\r\n", 8);
        szArgum2 = get_token(szArgum1, " \t\r\n", 128);
        //szArgum3 = get_token(szArgum2, " \t\r\n", 128);

        //sysprintf("Command:<%s> <%s> <%s>\n", szCmd, szArgum1, szArgum2);

        fsAsciiToUpperCase(szCmd);

        nCmdCode = get_command_code(szCmd);

        if ((szArgum1 == NULL) && (szCmd[1] == ':') && (szCmd[2] == 0))
            nCmdCode = CHANGE;

        if (nCmdCode < 0)
        {
            sysprintf("Command not found!\n");
            continue;
        }

        build_full_path(szPath1, szArgum1);
        fsAsciiToUnicode(szPath1, suFullName1, 1);
        build_full_path(szPath2, szArgum2);
        fsAsciiToUnicode(szPath2, suFullName2, 1);

        nStatus = 0;

        switch (nCmdCode)
        {
        case QQ:
        case HELP:
            sysprintf("%s", _pszCommandShellHelp);
            break;

        case DIR:
            nStatus = Action_DIR(suFullName1);
            //nStatus = Action_DIR2(suFullName1);
            break;

        case DIRS:
            nStatus = Action_DIRS(suFullName1);
            break;

        case TYPE:
            nStatus = Action_TYPE(suFullName1, szArgum1);
            break;

        case CD:
            if (!strcmp(szArgum1, "\\"))
            {
                _pszWorkingDirectory[_nCurrentDrive - 'C'][2] = '\0';
                break;
            }

            if (!strcmp(szArgum1, ".."))
            {
                if (strlen(_pszWorkingDirectory[_nCurrentDrive - 'C']) == 2)
                    break;

                strcpy(szPath1, _pszWorkingDirectory[_nCurrentDrive - 'C']);

                nStatus = 0;
                pcPtr = szPath1 + strlen(szPath1);
                while (pcPtr > szPath1)
                {
                    if (*pcPtr == '\\')
                        break;
                    pcPtr--;
                }
                *pcPtr = '\0';
                strcpy(_pszWorkingDirectory[_nCurrentDrive - 'C'], szPath1);
                break;
            }

            fsAsciiToUnicode(szPath1, suFullName1, 1);
            hFile = fsOpenFile(suFullName1, szArgum1, O_DIR);
            if (hFile < 0)
                nStatus = hFile;
            else
            {
                strcpy(_pszWorkingDirectory[_nCurrentDrive - 'C'], szPath1);
                fsCloseFile(hFile);
                nStatus = 0;
            }
            break;

        case DEL:
            nStatus = fsDeleteFile(suFullName1, szArgum1);
            break;

        case DELA:
            nStatus = fsDeleteDirTree(suFullName1, NULL);
            break;

        case COPYFILE:
            nStatus = fsCopyFile(suFullName1, szArgum1, suFullName2, szArgum2);
            break;

        case MKDIR:
        case MD:
            nStatus = fsMakeDirectory(suFullName1, szArgum1);
            break;

        case RMDIR:
        case RD:
            nStatus = fsRemoveDirectory(suFullName1, szArgum1);
            break;

        case RENAME:
            if ((nStatus = fsRenameFile(suFullName1, szArgum1, suFullName2, szArgum2, 0)) == ERR_FILE_IS_DIRECTORY)
                nStatus = fsRenameFile(suFullName1, szArgum1, suFullName2, szArgum2, 1);
            break;

        case CMP:
            nStatus = Action_Compare(suFullName1, szArgum1, suFullName2, szArgum2);
            break;

        case CHANGE:
            if ((szCmd[0] >= 'C') && (szCmd[0] <= 'Z'))
                _nCurrentDrive = szCmd[0];
            continue;

        //case DUMP:
        //  {
        //      UINT32  uSectorNo = 0;
        //
        //      while (*szArgum1)
        //          uSectorNo = uSectorNo * 10 + (*szArgum1++ - '0');
        //      fsDumpDiskSector(uSectorNo, 1);
        //  }
        //  continue;

        case RDTST:
            //_fs_uReadSecCnt = _fs_uWriteSecCnt = 0;
            nStatus = Action_ReadSpeedTest(suFullName1, szArgum1);
            //sysprintf("\n\n\nTotal: Read: %d, Write: %d\n", _fs_uReadSecCnt, _fs_uWriteSecCnt);
            break;

        case WRTST:
            //_fs_uReadSecCnt = _fs_uWriteSecCnt = 0;
            //nStatus = Action_WriteSpeedTest(suFullName1, szArgum1);
            nStatus = Action_WriteSpeedTest(suFullName1, NULL);
            sysprintf("wrtst [%x]\n", nStatus);
            //sysprintf("\n\n\nTotal: Read: %d, Write: %d\n", _fs_uReadSecCnt, _fs_uWriteSecCnt);
            break;

        case APTST:
            nStatus = Action_FileAppendTest(suFullName1, szArgum1);
            break;

        case RAWRD:
        {
            LDISK_T  *ptLDisk;
            PDISK_T  *ptPDisk;
            INT  nTime0;
            INT  nCount, nStatus;

            nStatus = get_vdisk('C', &ptLDisk);
            if (nStatus < 0)
                break;
            ptPDisk = ptLDisk->ptPDisk;

            nTime0 = get_timer_ticks();
            /* 40MB read test */
            for (nCount = 0; nCount < 40960; nCount += 64)
            {
                nStatus = ptPDisk->ptDriver->read(ptPDisk, 1024, 128, (UINT8 *)_pucDummy);
                if (nStatus < 0)
                    break;
            }
            nTime0 = get_timer_ticks() - nTime0;
            if (nTime0 == 0) nTime0 = 1;
            sysprintf("Raw Read speed: %d KB/sec\n", (INT)(nCount * 100) / nTime0);
        }
        break;

        case RAWWD:
        {
            LDISK_T  *ptLDisk;
            PDISK_T  *ptPDisk;
            INT  nTime0;
            INT  nCount, nStatus;

            nStatus = get_vdisk('C', &ptLDisk);
            if (nStatus < 0)
                break;
            ptPDisk = ptLDisk->ptPDisk;

            nTime0 = get_timer_ticks();
            /* 40MB write test */
            for (nCount = 0; nCount < 40960; nCount += 64)
            {
                nStatus = ptPDisk->ptDriver->write(ptPDisk, 1024, 128, (UINT8 *)_pucDummy, BLOCKING_WRITE);
                if (nStatus < 0)
                    break;
            }
            nTime0 = get_timer_ticks() - nTime0;
            if (nTime0 == 0) nTime0 = 1;
            sysprintf("Raw write speed: %d KB/sec\n", (INT)(nCount * 100) / nTime0);
        }
        break;

        case DISK:
            Action_PrintDiskInfo();
            break;

        case DF:
            FAT_dump_sector_cache();
            break;

        case FORMAT:
        {
#if !defined(ENABLE_USB_HOST)
            UINT32 u32BlockSize, u32FreeSize, u32DiskSize;
#endif

#if defined(ENABLE_SD_TWO_PART)||defined(ENABLE_SD_FOUR_PART)
            UINT32 u32RemainingSize;
#endif
            char chr;
#if defined(ENABLE_SD_ONE_PART)||defined(ENABLE_SD_TWO_PART)||defined(ENABLE_SD_FOUR_PART) || defined(ENABLE_SDIO_1)
            PDISK_T     *pDiskList;

            fsSetReservedArea(RESERVED_SIZE/512);   //Reserved 20480 sector=10MB.
#endif


            sysprintf("The operation should cause whole disk data lost, Do you want to continue? [Y/N]\n");
            chr = getchar();
            if( (chr == 'Y') || (chr == 'y') )
            {
#ifdef ENABLE_SDIO_1
                pDiskList = fsGetFullDiskInfomation();
                fsFormatFlashMemoryCard(pDiskList);
                fsReleaseDiskInformation(pDiskList);
                fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
#endif
#ifdef ENABLE_SD_ONE_PART
                pDiskList = fsGetFullDiskInfomation();
                fsFormatFlashMemoryCard(pDiskList);
                fsReleaseDiskInformation(pDiskList);
                fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
#endif
#ifdef ENABLE_SD_TWO_PART
                pDiskList = fsGetFullDiskInfomation();
                sysprintf("Total Disk Size = %dMB\n", pDiskList->uDiskSize/1024);
                u32RemainingSize =  pDiskList->uDiskSize - (RESERVED_SIZE/1024); //rest disk size = total disk size - reserved size
                sysprintf("RemainingSize = %dMB\n", u32RemainingSize/1024);
                if (fsTwoPartAndFormatAll((PDISK_T *)pDiskList->ptSelf,
                                          128*1024,
                                          //((PDISK_T *)(ptNDisk.pDisk))->uDiskSize - 16*1024) < 0)
                                          (u32RemainingSize-128*1024))<0)
                {
                    sysprintf("Format failed\n");
                    exit(-1);
                }
                fsSetVolumeLabel('C', "SD1-1\n", strlen("SD1-1"));
                fsSetVolumeLabel('D', "SD1-2\n", strlen("SD1-2"));
                pDiskList = fsGetFullDiskInfomation();
                fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
                fsDiskFreeSpace('D', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
#endif
#ifdef ENABLE_SD_FOUR_PART
                pDiskList = fsGetFullDiskInfomation();
                sysprintf("Total Disk Size = %dMB\n", pDiskList->uDiskSize/1024);
                u32RemainingSize =  pDiskList->uDiskSize - (RESERVED_SIZE/1024); //rest disk size = total disk size - reserved size
                sysprintf("RemainingSize = %dMB\n", u32RemainingSize/1024);
                if (fsFourPartAndFormatAll((PDISK_T *)pDiskList->ptSelf, 128*1024, 128*1024,
                                           128*1024,   u32RemainingSize - 3*128*1024) < 0)
                {
                    sysprintf("Format failed\n");
                    exit(-1);
                }

                fsSetVolumeLabel('C', "SD1-1\n", strlen("SD1-1"));
                fsSetVolumeLabel('D', "SD1-2\n", strlen("SD1-2"));
                fsSetVolumeLabel('E', "SD1-3\n", strlen("SD1-3"));
                fsSetVolumeLabel('F', "SD1-4\n", strlen("SD1-4"));
                pDiskList = fsGetFullDiskInfomation();
                fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
                fsDiskFreeSpace('D', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
                fsDiskFreeSpace('E', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
                fsDiskFreeSpace('F', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
#endif
#ifdef ENABLE_GNAND
                sysprintf("Disk Size = %d\n", ((PDISK_T *)(ptNDisk.pDisk))->uDiskSize);
                if (fsTwoPartAndFormatAll((PDISK_T *)ptNDisk.pDisk,
                                          32*1024,
                                          //((PDISK_T *)(ptNDisk.pDisk))->uDiskSize - 16*1024) < 0)
                                          g_u32TotalSize-32*1024)<0)
                {
                    sysprintf("Format failed\n");
                    exit(-1);
                }
                fsSetVolumeLabel('C', "NAND1-1\n", strlen("NAND1-1"));
                fsSetVolumeLabel('D', "NAND1-2\n", strlen("NAND1-2"));
                fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
                fsDiskFreeSpace('D', &u32BlockSize, &u32FreeSize, &u32DiskSize);
                sysprintf("block_size = %d\n", u32BlockSize);
                sysprintf("free_size = %d\n", u32FreeSize);
                sysprintf("disk_size = %d\n", u32DiskSize);
#endif

#ifdef ENABLE_RAM
                RemoveRAMDisk();
                memset(&i8RamDisk, 0, RAM_DISK_SIZE);
                InitRAMDisk((UINT32)&i8RamDisk, RAM_DISK_SIZE)  ;
                FormatRamDisk();
                fsSetVolumeLabel('D', "RAM", strlen("RAM"));
                //fsAssignDriveNumber('D', DISK_TYPE_HARD_DISK, 1, 1);
#endif
            }
        }
        break;

        default:
            sysprintf("Unknown command!\n");
            break;
        } /* end of switch */

        if (_bIsCardInserted)
        {
            _bIsCardInserted = FALSE;
#ifdef DEVICE_SD
            fmiInitSDDevice();
#endif
        }

        if (nStatus != ERR_FILE_EOF)
            fsGetErrorDescription(nStatus, NULL, 1);
    }
}


#ifdef ECOS
static cyg_handle_t     thread_handle;
static cyg_thread       thread;
#define STACKSIZE       (128*1024)
static UINT8            _Statck[STACKSIZE];
#endif

#if 0
void    FormatDisk(void)
{
#if 1
    PDISK_T      *ptPDiskList, *ptPDisk;
    PARTITION_T  *ptPartition;
#else

#endif
    UINT32 u32BlockSize, u32FreeSize, u32DiskSize;

    fsAssignDriveNumber('C', DISK_TYPE_SMART_MEDIA, 0, 1);
#if 0
    fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);

    sysprintf("Disk size %d KBytes\n", u32DiskSize);
    sysprintf("Free size %d KBytes\n", u32FreeSize);
    sysprintf("Block size %d KBytes\n", u32BlockSize);
    sysprintf("Do you want to format NAND flash? [Y/N]\n");
    chr = getchar();
    if( (chr == 'Y') || (chr == 'y') )
    {
        pDiskList = fsGetFullDiskInfomation();
        fsFormatFlashMemoryCard(pDiskList);
        fsReleaseDiskInformation(pDiskList);
        if (fsTwoPartAndFormatAll((PDISK_T *)ptNDisk.pDisk,
                                  16*1024,
                                  ((PDISK_T *)(ptNDisk.pDisk))->uDiskSize - 16*1024) < 0)
        {
            sysprintf("Format failed\n");
            exit(-1);
        }
    }
#else
    /* Get complete disk information */
    ptPDiskList = fsGetFullDiskInfomation();

    /* Format the first physical disk */
    ptPartition = (PARTITION_T*)ptPDiskList;
    ptPDisk = ptPDiskList;      /* format the first physical disk */
    fsTwoPartAndFormatAll(ptPDisk, 16384, u32DiskSize-16384);

    /* Release allocated memory */
    fsReleaseDiskInformation(ptPDiskList);
#endif
}


void GetDiskInformation(void)
{
    PDISK_T       *pDiskList, *ptPDiskPtr;
    PARTITION_T   *ptPartition;
    INT           nDiskIdx = 0;
    INT           nPartIdx;
    ptPDiskPtr = pDiskList = fsGetFullDiskInfomation();
    while (ptPDiskPtr != NULL)
    {
        sysprintf("\n\n=== Disk %d (%s) ======================\n",
                  nDiskIdx++, (ptPDiskPtr->nDiskType &
                               DISK_TYPE_USB_DEVICE) ? "USB" : "IDE");
        sysprintf("    name:     [%s%s]\n", ptPDiskPtr->szManufacture,
                  ptPDiskPtr->szProduct);
        sysprintf("    head:     [%d]\n", ptPDiskPtr->nHeadNum);
        sysprintf("    sector:   [%d]\n", ptPDiskPtr->nSectorNum);
        sysprintf("    cylinder: [%d]\n", ptPDiskPtr->nCylinderNum);
        sysprintf("    size:     [%d MB]\n", ptPDiskPtr->uDiskSize / 1024);

        ptPartition = ptPDiskPtr->ptPartList;
        nPartIdx = 1;
        while (ptPartition != NULL)
        {
            sysprintf("\n    --- Partition %d --------------------\n",
                      nPartIdx++);
            sysprintf("        active: [%s]\n",
                      (ptPartition->ucState & 0x80) ? "Yes" : "No");
            sysprintf("        size:   [%d MB]\n",
                      (ptPartition->uTotalSecN / 1024) / 2);
            sysprintf("        start:  [%d]\n", ptPartition->uStartSecN);
            sysprintf("        type:   ");
            ptPartition = ptPartition->ptNextPart;
        }
        ptPDiskPtr = ptPDiskPtr->ptPDiskAllLink;
    }
    fsReleaseDiskInformation(pDiskList);

}



#endif
/*
void fscopyAndCompare(void)
{




}
*/

void FormatRamDisk(void)
{
    PDISK_T       *pDiskList, *ptPDiskPtr;
    PARTITION_T   *ptPartition;
    INT           nDiskIdx = 0;
    INT           nPartIdx;
    ptPDiskPtr = pDiskList = fsGetFullDiskInfomation();
    while (ptPDiskPtr != NULL)
    {
        sysprintf("\n\n=== Disk %d (%s) ======================\n",
                  nDiskIdx++, (ptPDiskPtr->nDiskType &
                               DISK_TYPE_USB_DEVICE) ? "USB" : "IDE");
        sysprintf("    name:     [%s%s]\n", ptPDiskPtr->szManufacture,
                  ptPDiskPtr->szProduct);
        sysprintf("    head:     [%d]\n", ptPDiskPtr->nHeadNum);
        sysprintf("    sector:   [%d]\n", ptPDiskPtr->nSectorNum);
        sysprintf("    cylinder: [%d]\n", ptPDiskPtr->nCylinderNum);
        sysprintf("    size:     [%d MB]\n", ptPDiskPtr->uDiskSize / 1024);

        ptPartition = ptPDiskPtr->ptPartList;
        nPartIdx = 1;
        while (ptPartition != NULL)
        {
            sysprintf("\n    --- Partition %d --------------------\n",
                      nPartIdx++);
            sysprintf("        active: [%s]\n",
                      (ptPartition->ucState & 0x80) ? "Yes" : "No");
            sysprintf("        size:   [%d MB]\n",
                      (ptPartition->uTotalSecN / 1024) / 2);
            sysprintf("        start:  [%d]\n", ptPartition->uStartSecN);
            sysprintf("        type:   ");
            ptPartition = ptPartition->ptNextPart;
        }
        ptPDiskPtr = ptPDiskPtr->ptPDiskAllLink;
        fsFormatFlashMemoryCard(ptPDiskPtr);
    }
    fsReleaseDiskInformation(pDiskList);
}


INT  InitRAMDisk(UINT32 uStartAddr, UINT32 uDiskSize);
INT  UMAS_InitUmasDriver(void);
int main()
{
    WB_UART_T   uart;
    UINT32 u32ExtFreq;
    UINT32 u32PllOutHz;



#ifdef ENABLE_GNAND
    char        chr;
    UINT32 u32BlockSize, u32FreeSize, u32DiskSize, u32TotalSize;
#endif

    /* CACHE_ON */
    sysEnableCache(CACHE_WRITE_BACK);

    u32ExtFreq = sysGetExternalClock();
    uart.uart_no =  WB_UART_1;
    uart.uiFreq = u32ExtFreq;   //use APB clock
    uart.uiBaudrate = 115200;
    uart.uiDataBits = WB_DATA_BITS_8;
    uart.uiStopBits = WB_STOP_BITS_1;
    uart.uiParity = WB_PARITY_NONE;
    uart.uiRxTriggerLevel = LEVEL_1_BYTE;
    sysInitializeUART(&uart);

    u32PllOutHz = sysGetPLLOutputHz(eSYS_UPLL, u32ExtFreq);
    sysprintf("PLL out frequency %d Hz\n", u32PllOutHz);

    /**********************************************************************************************
     * Clock Constraints:
     * (a) If Memory Clock > System Clock, the source clock of Memory and System can come from
     *     different clock source. Suggestion MPLL for Memory Clock, UPLL for System Clock
     * (b) For Memory Clock = System Clock, the source clock of Memory and System must come from
     *     same clock source
     *********************************************************************************************/
#if 0
    /**********************************************************************************************
     * Slower down system and memory clock procedures:
     * If current working clock fast than desired working clock, Please follow the procedure below
     * 1. Change System Clock first
     * 2. Then change Memory Clock
     *
     * Following example shows the Memory Clock = System Clock case. User can specify different
     * Memory Clock and System Clock depends on DRAM bandwidth or power consumption requirement.
     *********************************************************************************************/
    sysSetSystemClock(eSYS_EXT, 12000000, 12000000);
    sysSetDramClock(eSYS_EXT, 12000000, 12000000);
#else
    /**********************************************************************************************
     * Speed up system and memory clock procedures:
     * If current working clock slower than desired working clock, Please follow the procedure below
     * 1. Change Memory Clock first
     * 2. Then change System Clock
     *
     * Following example shows to speed up clock case. User can specify different
     * Memory Clock and System Clock depends on DRAM bandwidth or power consumption requirement.
     *********************************************************************************************/
    sysSetDramClock(eSYS_MPLL, 360000000, 360000000);
    sysSetSystemClock(eSYS_UPLL,            //E_SYS_SRC_CLK eSrcClk,
                      240000000,            //UINT32 u32PllHz,
                      240000000);           //UINT32 u32SysHz,
    sysSetCPUClock(240000000/2);
#endif

    sysSetTimerReferenceClock (TIMER0, u32ExtFreq);
    sysStartTimer(TIMER0, 100, PERIODIC_MODE);

    sysprintf("fsInitFileSystem.\n");
    fsInitFileSystem();




#ifdef ENABLE_USB_HOST
    /* Depend on the board's layout */
    //USB_PortInit(HOST_NORMAL_PORT0_ONLY);
    //USB_PortInit(HOST_NORMAL_TWO_PORT);
    //USB_PortInit(HOST_LIKE_PORT0);
    //USB_PortInit(HOST_LIKE_PORT1);

    InitUsbSystem();
    UMAS_InitUmasDriver();
#endif

#if defined(ENABLE_SD)||defined(ENABLE_SD_TWO_PART)
    sicIoctl(SIC_SET_CLOCK, u32PllOutHz/1000, 0, 0);
    sicOpen();
    if (sicSdOpen0()<=0)
    {
        sysprintf("Error in initializing SD card !! \n");
        while(1);
    }
#endif
#ifdef ENABLE_SDIO_1
    sicIoctl(SIC_SET_CLOCK, u32PllOutHz/1000, 0, 0);    // clock from PLL
    sdioOpen();
    if (sdioSdOpen1()<=0)
    {
        sysprintf("Error in initializing SD card !! \n");
        while(1);
    }
#endif
#if defined(ENABLE_SD_ONE_PART)
    fsAssignDriveNumber('C', DISK_TYPE_SD_MMC, 0, 1);
#endif
#ifdef ENABLE_SD_TWO_PART
    fsAssignDriveNumber('C', DISK_TYPE_SD_MMC, 0, 1);
    fsAssignDriveNumber('D', DISK_TYPE_SD_MMC, 0, 2);
#endif
#ifdef ENABLE_SD_FOUR_PART
    fsAssignDriveNumber('C', DISK_TYPE_SD_MMC, 0, 1);
    fsAssignDriveNumber('D', DISK_TYPE_SD_MMC, 0, 2);
    fsAssignDriveNumber('E', DISK_TYPE_SD_MMC, 0, 3);
    fsAssignDriveNumber('F', DISK_TYPE_SD_MMC, 0, 4);
#endif
#if defined(ENABLE_SDIO_1)
    fsAssignDriveNumber('C', DISK_TYPE_SD_MMC, 0, 1);
#endif

#ifdef ENABLE_RAM
    memset(&i8RamDisk, 0, RAM_DISK_SIZE);
    InitRAMDisk((UINT32)&i8RamDisk, RAM_DISK_SIZE)  ;
    FormatRamDisk();
    fsSetVolumeLabel('D', "RAM", strlen("RAM"));
    //fsAssignDriveNumber('D', DISK_TYPE_HARD_DISK, 1, 1);
#endif

#ifdef ENABLE_GNAND
    {
        //fsAssignDriveNumber('C', DISK_TYPE_SMART_MEDIA, 0, 1);
        //fsAssignDriveNumber('D', DISK_TYPE_SMART_MEDIA, 0, 2);

        sicOpen();

        sysprintf("ENABLE_GNAND.\n");
        if(GNAND_InitNAND(&_nandDiskDriver0, &ptNDisk, TRUE) < 0)
        {
            sysprintf("GNAND_InitNAND error\n");
            exit(-1);
        }
        if(GNAND_MountNandDisk(&ptNDisk) < 0)
        {
            sysprintf("GNAND_MountNandDisk error\n");
            exit(-1);
        }
        u32TotalSize = ptNDisk.nZone* ptNDisk.nBlockPerZone*ptNDisk.nPagePerBlock*ptNDisk.nPageSize;
    }



    sysprintf("Do you want to format NAND flash? [Y/N]\n");
    chr = getchar();
    if( (chr == 'Y') || (chr == 'y') )
    {
        sysprintf("Total NAND size = %d KB\n", u32TotalSize/1024);
        if( fsTwoPartAndFormatAll((PDISK_T *)ptNDisk.pDisk,
                                  32*1024,
                                  (u32TotalSize/1024-32*1024))<0 )
        {
            sysprintf("Format failed\n");
            exit(-1);
        }

    }
    fsSetVolumeLabel('C', "NAND1-1\n", strlen("NAND1-1"));
    fsSetVolumeLabel('D', "NAND1-2\n", strlen("NAND1-2"));
    fsDiskFreeSpace('C', &u32BlockSize, &u32FreeSize, &u32DiskSize);
    sysprintf("block_size = %d\n", u32BlockSize);
    sysprintf("free_size = %d\n", u32FreeSize);
    sysprintf("disk_size = %d\n", u32DiskSize);
    g_u32TotalSize = u32DiskSize;
    sysprintf("Total NAND size = %d KB\n", g_u32TotalSize);
    fsDiskFreeSpace('D', &u32BlockSize, &u32FreeSize, &u32DiskSize);

    sysprintf("block_size = %d\n", u32BlockSize);
    sysprintf("free_size = %d\n", u32FreeSize);
    sysprintf("disk_size = %d\n", u32DiskSize);
    g_u32TotalSize = g_u32TotalSize+u32DiskSize;
    sysprintf("Total NAND size = %d KB\n", g_u32TotalSize);

#endif



#ifdef ECOS
    cyg_thread_create(20, CommandShell, 0, "cs",
                      _Statck, STACKSIZE, &thread_handle, &thread);
    cyg_thread_resume(thread_handle);
#else
    CommandShell();
#endif

    return 0;
}



