]> Chaos Git - corbenik/corbenik.git/commitdiff
Begin libctr9_io port, currently malfunctioning somehow
authorchaoskagami <chaos.kagami@gmail.com>
Fri, 8 Jul 2016 04:11:38 +0000 (00:11 -0400)
committerchaoskagami <chaos.kagami@gmail.com>
Fri, 8 Jul 2016 07:50:31 +0000 (03:50 -0400)
24 files changed:
.gitmodules
Makefile
external/libctr9_io [new submodule]
host/compile_ctr9_io.sh [new file with mode: 0755]
host/copy.sh
source/chain.c
source/fatfs/00readme.txt [deleted file]
source/fatfs/delay.s [deleted file]
source/fatfs/diskio.c [deleted file]
source/fatfs/diskio.h [deleted file]
source/fatfs/ff.c [deleted file]
source/fatfs/ff.h [deleted file]
source/fatfs/ffconf.h [deleted file]
source/fatfs/history.txt [deleted file]
source/fatfs/integer.h [deleted file]
source/fatfs/sdmmc.c [deleted file]
source/fatfs/sdmmc.h [deleted file]
source/firm/firm.c
source/menu.c
source/patch/emunand.c
source/patch/reboot.c
source/std/draw.c
source/std/fs.c
source/std/fs.h

index 0dd8102830fab36c874277c84726a9e77bd73219..d7c029684c59db971bfcb24071a5a47b6325ff72 100644 (file)
@@ -4,3 +4,6 @@
 [submodule "host/bdfe"]
        path = host/bdfe
        url = https://github.com/chaoskagami/bdfe
+[submodule "external/libctr9_io"]
+       path = external/libctr9_io
+       url = https://github.com/gemarcano/libctr9_io
index 9cd2e9788affa71a55ca27a5f8dd9879b12d20b7..8e250c6e797fd35c60bb90aae6524f6fce233eb8 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -46,16 +46,20 @@ REL ?= master
 CHAINLOADER ?= 1
 
 CROSS_ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
-CROSS_CFLAGS  := -MMD -MP -Wall -Wextra -Werror -fomit-frame-pointer -Os $(ASFLAGS) -fshort-wchar -fno-builtin -std=gnu11 -DVERSION=\"$(REVISION)\" -DREL=\"$(REL)\" -DCHAINLOADER=$(CHAINLOADER) -DPATH_CFW=\"/$(fw_folder)\" -DFW_NAME=\"$(fw_name)\" $(PATHARGS)
+CROSS_CFLAGS  := -MMD -MP -Wall -Wextra -Werror -fomit-frame-pointer -I$(shell pwd)/external/libctr9_io/out/include -Os $(ASFLAGS) -fshort-wchar -fno-builtin -std=gnu11 -DVERSION=\"$(REVISION)\" -DREL=\"$(REL)\" -DCHAINLOADER=$(CHAINLOADER) -DPATH_CFW=\"/$(fw_folder)\" -DFW_NAME=\"$(fw_name)\" $(PATHARGS)
 CROSS_FLAGS   := dir_out=$(abspath $(dir_out)) --no-print-directory
-CROSS_LDFLAGS := -nostdlib -Wl,-z,defs -lgcc -Wl,-Map,$(dir_build)/link.map
+CROSS_LDFLAGS := -nostdlib -Wl,-z,defs -lgcc -Wl,-Map,$(dir_build)/link.map -L$(shell pwd)/external/libctr9_io/out/lib -lctr9
 
 objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
                          $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
                          $(call rwildcard, $(dir_source), *.s *.c)))
 
 .PHONY: all
-all: hosttools font a9lh patch external
+all: hosttools font ctr9io a9lh patch external
+
+.PHONY: ctr9io
+ctr9io:
+       ./host/compile_ctr9_io.sh
 
 .PHONY: release
 release:
@@ -112,6 +116,7 @@ $(dir_out)/$(fw_folder)/locale: all
 .PHONY: clean
 clean:
        rm -f host/{font-emit,font.h,font_prop.h,termfont.bin}
+       cd external/libctr9_io && git clean -fxd
        make -C external dir_out=$(dir_out) fw_folder=$(fw_folder) root=$(root) clean
        make -C patch dir_out=$(dir_out) fw_folder=$(fw_folder) root=$(root) clean
        make -C host/bdfe dir_out=$(dir_out) fw_folder=$(fw_folder) root=$(root) clean
diff --git a/external/libctr9_io b/external/libctr9_io
new file mode 160000 (submodule)
index 0000000..f1e4074
--- /dev/null
@@ -0,0 +1 @@
+Subproject commit f1e407450e658883343d0877c4afcffe3bb697cc
diff --git a/host/compile_ctr9_io.sh b/host/compile_ctr9_io.sh
new file mode 100755 (executable)
index 0000000..61a9354
--- /dev/null
@@ -0,0 +1,16 @@
+#!/bin/bash
+
+unset CFLAGS
+unset LDFLAGS
+unset ASFLAGS
+unset CROSS_CFLAGS
+unset CROSS_LDFLAGS
+unset CROSS_ASFLAGS
+
+cd external/libctr9_io
+git clean -fxd
+autoreconf -fi
+./configure --host arm-none-eabi --prefix=$(pwd)/out
+make
+make install
+cd ../../
index 18d88444c51e93609b7e8813555d6eadeaa8a390..cd53e5e1fe26c6410d019f41362b8a01caede630 100755 (executable)
@@ -9,7 +9,7 @@ dev=/dev/sdb
 mnt=/mnt/ext1
 
 mount -t vfat ${dev}1 $mnt || exit 0
-rm -rf $mnt/{corbenik,skeith}
+rm -rf $mnt/corbenik
 cp -r out/* $mnt/ || exit 0
 cp -r input/* $mnt/ || exit 0
 cp out/arm9loaderhax.bin $mnt/corbenik/chain/Corbenik || exit 0
index db80493622dd9763698173f3a9096b9de3755fe8..906a90e03deb02851e64b24b0f5bf24a62be20b5 100644 (file)
@@ -75,7 +75,7 @@ void chainload_file(char* chain_file_data) {
 int
 list_chain_build_back(char *fpath)
 {
-    FILINFO fno = {.lfname = NULL };
+    FILINFO fno;
 
     // this code handles directory content deletion
     if (f_stat(fpath, &fno) != FR_OK)
@@ -87,9 +87,8 @@ list_chain_build_back(char *fpath)
         if (f_opendir(&pdir, fpath) != FR_OK)
             return 1;
 
-        *(fname++) = '/';
-        fno.lfname = fname;
-        fno.lfsize = fpath + 255 - fname;
+        fname[0] = '/';
+        fname++;
 
         while (f_readdir(&pdir, &fno) == FR_OK) {
             if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
@@ -103,7 +102,9 @@ list_chain_build_back(char *fpath)
         }
 
         f_closedir(&pdir);
-        *(--fname) = '\0';
+
+        --fname;
+        fname[0] = 0;
     } else {
         char* basename = &fpath[strlen(fpath) - 1];
         while(basename[0] != '/') basename--;
diff --git a/source/fatfs/00readme.txt b/source/fatfs/00readme.txt
deleted file mode 100644 (file)
index c46ac5f..0000000
+++ /dev/null
@@ -1,21 +0,0 @@
-FatFs Module Source Files R0.11
-
-
-FILES
-
-  00readme.txt This file.
-  history.txt  Revision history.
-  ffconf.h     Configuration file for FatFs module.
-  ff.h         Common include file for FatFs and application module.
-  ff.c         FatFs module.
-  diskio.h     Common include file for FatFs and disk I/O module.
-  diskio.c     An example of glue function to attach existing disk I/O module to FatFs.
-  integer.h    Integer type definitions for FatFs.
-  option       Optional external functions.
-
-
-  Low level disk I/O module is not included in this archive because the FatFs
-  module is only a generic file system layer and not depend on any specific
-  storage device. You have to provide a low level disk I/O module that written
-  to control the target storage device.
-
diff --git a/source/fatfs/delay.s b/source/fatfs/delay.s
deleted file mode 100644 (file)
index 77e42fa..0000000
+++ /dev/null
@@ -1,15 +0,0 @@
-.arm
-.global waitcycles
-.type   waitcycles STT_FUNC
-
-@waitcycles ( u32 us )
-waitcycles:
-    PUSH    {R0-R2,LR}
-    STR     R0, [SP,#4]
-    waitcycles_loop:
-        LDR     R3, [SP,#4]
-        SUBS    R2, R3, #1
-        STR     R2, [SP,#4]
-        CMP     R3, #0
-        BNE     waitcycles_loop
-    POP     {R0-R2,PC}
diff --git a/source/fatfs/diskio.c b/source/fatfs/diskio.c
deleted file mode 100644 (file)
index 9aedac3..0000000
+++ /dev/null
@@ -1,164 +0,0 @@
-/*-----------------------------------------------------------------------*/
-/* Low level disk I/O module skeleton for FatFs     (C)ChaN, 2014        */
-/*-----------------------------------------------------------------------*/
-/* If a working storage control module is available, it should be        */
-/* attached to the FatFs via a glue function rather than modifying it.   */
-/* This is an example of glue functions to attach various exsisting      */
-/* storage control modules to the FatFs module with a defined API.       */
-/*-----------------------------------------------------------------------*/
-
-#include <stddef.h>
-#include "diskio.h" /* FatFs lower layer API */
-#include "sdmmc.h"
-
-#define TYPE_NONE 0
-#define TYPE_SDCARD (1 << 4)
-
-#define SUBTYPE_NONE 5
-
-typedef struct
-{
-    BYTE type;
-    BYTE subtype;
-} FATpartition;
-
-typedef struct
-{
-    DWORD offset;
-    DWORD size;
-    BYTE keyslot;
-} SubtypeDesc;
-
-FATpartition DriveInfo[11] = {
-    { TYPE_SDCARD, SUBTYPE_NONE }, // 0 - SDCARD
-};
-
-/*-----------------------------------------------------------------------*/
-/* Get actual FAT partition type helper                                  */
-/*-----------------------------------------------------------------------*/
-
-static inline BYTE
-get_partition_type(__attribute__((unused)) BYTE pdrv /* Physical drive nmuber to identify the drive */
-                   )
-{
-    return DriveInfo[pdrv].type;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Get Drive Subtype helper                                              */
-/*-----------------------------------------------------------------------*/
-
-static inline SubtypeDesc *
-get_subtype_desc(__attribute__((unused)) BYTE pdrv /* Physical drive nmuber to identify the drive */
-                 )
-{
-    return NULL;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Get Drive Status                                                      */
-/*-----------------------------------------------------------------------*/
-
-DSTATUS
-disk_status(__attribute__((unused)) BYTE pdrv /* Physical drive nmuber to identify the drive */
-            )
-{
-    return RES_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Inidialize a Drive                                                    */
-/*-----------------------------------------------------------------------*/
-
-DSTATUS
-disk_initialize(__attribute__((unused)) BYTE pdrv /* Physical drive nmuber to identify the drive */
-                )
-{
-    if (pdrv == 0) { // a mounted SD card is the preriquisite for everything else
-        if (!sdmmc_sdcard_init())
-            return STA_NODISK;
-    }
-    return RES_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Read Sector(s)                                                        */
-/*-----------------------------------------------------------------------*/
-
-DRESULT
-disk_read(__attribute__((unused)) BYTE pdrv, /* Physical drive nmuber to identify the drive */
-          BYTE *buff,                        /* Data buffer to store read data */
-          DWORD sector,                      /* Sector address in LBA */
-          UINT count                         /* Number of sectors to read */
-          )
-{
-    BYTE type = get_partition_type(pdrv);
-
-    if (type == TYPE_NONE) {
-        return RES_PARERR;
-    } else if (type == TYPE_SDCARD) {
-        if (sdmmc_sdcard_readsectors(sector, count, buff))
-            return RES_PARERR;
-    }
-
-    return RES_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Write Sector(s)                                                       */
-/*-----------------------------------------------------------------------*/
-
-#if _USE_WRITE
-DRESULT
-disk_write(__attribute__((unused)) BYTE pdrv, /* Physical drive nmuber to identify the drive */
-           const BYTE *buff,                  /* Data to be written */
-           DWORD sector,                      /* Sector address in LBA */
-           UINT count                         /* Number of sectors to write */
-           )
-{
-    BYTE type = get_partition_type(pdrv);
-
-    if (type == TYPE_NONE) {
-        return RES_PARERR;
-    } else if (type == TYPE_SDCARD) {
-        if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
-            return RES_PARERR;
-    }
-
-    return RES_OK;
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Miscellaneous Functions                                               */
-/*-----------------------------------------------------------------------*/
-
-#if _USE_IOCTL
-DRESULT
-disk_ioctl(__attribute__((unused)) BYTE pdrv, /* Physical drive nmuber (0..) */
-           __attribute__((unused)) BYTE cmd,  /* Control code */
-           __attribute__((unused)) void *buff /* Buffer to send/receive control data */
-           )
-{
-    BYTE type = get_partition_type(pdrv);
-
-    switch (cmd) {
-        case GET_SECTOR_SIZE:
-            *((DWORD *)buff) = 0x200;
-            return RES_OK;
-        case GET_SECTOR_COUNT:
-            if (type == TYPE_SDCARD) { // SD card
-                *((DWORD *)buff) = getMMCDevice(1)->total_size;
-            }
-            return RES_OK;
-        case GET_BLOCK_SIZE:
-            *((DWORD *)buff) = 0x2000;
-            return RES_OK;
-        case CTRL_SYNC:
-            // nothing else to do here - sdmmc.c handles the rest
-            return RES_OK;
-    }
-
-    return RES_PARERR;
-}
-#endif
diff --git a/source/fatfs/diskio.h b/source/fatfs/diskio.h
deleted file mode 100644 (file)
index d116887..0000000
+++ /dev/null
@@ -1,75 +0,0 @@
-/*-----------------------------------------------------------------------/
-/  Low level disk interface modlue include file   (C)ChaN, 2014          /
-/-----------------------------------------------------------------------*/
-
-#ifndef _DISKIO_DEFINED
-#define _DISKIO_DEFINED
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#define _USE_WRITE 1 /* 1: Enable disk_write function */
-#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
-
-#include "integer.h"
-
-/* Status of Disk Functions */
-typedef BYTE DSTATUS;
-
-/* Results of Disk Functions */
-typedef enum {
-    RES_OK = 0, /* 0: Successful */
-    RES_ERROR,  /* 1: R/W Error */
-    RES_WRPRT,  /* 2: Write Protected */
-    RES_NOTRDY, /* 3: Not Ready */
-    RES_PARERR  /* 4: Invalid Parameter */
-} DRESULT;
-
-/*---------------------------------------*/
-/* Prototypes for disk control functions */
-
-DSTATUS disk_initialize(BYTE pdrv);
-DSTATUS disk_status(BYTE pdrv);
-DRESULT disk_read(BYTE pdrv, BYTE *buff, DWORD sector, UINT count);
-DRESULT disk_write(BYTE pdrv, const BYTE *buff, DWORD sector, UINT count);
-DRESULT disk_ioctl(BYTE pdrv, BYTE cmd, void *buff);
-
-/* Disk Status Bits (DSTATUS) */
-
-#define STA_NOINIT 0x01  /* Drive not initialized */
-#define STA_NODISK 0x02  /* No medium in the drive */
-#define STA_PROTECT 0x04 /* Write protected */
-
-/* Command code for disk_ioctrl fucntion */
-
-/* Generic command (Used by FatFs) */
-#define CTRL_SYNC 0        /* Complete pending write process (needed at _FS_READONLY == 0) */
-#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
-#define GET_SECTOR_SIZE 2  /* Get sector size (needed at _MAX_SS != _MIN_SS) */
-#define GET_BLOCK_SIZE 3   /* Get erase block size (needed at _USE_MKFS == 1) */
-#define CTRL_TRIM 4        /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
-
-/* Generic command (Not used by FatFs) */
-#define CTRL_POWER 5  /* Get/Set power status */
-#define CTRL_LOCK 6   /* Lock/Unlock media removal */
-#define CTRL_EJECT 7  /* Eject media */
-#define CTRL_FORMAT 8 /* Create physical format on the media */
-
-/* MMC/SDC specific ioctl command */
-#define MMC_GET_TYPE 10   /* Get card type */
-#define MMC_GET_CSD 11    /* Get CSD */
-#define MMC_GET_CID 12    /* Get CID */
-#define MMC_GET_OCR 13    /* Get OCR */
-#define MMC_GET_SDSTAT 14 /* Get SD status */
-
-/* ATA/CF specific ioctl command */
-#define ATA_GET_REV 20   /* Get F/W revision */
-#define ATA_GET_MODEL 21 /* Get model name */
-#define ATA_GET_SN 22    /* Get serial number */
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif
diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c
deleted file mode 100644 (file)
index 5eb62ec..0000000
+++ /dev/null
@@ -1,4936 +0,0 @@
-/*----------------------------------------------------------------------------/
-/  FatFs - FAT file system module  R0.11                 (C)ChaN, 2015
-/-----------------------------------------------------------------------------/
-/ FatFs module is a free software that opened under license policy of
-/ following conditions.
-/
-/ Copyright (C) 2015, ChaN, all right reserved.
-/
-/ 1. Redistributions of source code must retain the above copyright notice,
-/    this condition and the following disclaimer.
-/
-/ This software is provided by the copyright holder and contributors "AS IS"
-/ and any warranties related to this software are DISCLAIMED.
-/ The copyright owner or contributors be NOT LIABLE for any damages caused
-/ by use of this software.
-/----------------------------------------------------------------------------*/
-
-#include "ff.h"     /* Declarations of FatFs API */
-#include "diskio.h" /* Declarations of disk I/O functions */
-
-/*--------------------------------------------------------------------------
-
-   Module Private Definitions
-
----------------------------------------------------------------------------*/
-
-#if _FATFS != 32020 /* Revision ID */
-#error Wrong include file (ff.h).
-#endif
-
-/* Reentrancy related */
-#if _FS_REENTRANT
-#if _USE_LFN == 1
-#error Static LFN work area cannot be used at thread-safe configuration
-#endif
-#define ENTER_FF(fs)                                                                                                                                           \
-    {                                                                                                                                                          \
-        if (!lock_fs(fs))                                                                                                                                      \
-            return FR_TIMEOUT;                                                                                                                                 \
-    }
-#define LEAVE_FF(fs, res)                                                                                                                                      \
-    {                                                                                                                                                          \
-        unlock_fs(fs, res);                                                                                                                                    \
-        return res;                                                                                                                                            \
-    }
-#else
-#define ENTER_FF(fs)
-#define LEAVE_FF(fs, res) return res
-#endif
-
-#define ABORT(fs, res)                                                                                                                                         \
-    {                                                                                                                                                          \
-        fp->err = (BYTE)(res);                                                                                                                                 \
-        LEAVE_FF(fs, res);                                                                                                                                     \
-    }
-
-/* Definitions of sector size */
-#if (_MAX_SS < _MIN_SS) || (_MAX_SS != 512 && _MAX_SS != 1024 && _MAX_SS != 2048 && _MAX_SS != 4096) ||                                                        \
-    (_MIN_SS != 512 && _MIN_SS != 1024 && _MIN_SS != 2048 && _MIN_SS != 4096)
-#error Wrong sector size configuration
-#endif
-#if _MAX_SS == _MIN_SS
-#define SS(fs) ((UINT)_MAX_SS) /* Fixed sector size */
-#else
-#define SS(fs) ((fs)->ssize) /* Variable sector size */
-#endif
-
-/* Timestamp feature */
-#if _FS_NORTC == 1
-#if _NORTC_YEAR < 1980 || _NORTC_YEAR > 2107 || _NORTC_MON < 1 || _NORTC_MON > 12 || _NORTC_MDAY < 1 || _NORTC_MDAY > 31
-#error Invalid _FS_NORTC settings
-#endif
-#define GET_FATTIME() ((DWORD)(_NORTC_YEAR - 1980) << 25 | (DWORD)_NORTC_MON << 21 | (DWORD)_NORTC_MDAY << 16)
-#else
-#define GET_FATTIME() get_fattime()
-#endif
-
-/* File access control feature */
-#if _FS_LOCK
-#if _FS_READONLY
-#error _FS_LOCK must be 0 at read-only configuration
-#endif
-typedef struct
-{
-    FATFS *fs; /* Object ID 1, volume (NULL:blank entry) */
-    DWORD clu; /* Object ID 2, directory (0:root) */
-    WORD idx;  /* Object ID 3, directory index */
-    WORD ctr;  /* Object open counter, 0:none, 0x01..0xFF:read mode open count, 0x100:write mode */
-} FILESEM;
-#endif
-
-/* DBCS code ranges and SBCS extend character conversion table */
-
-#if _CODE_PAGE == 932 /* Japanese Shift-JIS */
-#define _DF1S 0x81    /* DBC 1st byte range 1 start */
-#define _DF1E 0x9F    /* DBC 1st byte range 1 end */
-#define _DF2S 0xE0    /* DBC 1st byte range 2 start */
-#define _DF2E 0xFC    /* DBC 1st byte range 2 end */
-#define _DS1S 0x40    /* DBC 2nd byte range 1 start */
-#define _DS1E 0x7E    /* DBC 2nd byte range 1 end */
-#define _DS2S 0x80    /* DBC 2nd byte range 2 start */
-#define _DS2E 0xFC    /* DBC 2nd byte range 2 end */
-
-#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
-#define _DF1S 0x81
-#define _DF1E 0xFE
-#define _DS1S 0x40
-#define _DS1E 0x7E
-#define _DS2S 0x80
-#define _DS2E 0xFE
-
-#elif _CODE_PAGE == 949 /* Korean */
-#define _DF1S 0x81
-#define _DF1E 0xFE
-#define _DS1S 0x41
-#define _DS1E 0x5A
-#define _DS2S 0x61
-#define _DS2E 0x7A
-#define _DS3S 0x81
-#define _DS3E 0xFE
-
-#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
-#define _DF1S 0x81
-#define _DF1E 0xFE
-#define _DS1S 0x40
-#define _DS1E 0x7E
-#define _DS2S 0xA1
-#define _DS2E 0xFE
-
-#elif _CODE_PAGE == 437 /* U.S. (OEM) */
-#define _DF1S 0
-/*#define _EXCVT
-   {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,
-   \
-                0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF,
-   \
-                0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF,
-   \
-                0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/
-
-static const unsigned short Tbl[] = { /*  CP437(0x80-0xFF) to Unicode conversion table */
-                                      0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4,
-                                      0x00C5, 0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5,
-                                      0x20A7, 0x0192, 0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC,
-                                      0x00A1, 0x00AB, 0x00BB, 0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557,
-                                      0x255D, 0x255C, 0x255B, 0x2510, 0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569,
-                                      0x2566, 0x2560, 0x2550, 0x256C, 0x2567, 0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518,
-                                      0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580, 0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6,
-                                      0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229, 0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
-                                      0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
-};
-
-WCHAR
-ff_convert(           /* Converted character, Returns zero on error */
-           WCHAR src, /* Character code to be converted */
-           UINT dir   /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
-           )
-{
-    WCHAR c;
-
-    if (src < 0x80) { /* ASCII */
-        c = src;
-    } else {
-        if (dir) { /* OEMCP to Unicode */
-            c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
-        } else { /* Unicode to OEMCP */
-            for (c = 0; c < 0x80; c++) {
-                if (src == Tbl[c])
-                    break;
-            }
-            c = (c + 0x80) & 0xFF;
-        }
-    }
-
-    return c;
-}
-
-WCHAR
-ff_wtoupper(WCHAR chr)
-{
-    if (chr >= 'a' && chr <= 'z')
-        return (chr - 32);
-    else
-        return chr;
-}
-
-#elif _CODE_PAGE == 720 /* Arabic (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x45, 0x41, 0x84, 0x41, 0x86, 0x43, 0x45, 0x45, 0x45, 0x49, 0x49, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0x93, 0x94, 0x95, 0x49, 0x49, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 737 /* Greek (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x80,  \
-            0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0xAA, 0x92, 0x93, 0x94, 0x95, 0x96, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x97,    \
-            0xEA, 0xEB, 0xEC, 0xE4, 0xED, 0xEE, 0xE7, 0xE8, 0xF1, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 775 /* Baltic (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x9A, 0x91, 0xA0, 0x8E, 0x95, 0x8F, 0x80, 0xAD, 0xED, 0x8A, 0x8A, 0xA1, 0x8D, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0x95, 0x96, 0x97, 0x97,  \
-            0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xE0, 0xA3, 0xA3, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xB5, 0xB6, 0xB7, 0xB8, 0xBD, 0xBE, 0xC6, 0xC7, 0xA5, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE3, 0xE8, 0xE8, 0xEA, 0xEA, 0xEE, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, 0x59,  \
-            0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0x21, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE7, 0xE9, 0xEA, 0xEB, 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xDE, 0x8F, 0x80, 0x9D, 0xD3, 0x8A, 0x8A, 0xD7, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x91, 0xE2, 0x99, 0x95, 0x95, 0x97, 0x97,  \
-            0x99, 0x9A, 0x9B, 0x9B, 0x9D, 0x9E, 0x9F, 0xB5, 0xD6, 0xE0, 0xE9, 0xA4, 0xA4, 0xA6, 0xA6, 0xA8, 0xA8, 0xAA, 0x8D, 0xAC, 0xB8, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBD, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC6, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD2, 0xD3, 0xD2, 0xD5, 0xD6, 0xD7, 0xB7, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE3, 0xD5, 0xE6, 0xE6, 0xE8, 0xE9, 0xE8, 0xEB, 0xED, 0xED, 0xDD, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xEB, 0xFC, 0xFC, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x81, 0x81, 0x83, 0x83, 0x85, 0x85, 0x87, 0x87, 0x89, 0x89, 0x8B, 0x8B, 0x8D, 0x8D, 0x8F, 0x8F, 0x91, 0x91, 0x93, 0x93, 0x95, 0x95, 0x97, 0x97, 0x99,  \
-            0x99, 0x9B, 0x9B, 0x9D, 0x9D, 0x9F, 0x9F, 0xA1, 0xA1, 0xA3, 0xA3, 0xA5, 0xA5, 0xA7, 0xA7, 0xA9, 0xA9, 0xAB, 0xAB, 0xAD, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB6, 0xB6, 0xB8, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBE, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD3, 0xD3, 0xD5, 0xD5, 0xD7, 0xD7, 0xDD, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xE0, 0xDF, 0xE0,    \
-            0xE2, 0xE2, 0xE4, 0xE4, 0xE6, 0xE6, 0xE8, 0xE8, 0xEA, 0xEA, 0xEC, 0xEC, 0xEE, 0xEE, 0xEF, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8, 0xF8,    \
-            0xFA, 0xFA, 0xFC, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 857 /* Turkish (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0x98, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, 0x98,  \
-            0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9E, 0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA6, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0x21, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xDE, 0x59, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x9A, 0x90, 0xB6, 0x8E, 0xB7, 0x8F, 0x80, 0xD2, 0xD3, 0xD4, 0xD8, 0xD7, 0xDE, 0x8E, 0x8F, 0x90, 0x92, 0x92, 0xE2, 0x99, 0xE3, 0xEA, 0xEB, 0x59,  \
-            0x99, 0x9A, 0x9D, 0x9C, 0x9D, 0x9E, 0x9F, 0xB5, 0xD6, 0xE0, 0xE9, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0x21, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC7, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD1, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE5, 0xE5, 0xE6, 0xE7, 0xE7, 0xE9, 0xEA, 0xEB, 0xED, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 862 /* Hebrew (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x41, 0x49, 0x4F, 0x55, 0xA5, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0x21, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 866 /* Russian (OEM) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x90,    \
-            0x91, 0x92, 0x93, 0x9d, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xF0, 0xF0, 0xF2, 0xF2, 0xF4, 0xF4, 0xF6, 0xF6, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x8A, 0x9B, 0x8C, 0x8D, 0x8E, 0x8F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xA3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xA5, 0xAA, 0xBB, 0xBC, 0xBD, 0xBC, 0xAF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x82, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x80, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x8A, 0x9B, 0x8C, 0x8D, 0x8E, 0x8F, 0xA0, 0xA2, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB2, 0xA5, 0xB5, 0xB6, 0xB7, 0xA8, 0xB9, 0xAA, 0xBB, 0xA3, 0xBD, 0xBD, 0xAF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0xAd, 0x9B, 0x8C, 0x9D, 0xAE, 0x9F, 0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x9F                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1253 /* Greek (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xA2, 0xB8, 0xB9, 0xBA, 0xE0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xF2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8,    \
-            0xD9, 0xDA, 0xFB, 0xBC, 0xFD, 0xBF, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1254 /* Turkish (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x8A, 0x9B, 0x8C, 0x9D, 0x9E, 0x9F, 0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0x9F                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xE0,    \
-            0xE1, 0xE2, 0xE3, 0xE4, 0xE5, 0xE6, 0xE7, 0xE8, 0xE9, 0xEA, 0xEB, 0xEC, 0xED, 0xEE, 0xEF, 0xF0, 0xF1, 0xF2, 0xF3, 0xF4, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0xF9, 0xFA, 0xFB, 0xFC, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x8C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0x41,    \
-            0xE1, 0x41, 0xE3, 0xE4, 0xE5, 0xE6, 0x43, 0x45, 0x45, 0x45, 0x45, 0xEC, 0xED, 0x49, 0x49, 0xF0, 0xF1, 0xF2, 0xF3, 0x4F, 0xF5, 0xF6, 0xF7, 0xF8,    \
-            0x55, 0xFA, 0x55, 0x55, 0xFD, 0xFE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0x9C, 0x9D, 0x9E, 0x9F, 0xA0, 0xA1, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xA8, 0xB9, 0xAA, 0xBB, 0xBC, 0xBD, 0xBE, 0xAF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xFF                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
-#define _DF1S 0
-#define _EXCVT                                                                                                                                                 \
-    {                                                                                                                                                          \
-        0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8A, 0x8B, 0x8C, 0x8D, 0x8E, 0x8F, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98,  \
-            0x99, 0x9A, 0x9B, 0xAC, 0x9D, 0x9E, 0x9F, 0xA0, 0x21, 0xA2, 0xA3, 0xA4, 0xA5, 0xA6, 0xA7, 0xA8, 0xA9, 0xAA, 0xAB, 0xAC, 0xAD, 0xAE, 0xAF, 0xB0,    \
-            0xB1, 0xB2, 0xB3, 0xB4, 0xB5, 0xB6, 0xB7, 0xB8, 0xB9, 0xBA, 0xBB, 0xBC, 0xBD, 0xBE, 0xBF, 0xC0, 0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8,    \
-            0xC9, 0xCA, 0xCB, 0xCC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xD2, 0xD3, 0xD4, 0xD5, 0xD6, 0xD7, 0xD8, 0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xDE, 0xDF, 0xC0,    \
-            0xC1, 0xC2, 0xC3, 0xC4, 0xC5, 0xC6, 0xC7, 0xC8, 0xC9, 0xCA, 0xCB, 0xEC, 0xCD, 0xCE, 0xCF, 0xD0, 0xD1, 0xF2, 0xD3, 0xD4, 0xD5, 0xD6, 0xF7, 0xD8,    \
-            0xD9, 0xDA, 0xDB, 0xDC, 0xDD, 0xFE, 0x9F                                                                                                           \
-    }
-
-#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
-#if _USE_LFN
-#error Cannot use LFN feature without valid code page.
-#endif
-#define _DF1S 0
-
-#else
-#error Unknown code page
-
-#endif
-
-/* Character code support macros */
-#define IsUpper(c) (((c) >= 'A') && ((c) <= 'Z'))
-#define IsLower(c) (((c) >= 'a') && ((c) <= 'z'))
-#define IsDigit(c) (((c) >= '0') && ((c) <= '9'))
-
-#if _DF1S /* Code page is DBCS */
-
-#ifdef _DF2S /* Two 1st byte areas */
-#define IsDBCS1(c) (((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E) || ((BYTE)(c) >= _DF2S && (BYTE)(c) <= _DF2E))
-#else /* One 1st byte area */
-#define IsDBCS1(c) ((BYTE)(c) >= _DF1S && (BYTE)(c) <= _DF1E)
-#endif
-
-#ifdef _DS3S /* Three 2nd byte areas */
-#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E) || ((BYTE)(c) >= _DS3S && (BYTE)(c) <= _DS3E))
-#else /* Two 2nd byte areas */
-#define IsDBCS2(c) (((BYTE)(c) >= _DS1S && (BYTE)(c) <= _DS1E) || ((BYTE)(c) >= _DS2S && (BYTE)(c) <= _DS2E))
-#endif
-
-#else /* Code page is SBCS */
-
-#define IsDBCS1(c) 0
-#define IsDBCS2(c) 0
-
-#endif /* _DF1S */
-
-/* Name status flags */
-#define NSFLAG 11    /* Index of name status byte in fn[] */
-#define NS_LOSS 0x01 /* Out of 8.3 format */
-#define NS_LFN 0x02  /* Force to create LFN entry */
-#define NS_LAST 0x04 /* Last segment */
-#define NS_BODY 0x08 /* Lower case flag (body) */
-#define NS_EXT 0x10  /* Lower case flag (ext) */
-#define NS_DOT 0x20  /* Dot entry */
-
-/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */
-#define MIN_FAT16 4086U  /* Minimum number of clusters as FAT16 */
-#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */
-
-/* FatFs refers the members in the FAT structures as byte array instead of
-/ structure member because the structure is not binary compatible between
-/ different platforms */
-
-#define BS_jmpBoot 0       /* x86 jump instruction (3) */
-#define BS_OEMName 3       /* OEM name (8) */
-#define BPB_BytsPerSec 11  /* Sector size [byte] (2) */
-#define BPB_SecPerClus 13  /* Cluster size [sector] (1) */
-#define BPB_RsvdSecCnt 14  /* Size of reserved area [sector] (2) */
-#define BPB_NumFATs 16     /* Number of FAT copies (1) */
-#define BPB_RootEntCnt 17  /* Number of root directory entries for FAT12/16 (2) */
-#define BPB_TotSec16 19    /* Volume size [sector] (2) */
-#define BPB_Media 21       /* Media descriptor (1) */
-#define BPB_FATSz16 22     /* FAT size [sector] (2) */
-#define BPB_SecPerTrk 24   /* Track size [sector] (2) */
-#define BPB_NumHeads 26    /* Number of heads (2) */
-#define BPB_HiddSec 28     /* Number of special hidden sectors (4) */
-#define BPB_TotSec32 32    /* Volume size [sector] (4) */
-#define BS_DrvNum 36       /* Physical drive number (2) */
-#define BS_BootSig 38      /* Extended boot signature (1) */
-#define BS_VolID 39        /* Volume serial number (4) */
-#define BS_VolLab 43       /* Volume label (8) */
-#define BS_FilSysType 54   /* File system type (1) */
-#define BPB_FATSz32 36     /* FAT size [sector] (4) */
-#define BPB_ExtFlags 40    /* Extended flags (2) */
-#define BPB_FSVer 42       /* File system version (2) */
-#define BPB_RootClus 44    /* Root directory first cluster (4) */
-#define BPB_FSInfo 48      /* Offset of FSINFO sector (2) */
-#define BPB_BkBootSec 50   /* Offset of backup boot sector (2) */
-#define BS_DrvNum32 64     /* Physical drive number (2) */
-#define BS_BootSig32 66    /* Extended boot signature (1) */
-#define BS_VolID32 67      /* Volume serial number (4) */
-#define BS_VolLab32 71     /* Volume label (8) */
-#define BS_FilSysType32 82 /* File system type (1) */
-#define FSI_LeadSig 0      /* FSI: Leading signature (4) */
-#define FSI_StrucSig 484   /* FSI: Structure signature (4) */
-#define FSI_Free_Count 488 /* FSI: Number of free clusters (4) */
-#define FSI_Nxt_Free 492   /* FSI: Last allocated cluster (4) */
-#define MBR_Table 446      /* MBR: Partition table offset (2) */
-#define SZ_PTE 16          /* MBR: Size of a partition table entry */
-#define BS_55AA 510        /* Signature word (2) */
-
-#define DIR_Name 0          /* Short file name (11) */
-#define DIR_Attr 11         /* Attribute (1) */
-#define DIR_NTres 12        /* Lower case flag (1) */
-#define DIR_CrtTimeTenth 13 /* Created time sub-second (1) */
-#define DIR_CrtTime 14      /* Created time (2) */
-#define DIR_CrtDate 16      /* Created date (2) */
-#define DIR_LstAccDate 18   /* Last accessed date (2) */
-#define DIR_FstClusHI 20    /* Higher 16-bit of first cluster (2) */
-#define DIR_WrtTime 22      /* Modified time (2) */
-#define DIR_WrtDate 24      /* Modified date (2) */
-#define DIR_FstClusLO 26    /* Lower 16-bit of first cluster (2) */
-#define DIR_FileSize 28     /* File size (4) */
-#define LDIR_Ord 0          /* LFN entry order and LLE flag (1) */
-#define LDIR_Attr 11        /* LFN attribute (1) */
-#define LDIR_Type 12        /* LFN type (1) */
-#define LDIR_Chksum 13      /* Sum of corresponding SFN entry */
-#define LDIR_FstClusLO 26   /* Must be zero (0) */
-#define SZ_DIRE 32          /* Size of a directory entry */
-#define LLEF 0x40           /* Last long entry flag in LDIR_Ord */
-#define DDEM 0xE5           /* Deleted directory entry mark at DIR_Name[0] */
-#define RDDEM 0x05          /* Replacement of the character collides with DDEM */
-
-/*------------------------------------------------------------*/
-/* Module private work area                                   */
-/*------------------------------------------------------------*/
-/* Remark: Uninitialized variables with static duration are
-/  guaranteed zero/null at start-up. If not, either the linker
-/  or start-up routine being used is out of ANSI-C standard.
-*/
-
-#if _VOLUMES < 1 || _VOLUMES > 10 // <--- increased the limit to 10 (this won't break anything, no?)
-#error Wrong _VOLUMES setting
-#endif
-static FATFS *FatFs[_VOLUMES]; /* Pointer to the file system objects (logical drives) */
-static WORD Fsid;              /* File system mount ID */
-
-#if _FS_RPATH && _VOLUMES >= 2
-static BYTE CurrVol; /* Current drive */
-#endif
-
-#if _FS_LOCK
-static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */
-#endif
-
-#if _USE_LFN == 0 /* Non LFN feature */
-#define DEFINE_NAMEBUF BYTE sfn[12]
-#define INIT_BUF(dobj) (dobj).fn = sfn
-#define FREE_BUF()
-#else
-#if _MAX_LFN < 12 || _MAX_LFN > 255
-#error Wrong _MAX_LFN setting
-#endif
-#if _USE_LFN == 1 /* LFN feature with static working buffer */
-static WCHAR LfnBuf[_MAX_LFN + 1];
-#define DEFINE_NAMEBUF BYTE sfn[12]
-#define INIT_BUF(dobj)                                                                                                                                         \
-    {                                                                                                                                                          \
-        (dobj).fn = sfn;                                                                                                                                       \
-        (dobj).lfn = LfnBuf;                                                                                                                                   \
-    }
-#define FREE_BUF()
-#elif _USE_LFN == 2 /* LFN feature with dynamic working buffer on the stack */
-#define DEFINE_NAMEBUF                                                                                                                                         \
-    BYTE sfn[12];                                                                                                                                              \
-    WCHAR lbuf[_MAX_LFN + 1]
-#define INIT_BUF(dobj)                                                                                                                                         \
-    {                                                                                                                                                          \
-        (dobj).fn = sfn;                                                                                                                                       \
-        (dobj).lfn = lbuf;                                                                                                                                     \
-    }
-#define FREE_BUF()
-#elif _USE_LFN == 3 /* LFN feature with dynamic working buffer on the heap */
-#define DEFINE_NAMEBUF                                                                                                                                         \
-    BYTE sfn[12];                                                                                                                                              \
-    WCHAR *lfn
-#define INIT_BUF(dobj)                                                                                                                                         \
-    {                                                                                                                                                          \
-        lfn = ff_memalloc((_MAX_LFN + 1) * 2);                                                                                                                 \
-        if (!lfn)                                                                                                                                              \
-            LEAVE_FF((dobj).fs, FR_NOT_ENOUGH_CORE);                                                                                                           \
-        (dobj).lfn = lfn;                                                                                                                                      \
-        (dobj).fn = sfn;                                                                                                                                       \
-    }
-#define FREE_BUF() ff_memfree(lfn)
-#else
-#error Wrong _USE_LFN setting
-#endif
-#endif
-
-#ifdef _EXCVT
-static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */
-#endif
-
-/*--------------------------------------------------------------------------
-
-   Module Private Functions
-
----------------------------------------------------------------------------*/
-
-/*-----------------------------------------------------------------------*/
-/* String functions                                                      */
-/*-----------------------------------------------------------------------*/
-
-/* Copy memory to memory */
-static void
-mem_cpy(void *dst, const void *src, UINT cnt)
-{
-    BYTE *d = (BYTE *)dst;
-    const BYTE *s = (const BYTE *)src;
-
-#if _WORD_ACCESS == 1
-    while (cnt >= sizeof(int)) {
-        *(int *)d = *(int *)s;
-        d += sizeof(int);
-        s += sizeof(int);
-        cnt -= sizeof(int);
-    }
-#endif
-    while (cnt--)
-        *d++ = *s++;
-}
-
-/* Fill memory */
-static void
-mem_set(void *dst, int val, UINT cnt)
-{
-    BYTE *d = (BYTE *)dst;
-
-    while (cnt--)
-        *d++ = (BYTE)val;
-}
-
-/* Compare memory to memory */
-static int
-mem_cmp(const void *dst, const void *src, UINT cnt)
-{
-    const BYTE *d = (const BYTE *)dst, *s = (const BYTE *)src;
-    int r = 0;
-
-    while (cnt-- && (r = *d++ - *s++) == 0)
-        ;
-    return r;
-}
-
-/* Check if chr is contained in the string */
-static int
-chk_chr(const char *str, int chr)
-{
-    while (*str && *str != chr)
-        str++;
-    return *str;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Request/Release grant to access the volume                            */
-/*-----------------------------------------------------------------------*/
-#if _FS_REENTRANT
-static int
-lock_fs(FATFS *fs /* File system object */
-        )
-{
-    return ff_req_grant(fs->sobj);
-}
-
-static void
-unlock_fs(FATFS *fs,  /* File system object */
-          FRESULT res /* Result code to be returned */
-          )
-{
-    if (fs && res != FR_NOT_ENABLED && res != FR_INVALID_DRIVE && res != FR_INVALID_OBJECT && res != FR_TIMEOUT) {
-        ff_rel_grant(fs->sobj);
-    }
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* File lock control functions                                           */
-/*-----------------------------------------------------------------------*/
-#if _FS_LOCK
-
-static FRESULT
-chk_lock(         /* Check if the file can be accessed */
-         DIR *dp, /* Directory object pointing the file to be checked */
-         int acc  /* Desired access type (0:Read, 1:Write, 2:Delete/Rename) */
-         )
-{
-    UINT i, be;
-
-    /* Search file semaphore table */
-    for (i = be = 0; i < _FS_LOCK; i++) {
-        if (Files[i].fs) {               /* Existing entry */
-            if (Files[i].fs == dp->fs && /* Check if the object matched with an open object */
-                Files[i].clu == dp->sclust && Files[i].idx == dp->index)
-                break;
-        } else { /* Blank entry */
-            be = 1;
-        }
-    }
-    if (i == _FS_LOCK)                                            /* The object is not opened */
-        return (be || acc == 2) ? FR_OK : FR_TOO_MANY_OPEN_FILES; /* Is there a blank entry for new object? */
-
-    /* The object has been opened. Reject any open against writing file and all write mode open */
-    return (acc || Files[i].ctr == 0x100) ? FR_LOCKED : FR_OK;
-}
-
-static int enq_lock(void) /* Check if an entry is available for a new object */
-{
-    UINT i;
-
-    for (i = 0; i < _FS_LOCK && Files[i].fs; i++)
-        ;
-    return (i == _FS_LOCK) ? 0 : 1;
-}
-
-static UINT
-inc_lock(         /* Increment object open counter and returns its index (0:Internal error) */
-         DIR *dp, /* Directory object pointing the file to register or increment */
-         int acc  /* Desired access (0:Read, 1:Write, 2:Delete/Rename) */
-         )
-{
-    UINT i;
-
-    for (i = 0; i < _FS_LOCK; i++) { /* Find the object */
-        if (Files[i].fs == dp->fs && Files[i].clu == dp->sclust && Files[i].idx == dp->index)
-            break;
-    }
-
-    if (i == _FS_LOCK) { /* Not opened. Register it as new. */
-        for (i = 0; i < _FS_LOCK && Files[i].fs; i++)
-            ;
-        if (i == _FS_LOCK)
-            return 0; /* No free entry to register (int err) */
-        Files[i].fs = dp->fs;
-        Files[i].clu = dp->sclust;
-        Files[i].idx = dp->index;
-        Files[i].ctr = 0;
-    }
-
-    if (acc && Files[i].ctr)
-        return 0; /* Access violation (int err) */
-
-    Files[i].ctr = acc ? 0x100 : Files[i].ctr + 1; /* Set semaphore value */
-
-    return i + 1;
-}
-
-static FRESULT
-dec_lock(       /* Decrement object open counter */
-         UINT i /* Semaphore index (1..) */
-         )
-{
-    WORD n;
-    FRESULT res;
-
-    if (--i < _FS_LOCK) { /* Shift index number origin from 0 */
-        n = Files[i].ctr;
-        if (n == 0x100)
-            n = 0; /* If write mode open, delete the entry */
-        if (n)
-            n--; /* Decrement read mode open count */
-        Files[i].ctr = n;
-        if (!n)
-            Files[i].fs = 0; /* Delete the entry if open count gets zero */
-        res = FR_OK;
-    } else {
-        res = FR_INT_ERR; /* Invalid index nunber */
-    }
-    return res;
-}
-
-static void
-clear_lock(/* Clear lock entries of the volume */
-           FATFS *fs)
-{
-    UINT i;
-
-    for (i = 0; i < _FS_LOCK; i++) {
-        if (Files[i].fs == fs)
-            Files[i].fs = 0;
-    }
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Move/Flush disk access window in the file system object               */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
-static FRESULT
-sync_window(FATFS *fs /* File system object */
-            )
-{
-    DWORD wsect;
-    UINT nf;
-    FRESULT res = FR_OK;
-
-    if (fs->wflag) {         /* Write back the sector if it is dirty */
-        wsect = fs->winsect; /* Current sector number */
-        if (disk_write(fs->drv, fs->win, wsect, 1) != RES_OK) {
-            res = FR_DISK_ERR;
-        } else {
-            fs->wflag = 0;
-            if (wsect - fs->fatbase < fs->fsize) {     /* Is it in the FAT area? */
-                for (nf = fs->n_fats; nf >= 2; nf--) { /* Reflect the change to all FAT copies */
-                    wsect += fs->fsize;
-                    disk_write(fs->drv, fs->win, wsect, 1);
-                }
-            }
-        }
-    }
-    return res;
-}
-#endif
-
-static FRESULT
-move_window(FATFS *fs,   /* File system object */
-            DWORD sector /* Sector number to make appearance in the fs->win[] */
-            )
-{
-    FRESULT res = FR_OK;
-
-    if (sector != fs->winsect) { /* Window offset changed? */
-#if !_FS_READONLY
-        res = sync_window(fs); /* Write-back changes */
-#endif
-        if (res == FR_OK) { /* Fill sector window with new data */
-            if (disk_read(fs->drv, fs->win, sector, 1) != RES_OK) {
-                sector = 0xFFFFFFFF; /* Invalidate window if data is not reliable */
-                res = FR_DISK_ERR;
-            }
-            fs->winsect = sector;
-        }
-    }
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Synchronize file system and strage device                             */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
-static FRESULT
-sync_fs(          /* FR_OK: successful, FR_DISK_ERR: failed */
-        FATFS *fs /* File system object */
-        )
-{
-    FRESULT res;
-
-    res = sync_window(fs);
-    if (res == FR_OK) {
-        /* Update FSINFO sector if needed */
-        if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
-            /* Create FSINFO structure */
-            mem_set(fs->win, 0, SS(fs));
-            ST_WORD(fs->win + BS_55AA, 0xAA55);
-            ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
-            ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
-            ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
-            ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
-            /* Write it into the FSINFO sector */
-            fs->winsect = fs->volbase + 1;
-            disk_write(fs->drv, fs->win, fs->winsect, 1);
-            fs->fsi_flag = 0;
-        }
-        /* Make sure that no pending write process in the physical drive */
-        if (disk_ioctl(fs->drv, CTRL_SYNC, 0) != RES_OK)
-            res = FR_DISK_ERR;
-    }
-
-    return res;
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Get sector# from cluster#                                             */
-/*-----------------------------------------------------------------------*/
-/* Hidden API for hacks and disk tools */
-
-DWORD
-clust2sect(           /* !=0: Sector number, 0: Failed - invalid cluster# */
-           FATFS *fs, /* File system object */
-           DWORD clst /* Cluster# to be converted */
-           )
-{
-    clst -= 2;
-    if (clst >= fs->n_fatent - 2)
-        return 0; /* Invalid cluster# */
-    return clst * fs->csize + fs->database;
-}
-
-/*-----------------------------------------------------------------------*/
-/* FAT access - Read value of a FAT entry                                */
-/*-----------------------------------------------------------------------*/
-/* Hidden API for hacks and disk tools */
-
-DWORD
-get_fat(           /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
-        FATFS *fs, /* File system object */
-        DWORD clst /* FAT index number (cluster number) to get the value */
-        )
-{
-    UINT wc, bc;
-    BYTE *p;
-    DWORD val;
-
-    if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
-        val = 1;                            /* Internal error */
-
-    } else {
-        val = 0xFFFFFFFF; /* Default value falls on disk error */
-
-        switch (fs->fs_type) {
-            case FS_FAT12:
-                bc = (UINT)clst;
-                bc += bc / 2;
-                if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK)
-                    break;
-                wc = fs->win[bc++ % SS(fs)];
-                if (move_window(fs, fs->fatbase + (bc / SS(fs))) != FR_OK)
-                    break;
-                wc |= fs->win[bc % SS(fs)] << 8;
-                val = clst & 1 ? wc >> 4 : (wc & 0xFFF);
-                break;
-
-            case FS_FAT16:
-                if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK)
-                    break;
-                p = &fs->win[clst * 2 % SS(fs)];
-                val = LD_WORD(p);
-                break;
-
-            case FS_FAT32:
-                if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK)
-                    break;
-                p = &fs->win[clst * 4 % SS(fs)];
-                val = LD_DWORD(p) & 0x0FFFFFFF;
-                break;
-
-            default:
-                val = 1; /* Internal error */
-        }
-    }
-
-    return val;
-}
-
-/*-----------------------------------------------------------------------*/
-/* FAT access - Change value of a FAT entry                              */
-/*-----------------------------------------------------------------------*/
-/* Hidden API for hacks and disk tools */
-
-#if !_FS_READONLY
-FRESULT
-put_fat(FATFS *fs,  /* File system object */
-        DWORD clst, /* FAT index number (cluster number) to be changed */
-        DWORD val   /* New value to be set to the entry */
-        )
-{
-    UINT bc;
-    BYTE *p;
-    FRESULT res;
-
-    if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
-        res = FR_INT_ERR;
-
-    } else {
-        switch (fs->fs_type) {
-            case FS_FAT12:
-                bc = (UINT)clst;
-                bc += bc / 2;
-                res = move_window(fs, fs->fatbase + (bc / SS(fs)));
-                if (res != FR_OK)
-                    break;
-                p = &fs->win[bc++ % SS(fs)];
-                *p = (clst & 1) ? ((*p & 0x0F) | ((BYTE)val << 4)) : (BYTE)val;
-                fs->wflag = 1;
-                res = move_window(fs, fs->fatbase + (bc / SS(fs)));
-                if (res != FR_OK)
-                    break;
-                p = &fs->win[bc % SS(fs)];
-                *p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
-                fs->wflag = 1;
-                break;
-
-            case FS_FAT16:
-                res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
-                if (res != FR_OK)
-                    break;
-                p = &fs->win[clst * 2 % SS(fs)];
-                ST_WORD(p, (WORD)val);
-                fs->wflag = 1;
-                break;
-
-            case FS_FAT32:
-                res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
-                if (res != FR_OK)
-                    break;
-                p = &fs->win[clst * 4 % SS(fs)];
-                val |= LD_DWORD(p) & 0xF0000000;
-                ST_DWORD(p, val);
-                fs->wflag = 1;
-                break;
-
-            default:
-                res = FR_INT_ERR;
-        }
-    }
-
-    return res;
-}
-#endif /* !_FS_READONLY */
-
-/*-----------------------------------------------------------------------*/
-/* FAT handling - Remove a cluster chain                                 */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
-static FRESULT
-remove_chain(FATFS *fs, /* File system object */
-             DWORD clst /* Cluster# to remove a chain from */
-             )
-{
-    FRESULT res;
-    DWORD nxt;
-#if _USE_TRIM
-    DWORD scl = clst, ecl = clst, rt[2];
-#endif
-
-    if (clst < 2 || clst >= fs->n_fatent) { /* Check range */
-        res = FR_INT_ERR;
-
-    } else {
-        res = FR_OK;
-        while (clst < fs->n_fatent) { /* Not a last link? */
-            nxt = get_fat(fs, clst);  /* Get cluster status */
-            if (nxt == 0)
-                break; /* Empty cluster? */
-            if (nxt == 1) {
-                res = FR_INT_ERR;
-                break;
-            } /* Internal error? */
-            if (nxt == 0xFFFFFFFF) {
-                res = FR_DISK_ERR;
-                break;
-            }                           /* Disk error? */
-            res = put_fat(fs, clst, 0); /* Mark the cluster "empty" */
-            if (res != FR_OK)
-                break;
-            if (fs->free_clust != 0xFFFFFFFF) { /* Update FSINFO */
-                fs->free_clust++;
-                fs->fsi_flag |= 1;
-            }
-#if _USE_TRIM
-            if (ecl + 1 == nxt) { /* Is next cluster contiguous? */
-                ecl = nxt;
-            } else {                                         /* End of contiguous clusters */
-                rt[0] = clust2sect(fs, scl);                 /* Start sector */
-                rt[1] = clust2sect(fs, ecl) + fs->csize - 1; /* End sector */
-                disk_ioctl(fs->drv, CTRL_TRIM, rt);          /* Erase the block */
-                scl = ecl = nxt;
-            }
-#endif
-            clst = nxt; /* Next cluster */
-        }
-    }
-
-    return res;
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* FAT handling - Stretch or Create a cluster chain                      */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
-static DWORD
-create_chain(           /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
-             FATFS *fs, /* File system object */
-             DWORD clst /* Cluster# to stretch. 0 means create a new chain. */
-             )
-{
-    DWORD cs, ncl, scl;
-    FRESULT res;
-
-    if (clst == 0) {          /* Create a new chain */
-        scl = fs->last_clust; /* Get suggested start point */
-        if (!scl || scl >= fs->n_fatent)
-            scl = 1;
-    } else {                    /* Stretch the current chain */
-        cs = get_fat(fs, clst); /* Check the cluster status */
-        if (cs < 2)
-            return 1; /* Invalid value */
-        if (cs == 0xFFFFFFFF)
-            return cs; /* A disk error occurred */
-        if (cs < fs->n_fatent)
-            return cs; /* It is already followed by next cluster */
-        scl = clst;
-    }
-
-    ncl = scl; /* Start cluster */
-    for (;;) {
-        ncl++;                     /* Next cluster */
-        if (ncl >= fs->n_fatent) { /* Check wrap around */
-            ncl = 2;
-            if (ncl > scl)
-                return 0; /* No free cluster */
-        }
-        cs = get_fat(fs, ncl); /* Get the cluster status */
-        if (cs == 0)
-            break;                       /* Found a free cluster */
-        if (cs == 0xFFFFFFFF || cs == 1) /* An error occurred */
-            return cs;
-        if (ncl == scl)
-            return 0; /* No free cluster */
-    }
-
-    res = put_fat(fs, ncl, 0x0FFFFFFF); /* Mark the new cluster "last link" */
-    if (res == FR_OK && clst != 0) {
-        res = put_fat(fs, clst, ncl); /* Link it to the previous one if needed */
-    }
-    if (res == FR_OK) {
-        fs->last_clust = ncl; /* Update FSINFO */
-        if (fs->free_clust != 0xFFFFFFFF) {
-            fs->free_clust--;
-            fs->fsi_flag |= 1;
-        }
-    } else {
-        ncl = (res == FR_DISK_ERR) ? 0xFFFFFFFF : 1;
-    }
-
-    return ncl; /* Return new cluster number or error code */
-}
-#endif /* !_FS_READONLY */
-
-/*-----------------------------------------------------------------------*/
-/* FAT handling - Convert offset into cluster with link map table        */
-/*-----------------------------------------------------------------------*/
-
-#if _USE_FASTSEEK
-static DWORD
-clmt_clust(          /* <2:Error, >=2:Cluster number */
-           FIL *fp,  /* Pointer to the file object */
-           DWORD ofs /* File offset to be converted to cluster# */
-           )
-{
-    DWORD cl, ncl, *tbl;
-
-    tbl = fp->cltbl + 1;                   /* Top of CLMT */
-    cl = ofs / SS(fp->fs) / fp->fs->csize; /* Cluster order from top of the file */
-    for (;;) {
-        ncl = *tbl++; /* Number of cluters in the fragment */
-        if (!ncl)
-            return 0; /* End of table? (error) */
-        if (cl < ncl)
-            break; /* In this fragment? */
-        cl -= ncl;
-        tbl++; /* Next fragment */
-    }
-    return cl + *tbl; /* Return the cluster number */
-}
-#endif /* _USE_FASTSEEK */
-
-/*-----------------------------------------------------------------------*/
-/* Directory handling - Set directory index                              */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-dir_sdi(DIR *dp, /* Pointer to directory object */
-        UINT idx /* Index of directory table */
-        )
-{
-    DWORD clst, sect;
-    UINT ic;
-
-    dp->index = (WORD)idx;                     /* Current index */
-    clst = dp->sclust;                         /* Table start cluster (0:root) */
-    if (clst == 1 || clst >= dp->fs->n_fatent) /* Check start cluster range */
-        return FR_INT_ERR;
-    if (!clst && dp->fs->fs_type == FS_FAT32) /* Replace cluster# 0 with root cluster# if in FAT32 */
-        clst = dp->fs->dirbase;
-
-    if (clst == 0) {                  /* Static table (root-directory in FAT12/16) */
-        if (idx >= dp->fs->n_rootdir) /* Is index out of range? */
-            return FR_INT_ERR;
-        sect = dp->fs->dirbase;
-    } else {                                       /* Dynamic table (root-directory in FAT32 or sub-directory) */
-        ic = SS(dp->fs) / SZ_DIRE * dp->fs->csize; /* Entries per cluster */
-        while (idx >= ic) {                        /* Follow cluster chain */
-            clst = get_fat(dp->fs, clst);          /* Get next cluster */
-            if (clst == 0xFFFFFFFF)
-                return FR_DISK_ERR;                   /* Disk error */
-            if (clst < 2 || clst >= dp->fs->n_fatent) /* Reached to end of table or internal error */
-                return FR_INT_ERR;
-            idx -= ic;
-        }
-        sect = clust2sect(dp->fs, clst);
-    }
-    dp->clust = clst; /* Current cluster# */
-    if (!sect)
-        return FR_INT_ERR;
-    dp->sect = sect + idx / (SS(dp->fs) / SZ_DIRE);                   /* Sector# of the directory entry */
-    dp->dir = dp->fs->win + (idx % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Ptr to the entry in the sector */
-
-    return FR_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Directory handling - Move directory table index next                  */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-dir_next(            /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
-         DIR *dp,    /* Pointer to the directory object */
-         int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
-         )
-{
-    DWORD clst;
-    UINT i;
-#if !_FS_READONLY
-    UINT c;
-#endif
-
-    i = dp->index + 1;
-    if (!(i & 0xFFFF) || !dp->sect) /* Report EOT when index has reached 65535 */
-        return FR_NO_FILE;
-
-    if (!(i % (SS(dp->fs) / SZ_DIRE))) { /* Sector changed? */
-        dp->sect++;                      /* Next sector */
-
-        if (!dp->clust) {               /* Static table */
-            if (i >= dp->fs->n_rootdir) /* Report EOT if it reached end of static table */
-                return FR_NO_FILE;
-        } else {                                                             /* Dynamic table */
-            if (((i / (SS(dp->fs) / SZ_DIRE)) & (dp->fs->csize - 1)) == 0) { /* Cluster changed? */
-                clst = get_fat(dp->fs, dp->clust);                           /* Get next cluster */
-                if (clst <= 1)
-                    return FR_INT_ERR;
-                if (clst == 0xFFFFFFFF)
-                    return FR_DISK_ERR;
-                if (clst >= dp->fs->n_fatent) { /* If it reached end of dynamic table, */
-#if !_FS_READONLY
-                    if (!stretch)
-                        return FR_NO_FILE;                  /* If do not stretch, report EOT */
-                    clst = create_chain(dp->fs, dp->clust); /* Stretch cluster chain */
-                    if (clst == 0)
-                        return FR_DENIED; /* No free cluster */
-                    if (clst == 1)
-                        return FR_INT_ERR;
-                    if (clst == 0xFFFFFFFF)
-                        return FR_DISK_ERR;
-                    /* Clean-up stretched table */
-                    if (sync_window(dp->fs))
-                        return FR_DISK_ERR;                     /* Flush disk access window */
-                    mem_set(dp->fs->win, 0, SS(dp->fs));        /* Clear window buffer */
-                    dp->fs->winsect = clust2sect(dp->fs, clst); /* Cluster start sector */
-                    for (c = 0; c < dp->fs->csize; c++) {       /* Fill the new cluster with 0 */
-                        dp->fs->wflag = 1;
-                        if (sync_window(dp->fs))
-                            return FR_DISK_ERR;
-                        dp->fs->winsect++;
-                    }
-                    dp->fs->winsect -= c; /* Rewind window offset */
-#else
-                    if (!stretch)
-                        return FR_NO_FILE;                          /* If do not stretch, report EOT (this is to suppress warning) */
-                    return FR_NO_FILE;                              /* Report EOT */
-#endif
-                }
-                dp->clust = clst; /* Initialize data for new cluster */
-                dp->sect = clust2sect(dp->fs, clst);
-            }
-        }
-    }
-
-    dp->index = (WORD)i;                                            /* Current index */
-    dp->dir = dp->fs->win + (i % (SS(dp->fs) / SZ_DIRE)) * SZ_DIRE; /* Current entry in the window */
-
-    return FR_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Directory handling - Reserve directory entry                          */
-/*-----------------------------------------------------------------------*/
-
-#if !_FS_READONLY
-static FRESULT
-dir_alloc(DIR *dp,  /* Pointer to the directory object */
-          UINT nent /* Number of contiguous entries to allocate (1-21) */
-          )
-{
-    FRESULT res;
-    UINT n;
-
-    res = dir_sdi(dp, 0);
-    if (res == FR_OK) {
-        n = 0;
-        do {
-            res = move_window(dp->fs, dp->sect);
-            if (res != FR_OK)
-                break;
-            if (dp->dir[0] == DDEM || dp->dir[0] == 0) { /* Is it a free entry? */
-                if (++n == nent)
-                    break; /* A block of contiguous free entries is found */
-            } else {
-                n = 0; /* Not a blank entry. Restart to search */
-            }
-            res = dir_next(dp, 1); /* Next entry with table stretch enabled */
-        } while (res == FR_OK);
-    }
-    if (res == FR_NO_FILE)
-        res = FR_DENIED; /* No directory entry to allocate */
-    return res;
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Directory handling - Load/Store start cluster number                  */
-/*-----------------------------------------------------------------------*/
-
-static DWORD
-ld_clust(FATFS *fs, /* Pointer to the fs object */
-         BYTE *dir  /* Pointer to the directory entry */
-         )
-{
-    DWORD cl;
-
-    cl = LD_WORD(dir + DIR_FstClusLO);
-    if (fs->fs_type == FS_FAT32)
-        cl |= (DWORD)LD_WORD(dir + DIR_FstClusHI) << 16;
-
-    return cl;
-}
-
-#if !_FS_READONLY
-static void
-st_clust(BYTE *dir, /* Pointer to the directory entry */
-         DWORD cl   /* Value to be set */
-         )
-{
-    ST_WORD(dir + DIR_FstClusLO, cl);
-    ST_WORD(dir + DIR_FstClusHI, cl >> 16);
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* LFN handling - Test/Pick/Fit an LFN segment from/to directory entry   */
-/*-----------------------------------------------------------------------*/
-#if _USE_LFN
-static const BYTE LfnOfs[] = { 1, 3, 5, 7, 9, 14, 16, 18, 20, 22, 24, 28, 30 }; /* Offset of LFN characters in the directory entry */
-
-static int
-cmp_lfn(               /* 1:Matched, 0:Not matched */
-        WCHAR *lfnbuf, /* Pointer to the LFN to be compared */
-        BYTE *dir      /* Pointer to the directory entry containing a part of LFN */
-        )
-{
-    UINT i, s;
-    WCHAR wc, uc;
-
-    i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */
-    s = 0;
-    wc = 1;
-    do {
-        uc = LD_WORD(dir + LfnOfs[s]);                           /* Pick an LFN character from the entry */
-        if (wc) {                                                /* Last character has not been processed */
-            wc = ff_wtoupper(uc);                                /* Convert it to upper case */
-            if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */
-                return 0;                                        /* Not matched */
-        } else {
-            if (uc != 0xFFFF)
-                return 0; /* Check filler */
-        }
-    } while (++s < 13); /* Repeat until all characters in the entry are checked */
-
-    if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
-        return 0;
-
-    return 1; /* The part of LFN matched */
-}
-
-static int
-pick_lfn(               /* 1:Succeeded, 0:Buffer overflow */
-         WCHAR *lfnbuf, /* Pointer to the Unicode-LFN buffer */
-         BYTE *dir      /* Pointer to the directory entry */
-         )
-{
-    UINT i, s;
-    WCHAR wc, uc;
-
-    i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
-
-    s = 0;
-    wc = 1;
-    do {
-        uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */
-        if (wc) {                      /* Last character has not been processed */
-            if (i >= _MAX_LFN)
-                return 0;          /* Buffer overflow? */
-            lfnbuf[i++] = wc = uc; /* Store it */
-        } else {
-            if (uc != 0xFFFF)
-                return 0; /* Check filler */
-        }
-    } while (++s < 13); /* Read all character in the entry */
-
-    if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
-        if (i >= _MAX_LFN)
-            return 0; /* Buffer overflow? */
-        lfnbuf[i] = 0;
-    }
-
-    return 1;
-}
-
-#if !_FS_READONLY
-static void
-fit_lfn(const WCHAR *lfnbuf, /* Pointer to the LFN buffer */
-        BYTE *dir,           /* Pointer to the directory entry */
-        BYTE ord,            /* LFN order (1-20) */
-        BYTE sum             /* SFN sum */
-        )
-{
-    UINT i, s;
-    WCHAR wc;
-
-    dir[LDIR_Chksum] = sum;  /* Set check sum */
-    dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
-    dir[LDIR_Type] = 0;
-    ST_WORD(dir + LDIR_FstClusLO, 0);
-
-    i = (ord - 1) * 13; /* Get offset in the LFN buffer */
-    s = wc = 0;
-    do {
-        if (wc != 0xFFFF)
-            wc = lfnbuf[i++];         /* Get an effective character */
-        ST_WORD(dir + LfnOfs[s], wc); /* Put it */
-        if (!wc)
-            wc = 0xFFFF; /* Padding characters following last character */
-    } while (++s < 13);
-    if (wc == 0xFFFF || !lfnbuf[i])
-        ord |= LLEF;     /* Bottom LFN part is the start of LFN sequence */
-    dir[LDIR_Ord] = ord; /* Set the LFN order */
-}
-
-#endif
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Create numbered name                                                  */
-/*-----------------------------------------------------------------------*/
-#if _USE_LFN
-static void
-gen_numname(BYTE *dst,        /* Pointer to the buffer to store numbered SFN */
-            const BYTE *src,  /* Pointer to SFN */
-            const WCHAR *lfn, /* Pointer to LFN */
-            UINT seq          /* Sequence number */
-            )
-{
-    BYTE ns[8], c;
-    UINT i, j;
-    WCHAR wc;
-    DWORD sr;
-
-    mem_cpy(dst, src, 11);
-
-    if (seq > 5) { /* On many collisions, generate a hash number instead of sequential number */
-        sr = seq;
-        while (*lfn) { /* Create a CRC */
-            wc = *lfn++;
-            for (i = 0; i < 16; i++) {
-                sr = (sr << 1) + (wc & 1);
-                wc >>= 1;
-                if (sr & 0x10000)
-                    sr ^= 0x11021;
-            }
-        }
-        seq = (UINT)sr;
-    }
-
-    /* itoa (hexdecimal) */
-    i = 7;
-    do {
-        c = (seq % 16) + '0';
-        if (c > '9')
-            c += 7;
-        ns[i--] = c;
-        seq /= 16;
-    } while (seq);
-    ns[i] = '~';
-
-    /* Append the number */
-    for (j = 0; j < i && dst[j] != ' '; j++) {
-        if (IsDBCS1(dst[j])) {
-            if (j == i - 1)
-                break;
-            j++;
-        }
-    }
-    do {
-        dst[j++] = (i < 8) ? ns[i++] : ' ';
-    } while (j < 8);
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Calculate sum of an SFN                                               */
-/*-----------------------------------------------------------------------*/
-#if _USE_LFN
-static BYTE
-sum_sfn(const BYTE *dir /* Pointer to the SFN entry */
-        )
-{
-    BYTE sum = 0;
-    UINT n = 11;
-
-    do
-        sum = (sum >> 1) + (sum << 7) + *dir++;
-    while (--n);
-    return sum;
-}
-#endif
-
-/*-----------------------------------------------------------------------*/
-/* Directory handling - Find an object in the directory                  */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-dir_find(DIR *dp /* Pointer to the directory object linked to the file name */
-         )
-{
-    FRESULT res;
-    BYTE c, *dir;
-#if _USE_LFN
-    BYTE a, ord, sum;
-#endif
-
-    res = dir_sdi(dp, 0); /* Rewind directory object */
-    if (res != FR_OK)
-        return res;
-
-#if _USE_LFN
-    ord = sum = 0xFF;
-    dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
-#endif
-    do {
-        res = move_window(dp->fs, dp->sect);
-        if (res != FR_OK)
-            break;
-        dir = dp->dir; /* Ptr to the directory entry of current index */
-        c = dir[DIR_Name];
-        if (c == 0) {
-            res = FR_NO_FILE;
-            break;
-        }    /* Reached to end of table */
-#if _USE_LFN /* LFN configuration */
-        a = dir[DIR_Attr] & AM_MASK;
-        if (c == DDEM || ((a & AM_VOL) && a != AM_LFN)) { /* An entry without valid data */
-            ord = 0xFF;
-            dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
-        } else {
-            if (a == AM_LFN) { /* An LFN entry is found */
-                if (dp->lfn) {
-                    if (c & LLEF) { /* Is it start of LFN sequence? */
-                        sum = dir[LDIR_Chksum];
-                        c &= ~LLEF;
-                        ord = c;                 /* LFN start order */
-                        dp->lfn_idx = dp->index; /* Start index of LFN */
-                    }
-                    /* Check validity of the LFN entry and compare it with given name */
-                    ord = (c == ord && sum == dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
-                }
-            } else { /* An SFN entry is found */
-                if (!ord && sum == sum_sfn(dir))
-                    break; /* LFN matched? */
-                if (!(dp->fn[NSFLAG] & NS_LOSS) && !mem_cmp(dir, dp->fn, 11))
-                    break; /* SFN matched? */
-                ord = 0xFF;
-                dp->lfn_idx = 0xFFFF; /* Reset LFN sequence */
-            }
-        }
-#else /* Non LFN configuration */
-        if (!(dir[DIR_Attr] & AM_VOL) && !mem_cmp(dir, dp->fn, 11)) /* Is it a valid entry? */
-            break;
-#endif
-        res = dir_next(dp, 0); /* Next entry */
-    } while (res == FR_OK);
-
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Read an object from the directory                                     */
-/*-----------------------------------------------------------------------*/
-#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
-static FRESULT
-dir_read(DIR *dp, /* Pointer to the directory object */
-         int vol  /* Filtered by 0:file/directory or 1:volume label */
-         )
-{
-    FRESULT res;
-    BYTE a, c, *dir;
-#if _USE_LFN
-    BYTE ord = 0xFF, sum = 0xFF;
-#endif
-
-    res = FR_NO_FILE;
-    while (dp->sect) {
-        res = move_window(dp->fs, dp->sect);
-        if (res != FR_OK)
-            break;
-        dir = dp->dir; /* Ptr to the directory entry of current index */
-        c = dir[DIR_Name];
-        if (c == 0) {
-            res = FR_NO_FILE;
-            break;
-        } /* Reached to end of table */
-        a = dir[DIR_Attr] & AM_MASK;
-#if _USE_LFN                                                                                  /* LFN configuration */
-        if (c == DDEM || (!_FS_RPATH && c == '.') || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
-            ord = 0xFF;
-        } else {
-            if (a == AM_LFN) {  /* An LFN entry is found */
-                if (c & LLEF) { /* Is it start of LFN sequence? */
-                    sum = dir[LDIR_Chksum];
-                    c &= ~LLEF;
-                    ord = c;
-                    dp->lfn_idx = dp->index;
-                }
-                /* Check LFN validity and capture it */
-                ord = (c == ord && sum == dir[LDIR_Chksum] && pick_lfn(dp->lfn, dir)) ? ord - 1 : 0xFF;
-            } else {                            /* An SFN entry is found */
-                if (ord || sum != sum_sfn(dir)) /* Is there a valid LFN? */
-                    dp->lfn_idx = 0xFFFF;       /* It has no LFN. */
-                break;
-            }
-        }
-#else /* Non LFN configuration */
-        if (c != DDEM && (_FS_RPATH || c != '.') && a != AM_LFN && (int)((a & ~AM_ARC) == AM_VOL) == vol) /* Is it a valid entry? */
-            break;
-#endif
-        res = dir_next(dp, 0); /* Next entry */
-        if (res != FR_OK)
-            break;
-    }
-
-    if (res != FR_OK)
-        dp->sect = 0;
-
-    return res;
-}
-#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */
-
-/*-----------------------------------------------------------------------*/
-/* Register an object to the directory                                   */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
-static FRESULT
-dir_register(        /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */
-             DIR *dp /* Target directory with object name to be created */
-             )
-{
-    FRESULT res;
-#if _USE_LFN /* LFN configuration */
-    UINT n, nent;
-    BYTE sn[12], *fn, sum;
-    WCHAR *lfn;
-
-    fn = dp->fn;
-    lfn = dp->lfn;
-    mem_cpy(sn, fn, 12);
-
-    if (_FS_RPATH && (sn[NSFLAG] & NS_DOT)) /* Cannot create dot entry */
-        return FR_INVALID_NAME;
-
-    if (sn[NSFLAG] & NS_LOSS) { /* When LFN is out of 8.3 format, generate a numbered name */
-        fn[NSFLAG] = 0;
-        dp->lfn = 0; /* Find only SFN */
-        for (n = 1; n < 100; n++) {
-            gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
-            res = dir_find(dp);          /* Check if the name collides with existing SFN */
-            if (res != FR_OK)
-                break;
-        }
-        if (n == 100)
-            return FR_DENIED; /* Abort if too many collisions */
-        if (res != FR_NO_FILE)
-            return res; /* Abort if the result is other than 'not collided' */
-        fn[NSFLAG] = sn[NSFLAG];
-        dp->lfn = lfn;
-    }
-
-    if (sn[NSFLAG] & NS_LFN) { /* When LFN is to be created, allocate entries for an SFN + LFNs. */
-        for (n = 0; lfn[n]; n++)
-            ;
-        nent = (n + 25) / 13;
-    } else { /* Otherwise allocate an entry for an SFN  */
-        nent = 1;
-    }
-    res = dir_alloc(dp, nent); /* Allocate entries */
-
-    if (res == FR_OK && --nent) { /* Set LFN entry if needed */
-        res = dir_sdi(dp, dp->index - nent);
-        if (res == FR_OK) {
-            sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */
-            do {                   /* Store LFN entries in bottom first */
-                res = move_window(dp->fs, dp->sect);
-                if (res != FR_OK)
-                    break;
-                fit_lfn(dp->lfn, dp->dir, (BYTE)nent, sum);
-                dp->fs->wflag = 1;
-                res = dir_next(dp, 0); /* Next entry */
-            } while (res == FR_OK && --nent);
-        }
-    }
-#else /* Non LFN configuration */
-    res = dir_alloc(dp, 1); /* Allocate an entry for SFN */
-#endif
-
-    if (res == FR_OK) { /* Set SFN entry */
-        res = move_window(dp->fs, dp->sect);
-        if (res == FR_OK) {
-            mem_set(dp->dir, 0, SZ_DIRE); /* Clean the entry */
-            mem_cpy(dp->dir, dp->fn, 11); /* Put SFN */
-#if _USE_LFN
-            dp->dir[DIR_NTres] = dp->fn[NSFLAG] & (NS_BODY | NS_EXT); /* Put NT flag */
-#endif
-            dp->fs->wflag = 1;
-        }
-    }
-
-    return res;
-}
-#endif /* !_FS_READONLY */
-
-/*-----------------------------------------------------------------------*/
-/* Remove an object from the directory                                   */
-/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY && !_FS_MINIMIZE
-static FRESULT
-dir_remove(        /* FR_OK: Successful, FR_DISK_ERR: A disk error */
-           DIR *dp /* Directory object pointing the entry to be removed */
-           )
-{
-    FRESULT res;
-#if _USE_LFN /* LFN configuration */
-    UINT i;
-
-    i = dp->index;                                                /* SFN index */
-    res = dir_sdi(dp, (dp->lfn_idx == 0xFFFF) ? i : dp->lfn_idx); /* Goto the SFN or top of the LFN entries */
-    if (res == FR_OK) {
-        do {
-            res = move_window(dp->fs, dp->sect);
-            if (res != FR_OK)
-                break;
-            mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
-            *dp->dir = DDEM;
-            dp->fs->wflag = 1;
-            if (dp->index >= i)
-                break;             /* When reached SFN, all entries of the object has been deleted. */
-            res = dir_next(dp, 0); /* Next entry */
-        } while (res == FR_OK);
-        if (res == FR_NO_FILE)
-            res = FR_INT_ERR;
-    }
-
-#else /* Non LFN configuration */
-    res = dir_sdi(dp, dp->index);
-    if (res == FR_OK) {
-        res = move_window(dp->fs, dp->sect);
-        if (res == FR_OK) {
-            mem_set(dp->dir, 0, SZ_DIRE); /* Clear and mark the entry "deleted" */
-            *dp->dir = DDEM;
-            dp->fs->wflag = 1;
-        }
-    }
-#endif
-
-    return res;
-}
-#endif /* !_FS_READONLY */
-
-/*-----------------------------------------------------------------------*/
-/* Get file information from directory entry                             */
-/*-----------------------------------------------------------------------*/
-#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
-static void
-get_fileinfo(             /* No return code */
-             DIR *dp,     /* Pointer to the directory object */
-             FILINFO *fno /* Pointer to the file information to be filled */
-             )
-{
-    UINT i;
-    TCHAR *p, c;
-    BYTE *dir;
-#if _USE_LFN
-    WCHAR w, *lfn;
-#endif
-
-    p = fno->fname;
-    if (dp->sect) { /* Get SFN */
-        dir = dp->dir;
-        i = 0;
-        while (i < 11) { /* Copy name body and extension */
-            c = (TCHAR)dir[i++];
-            if (c == ' ')
-                continue; /* Skip padding spaces */
-            if (c == RDDEM)
-                c = (TCHAR)DDEM; /* Restore replaced DDEM character */
-            if (i == 9)
-                *p++ = '.'; /* Insert a . if extension is exist */
-#if _USE_LFN
-            if (IsUpper(c) && (dir[DIR_NTres] & (i >= 9 ? NS_EXT : NS_BODY)))
-                c += 0x20; /* To lower */
-#if _LFN_UNICODE
-            if (IsDBCS1(c) && i != 8 && i != 11 && IsDBCS2(dir[i]))
-                c = c << 8 | dir[i++];
-            c = ff_convert(c, 1); /* OEM -> Unicode */
-            if (!c)
-                c = '?';
-#endif
-#endif
-            *p++ = c;
-        }
-        fno->fattrib = dir[DIR_Attr];              /* Attribute */
-        fno->fsize = LD_DWORD(dir + DIR_FileSize); /* Size */
-        fno->fdate = LD_WORD(dir + DIR_WrtDate);   /* Date */
-        fno->ftime = LD_WORD(dir + DIR_WrtTime);   /* Time */
-    }
-    *p = 0; /* Terminate SFN string by a \0 */
-
-#if _USE_LFN
-    if (fno->lfname) {
-        i = 0;
-        p = fno->lfname;
-        if (dp->sect && fno->lfsize && dp->lfn_idx != 0xFFFF) { /* Get LFN if available */
-            lfn = dp->lfn;
-            while ((w = *lfn++) != 0) { /* Get an LFN character */
-#if !_LFN_UNICODE
-                w = ff_convert(w, 0); /* Unicode -> OEM */
-                if (!w) {
-                    i = 0;
-                    break;
-                }                        /* No LFN if it could not be converted */
-                if (_DF1S && w >= 0x100) /* Put 1st byte if it is a DBC (always false on SBCS cfg) */
-                    p[i++] = (TCHAR)(w >> 8);
-#endif
-                if (i >= fno->lfsize - 1) {
-                    i = 0;
-                    break;
-                } /* No LFN if buffer overflow */
-                p[i++] = (TCHAR)w;
-            }
-        }
-        p[i] = 0; /* Terminate LFN string by a \0 */
-    }
-#endif
-}
-#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
-
-/*-----------------------------------------------------------------------*/
-/* Pattern matching                                                      */
-/*-----------------------------------------------------------------------*/
-#if _USE_FIND && _FS_MINIMIZE <= 1
-static WCHAR
-get_achar(                  /* Get a character and advances ptr 1 or 2 */
-          const TCHAR **ptr /* Pointer to pointer to the SBCS/DBCS/Unicode string */
-          )
-{
-    WCHAR chr;
-
-#if !_LFN_UNICODE
-    chr = (BYTE) * (*ptr)++; /* Get a byte */
-    if (IsLower(chr))
-        chr -= 0x20;                    /* To upper ASCII char */
-    if (IsDBCS1(chr) && IsDBCS2(**ptr)) /* Get DBC 2nd byte if needed */
-        chr = chr << 8 | (BYTE) * (*ptr)++;
-#ifdef _EXCVT
-    if (chr >= 0x80)
-        chr = ExCvt[chr - 0x80]; /* To upper SBCS extended char */
-#endif
-#else
-    chr = ff_wtoupper(*(*ptr)++);              /* Get a word and to upper */
-#endif
-    return chr;
-}
-
-static int
-pattern_matching(                  /* Return value: 0:mismatched, 1:matched */
-                 const TCHAR *pat, /* Matching pattern */
-                 const TCHAR *nam, /* String to be tested */
-                 int skip,         /* Number of pre-skip chars (number of ?s) */
-                 int inf           /* Infinite search (* specified) */
-                 )
-{
-    const TCHAR *pp, *np;
-    WCHAR pc, nc;
-    int nm, nx;
-
-    while (skip--) { /* Pre-skip name chars */
-        if (!get_achar(&nam))
-            return 0; /* Branch mismatched if less name chars */
-    }
-    if (!*pat && inf)
-        return 1; /* (short circuit) */
-
-    do {
-        pp = pat;
-        np = nam; /* Top of pattern and name to match */
-        for (;;) {
-            if (*pp == '?' || *pp == '*') { /* Wildcard? */
-                nm = nx = 0;
-                do { /* Analyze the wildcard chars */
-                    if (*pp++ == '?')
-                        nm++;
-                    else
-                        nx = 1;
-                } while (*pp == '?' || *pp == '*');
-                if (pattern_matching(pp, np, nm, nx))
-                    return 1; /* Test new branch (recurs upto number of wildcard blocks in the pattern) */
-                nc = *np;
-                break; /* Branch mismatched */
-            }
-            pc = get_achar(&pp); /* Get a pattern char */
-            nc = get_achar(&np); /* Get a name char */
-            if (pc != nc)
-                break; /* Branch mismatched? */
-            if (!pc)
-                return 1; /* Branch matched? (matched at end of both strings) */
-        }
-        get_achar(&nam); /* nam++ */
-    } while (inf && nc); /* Retry until end of name if infinite search is specified */
-
-    return 0;
-}
-#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */
-
-/*-----------------------------------------------------------------------*/
-/* Pick a segment and create the object name in directory form           */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-create_name(DIR *dp,           /* Pointer to the directory object */
-            const TCHAR **path /* Pointer to pointer to the segment in the path string */
-            )
-{
-#if _USE_LFN /* LFN configuration */
-    BYTE b, cf;
-    WCHAR w, *lfn;
-    UINT i, ni, si, di;
-    const TCHAR *p;
-
-    /* Create LFN in Unicode */
-    for (p = *path; *p == '/' || *p == '\\'; p++)
-        ; /* Strip duplicated separator */
-    lfn = dp->lfn;
-    si = di = 0;
-    for (;;) {
-        w = p[si++]; /* Get a character */
-        if (w < ' ' || w == '/' || w == '\\')
-            break;          /* Break on end of segment */
-        if (di >= _MAX_LFN) /* Reject too long name */
-            return FR_INVALID_NAME;
-#if !_LFN_UNICODE
-        w &= 0xFF;
-        if (IsDBCS1(w)) {      /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
-            b = (BYTE)p[si++]; /* Get 2nd byte */
-            w = (w << 8) + b;  /* Create a DBC */
-            if (!IsDBCS2(b))
-                return FR_INVALID_NAME; /* Reject invalid sequence */
-        }
-        w = ff_convert(w, 1); /* Convert ANSI/OEM to Unicode */
-        if (!w)
-            return FR_INVALID_NAME; /* Reject invalid code */
-#endif
-        if (w < 0x80 && chk_chr("\"*:<>\?|\x7F", w)) /* Reject illegal characters for LFN */
-            return FR_INVALID_NAME;
-        lfn[di++] = w; /* Store the Unicode character */
-    }
-    *path = &p[si];               /* Return pointer to the next segment */
-    cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
-#if _FS_RPATH
-    if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */
-        (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) {
-        lfn[di] = 0;
-        for (i = 0; i < 11; i++)
-            dp->fn[i] = (i < di) ? '.' : ' ';
-        dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
-        return FR_OK;
-    }
-#endif
-    while (di) { /* Strip trailing spaces and dots */
-        w = lfn[di - 1];
-        if (w != ' ' && w != '.')
-            break;
-        di--;
-    }
-    if (!di)
-        return FR_INVALID_NAME; /* Reject nul string */
-
-    lfn[di] = 0; /* LFN is created */
-
-    /* Create SFN in directory form */
-    mem_set(dp->fn, ' ', 11);
-    for (si = 0; lfn[si] == ' ' || lfn[si] == '.'; si++)
-        ; /* Strip leading spaces and dots */
-    if (si)
-        cf |= NS_LOSS | NS_LFN;
-    while (di && lfn[di - 1] != '.')
-        di--; /* Find extension (di<=si: no extension) */
-
-    b = i = 0;
-    ni = 8;
-    for (;;) {
-        w = lfn[si++]; /* Get an LFN character */
-        if (!w)
-            break;                                /* Break on end of the LFN */
-        if (w == ' ' || (w == '.' && si != di)) { /* Remove spaces and dots */
-            cf |= NS_LOSS | NS_LFN;
-            continue;
-        }
-
-        if (i >= ni || si == di) { /* Extension or end of SFN */
-            if (ni == 11) {        /* Long extension */
-                cf |= NS_LOSS | NS_LFN;
-                break;
-            }
-            if (si != di)
-                cf |= NS_LOSS | NS_LFN; /* Out of 8.3 format */
-            if (si > di)
-                break; /* No extension */
-            si = di;
-            i = 8;
-            ni = 11; /* Enter extension section */
-            b <<= 2;
-            continue;
-        }
-
-        if (w >= 0x80) { /* Non ASCII character */
-#ifdef _EXCVT
-            w = ff_convert(w, 0); /* Unicode -> OEM code */
-            if (w)
-                w = ExCvt[w - 0x80]; /* Convert extended character to upper (SBCS) */
-#else
-            w = ff_convert(ff_wtoupper(w), 0); /* Upper converted Unicode -> OEM code */
-#endif
-            cf |= NS_LFN; /* Force create LFN entry */
-        }
-
-        if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */
-            if (i >= ni - 1) {
-                cf |= NS_LOSS | NS_LFN;
-                i = ni;
-                continue;
-            }
-            dp->fn[i++] = (BYTE)(w >> 8);
-        } else {                              /* SBC */
-            if (!w || chk_chr("+,;=[]", w)) { /* Replace illegal characters for SFN */
-                w = '_';
-                cf |= NS_LOSS | NS_LFN; /* Lossy conversion */
-            } else {
-                if (IsUpper(w)) { /* ASCII large capital */
-                    b |= 2;
-                } else {
-                    if (IsLower(w)) { /* ASCII small capital */
-                        b |= 1;
-                        w -= 0x20;
-                    }
-                }
-            }
-        }
-        dp->fn[i++] = (BYTE)w;
-    }
-
-    if (dp->fn[0] == DDEM)
-        dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */
-
-    if (ni == 8)
-        b <<= 2;
-    if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
-        cf |= NS_LFN;
-    if (!(cf & NS_LFN)) { /* When LFN is in 8.3 format without extended character, NT flags are created */
-        if ((b & 0x03) == 0x01)
-            cf |= NS_EXT; /* NT flag (Extension has only small capital) */
-        if ((b & 0x0C) == 0x04)
-            cf |= NS_BODY; /* NT flag (Filename has only small capital) */
-    }
-
-    dp->fn[NSFLAG] = cf; /* SFN is created */
-
-    return FR_OK;
-
-#else /* Non-LFN configuration */
-    BYTE b, c, d, *sfn;
-    UINT ni, si, i;
-    const char *p;
-
-    /* Create file name in directory form */
-    for (p = *path; *p == '/' || *p == '\\'; p++)
-        ; /* Strip duplicated separator */
-    sfn = dp->fn;
-    mem_set(sfn, ' ', 11);
-    si = i = b = 0;
-    ni = 8;
-#if _FS_RPATH
-    if (p[si] == '.') { /* Is this a dot entry? */
-        for (;;) {
-            c = (BYTE)p[si++];
-            if (c != '.' || si >= 3)
-                break;
-            sfn[i++] = c;
-        }
-        if (c != '/' && c != '\\' && c > ' ')
-            return FR_INVALID_NAME;
-        *path = &p[si];                                       /* Return pointer to the next segment */
-        sfn[NSFLAG] = (c <= ' ') ? NS_LAST | NS_DOT : NS_DOT; /* Set last segment flag if end of path */
-        return FR_OK;
-    }
-#endif
-    for (;;) {
-        c = (BYTE)p[si++];
-        if (c <= ' ' || c == '/' || c == '\\')
-            break; /* Break on end of segment */
-        if (c == '.' || i >= ni) {
-            if (ni != 8 || c != '.')
-                return FR_INVALID_NAME;
-            i = 8;
-            ni = 11;
-            b <<= 2;
-            continue;
-        }
-        if (c >= 0x80) { /* Extended character? */
-            b |= 3;      /* Eliminate NT flag */
-#ifdef _EXCVT
-            c = ExCvt[c - 0x80]; /* To upper extended characters (SBCS cfg) */
-#else
-#if !_DF1S
-            return FR_INVALID_NAME; /* Reject extended characters (ASCII cfg) */
-#endif
-#endif
-        }
-        if (IsDBCS1(c)) {                   /* Check if it is a DBC 1st byte (always false on SBCS cfg) */
-            d = (BYTE)p[si++];              /* Get 2nd byte */
-            if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
-                return FR_INVALID_NAME;
-            sfn[i++] = c;
-            sfn[i++] = d;
-        } else {                                   /* SBC */
-            if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) /* Reject illegal chrs for SFN */
-                return FR_INVALID_NAME;
-            if (IsUpper(c)) { /* ASCII large capital? */
-                b |= 2;
-            } else {
-                if (IsLower(c)) { /* ASCII small capital? */
-                    b |= 1;
-                    c -= 0x20;
-                }
-            }
-            sfn[i++] = c;
-        }
-    }
-    *path = &p[si];               /* Return pointer to the next segment */
-    c = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of path */
-
-    if (!i)
-        return FR_INVALID_NAME; /* Reject nul string */
-    if (sfn[0] == DDEM)
-        sfn[0] = RDDEM; /* When first character collides with DDEM, replace it with RDDEM */
-
-    if (ni == 8)
-        b <<= 2;
-    if ((b & 0x03) == 0x01)
-        c |= NS_EXT; /* NT flag (Name extension has only small capital) */
-    if ((b & 0x0C) == 0x04)
-        c |= NS_BODY; /* NT flag (Name body has only small capital) */
-
-    sfn[NSFLAG] = c; /* Store NT flag, File name is created */
-
-    return FR_OK;
-#endif
-}
-
-/*-----------------------------------------------------------------------*/
-/* Follow a file path                                                    */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-follow_path(                  /* FR_OK(0): successful, !=0: error code */
-            DIR *dp,          /* Directory object to return last directory and found object */
-            const TCHAR *path /* Full-path string to find a file or directory */
-            )
-{
-    FRESULT res;
-    BYTE *dir, ns;
-
-#if _FS_RPATH
-    if (*path == '/' || *path == '\\') { /* There is a heading separator */
-        path++;
-        dp->sclust = 0;            /* Strip it and start from the root directory */
-    } else {                       /* No heading separator */
-        dp->sclust = dp->fs->cdir; /* Start from the current directory */
-    }
-#else
-    if (*path == '/' || *path == '\\') /* Strip heading separator if exist */
-        path++;
-    dp->sclust = 0; /* Always start from the root directory */
-#endif
-
-    if ((UINT)*path < ' ') { /* Null path name is the origin directory itself */
-        res = dir_sdi(dp, 0);
-        dp->dir = 0;
-    } else { /* Follow path */
-        for (;;) {
-            res = create_name(dp, &path); /* Get a segment name of the path */
-            if (res != FR_OK)
-                break;
-            res = dir_find(dp); /* Find an object with the sagment name */
-            ns = dp->fn[NSFLAG];
-            if (res != FR_OK) {                       /* Failed to find the object */
-                if (res == FR_NO_FILE) {              /* Object is not found */
-                    if (_FS_RPATH && (ns & NS_DOT)) { /* If dot entry is not exist, */
-                        dp->sclust = 0;
-                        dp->dir = 0; /* it is the root directory and stay there */
-                        if (!(ns & NS_LAST))
-                            continue; /* Continue to follow if not last segment */
-                        res = FR_OK;  /* Ended at the root directroy. Function completed. */
-                    } else {          /* Could not find the object */
-                        if (!(ns & NS_LAST))
-                            res = FR_NO_PATH; /* Adjust error code if not last segment */
-                    }
-                }
-                break;
-            }
-            if (ns & NS_LAST)
-                break;                       /* Last segment matched. Function completed. */
-            dir = dp->dir;                   /* Follow the sub-directory */
-            if (!(dir[DIR_Attr] & AM_DIR)) { /* It is not a sub-directory and cannot follow */
-                res = FR_NO_PATH;
-                break;
-            }
-            dp->sclust = ld_clust(dp->fs, dir);
-        }
-    }
-
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Get logical drive number from path name                               */
-/*-----------------------------------------------------------------------*/
-
-static int
-get_ldnumber(                   /* Returns logical drive number (-1:invalid drive) */
-             const TCHAR **path /* Pointer to pointer to the path name */
-             )
-{
-    const TCHAR *tp, *tt;
-    UINT i;
-    int vol = -1;
-#if _STR_VOLUME_ID /* Find string drive id */
-    static const char *const str[] = { _VOLUME_STRS };
-    const char *sp;
-    char c;
-    TCHAR tc;
-#endif
-
-    if (*path) { /* If the pointer is not a null */
-        for (tt = *path; (UINT)*tt >= (_USE_LFN ? ' ' : '!') && *tt != ':'; tt++)
-            ;             /* Find ':' in the path */
-        if (*tt == ':') { /* If a ':' is exist in the path name */
-            tp = *path;
-            i = *tp++ - '0';
-            if (i < 10 && tp == tt) { /* Is there a numeric drive id? */
-                if (i < _VOLUMES) {   /* If a drive id is found, get the value and strip it */
-                    vol = (int)i;
-                    *path = ++tt;
-                }
-            }
-#if _STR_VOLUME_ID
-            else { /* No numeric drive number, find string drive id */
-                i = 0;
-                tt++;
-                do {
-                    sp = str[i];
-                    tp = *path;
-                    do { /* Compare a string drive id with path name */
-                        c = *sp++;
-                        tc = *tp++;
-                        if (IsLower(tc))
-                            tc -= 0x20;
-                    } while (c && (TCHAR)c == tc);
-                } while ((c || tp != tt) && ++i < _VOLUMES); /* Repeat for each id until pattern match */
-                if (i < _VOLUMES) {                          /* If a drive id is found, get the value and strip it */
-                    vol = (int)i;
-                    *path = tt;
-                }
-            }
-#endif
-            return vol;
-        }
-#if _FS_RPATH && _VOLUMES >= 2
-        vol = CurrVol; /* Current drive */
-#else
-        vol = 0;    /* Drive 0 */
-#endif
-    }
-    return vol;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Load a sector and check if it is an FAT boot sector                   */
-/*-----------------------------------------------------------------------*/
-
-static BYTE
-check_fs(           /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */
-         FATFS *fs, /* File system object */
-         DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
-         )
-{
-    fs->wflag = 0;
-    fs->winsect = 0xFFFFFFFF;           /* Invaidate window */
-    if (move_window(fs, sect) != FR_OK) /* Load boot record */
-        return 3;
-
-    if (LD_WORD(&fs->win[BS_55AA]) != 0xAA55) /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
-        return 2;
-
-    if ((LD_DWORD(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
-        return 0;
-    if ((LD_DWORD(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) /* Check "FAT" string */
-        return 0;
-
-    return 1;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Find logical drive and check if the volume is mounted                 */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-find_volume(                    /* FR_OK(0): successful, !=0: any error occurred */
-            FATFS **rfs,        /* Pointer to pointer to the found file system object */
-            const TCHAR **path, /* Pointer to pointer to the path name (drive number) */
-            BYTE wmode          /* !=0: Check write protection for write access */
-            )
-{
-    BYTE fmt, *pt;
-    int vol;
-    DSTATUS stat;
-    DWORD bsect, fasize, tsect, sysect, nclst, szbfat, br[4];
-    WORD nrsv;
-    FATFS *fs;
-    UINT i;
-
-    /* Get logical drive number from the path name */
-    *rfs = 0;
-    vol = get_ldnumber(path);
-    if (vol < 0)
-        return FR_INVALID_DRIVE;
-
-    /* Check if the file system object is valid or not */
-    fs = FatFs[vol]; /* Get pointer to the file system object */
-    if (!fs)
-        return FR_NOT_ENABLED; /* Is the file system object available? */
-
-    ENTER_FF(fs); /* Lock the volume */
-    *rfs = fs;    /* Return pointer to the file system object */
-
-    if (fs->fs_type) { /* If the volume has been mounted */
-        stat = disk_status(fs->drv);
-        if (!(stat & STA_NOINIT)) {                             /* and the physical drive is kept initialized */
-            if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check write protection if needed */
-                return FR_WRITE_PROTECTED;
-            return FR_OK; /* The file system object is valid */
-        }
-    }
-
-    /* The file system object is not valid. */
-    /* Following code attempts to mount the volume. (analyze BPB and initialize the fs object) */
-
-    fs->fs_type = 0;                                    /* Clear the file system object */
-    fs->drv = LD2PD(vol);                               /* Bind the logical drive and a physical drive */
-    stat = disk_initialize(fs->drv);                    /* Initialize the physical drive */
-    if (stat & STA_NOINIT)                              /* Check if the initialization succeeded */
-        return FR_NOT_READY;                            /* Failed to initialize due to no medium or hard error */
-    if (!_FS_READONLY && wmode && (stat & STA_PROTECT)) /* Check disk write protection if needed */
-        return FR_WRITE_PROTECTED;
-#if _MAX_SS != _MIN_SS /* Get sector size (multiple sector size cfg only) */
-    if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) < _MIN_SS || SS(fs) > _MAX_SS)
-        return FR_DISK_ERR;
-#endif
-    /* Find an FAT partition on the drive. Supports only generic partitioning, FDISK and SFD. */
-    bsect = 0;
-    fmt = check_fs(fs, bsect);                /* Load sector 0 and check if it is an FAT boot sector as SFD */
-    if (fmt == 1 || (!fmt && (LD2PT(vol)))) { /* Not an FAT boot sector or forced partition number */
-        for (i = 0; i < 4; i++) {             /* Get partition offset */
-            pt = fs->win + MBR_Table + i * SZ_PTE;
-            br[i] = pt[4] ? LD_DWORD(&pt[8]) : 0;
-        }
-        i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
-        if (i)
-            i--;
-        do { /* Find an FAT volume */
-            bsect = br[i];
-            fmt = bsect ? check_fs(fs, bsect) : 2; /* Check the partition */
-        } while (!LD2PT(vol) && fmt && ++i < 4);
-    }
-    if (fmt == 3)
-        return FR_DISK_ERR; /* An error occured in the disk I/O layer */
-    if (fmt)
-        return FR_NO_FILESYSTEM; /* No FAT volume is found */
-
-    /* An FAT volume is found. Following code initializes the file system object */
-
-    if (LD_WORD(fs->win + BPB_BytsPerSec) != SS(fs)) /* (BPB_BytsPerSec must be equal to the physical sector size) */
-        return FR_NO_FILESYSTEM;
-
-    fasize = LD_WORD(fs->win + BPB_FATSz16); /* Number of sectors per FAT */
-    if (!fasize)
-        fasize = LD_DWORD(fs->win + BPB_FATSz32);
-    fs->fsize = fasize;
-
-    fs->n_fats = fs->win[BPB_NumFATs];      /* Number of FAT copies */
-    if (fs->n_fats != 1 && fs->n_fats != 2) /* (Must be 1 or 2) */
-        return FR_NO_FILESYSTEM;
-    fasize *= fs->n_fats; /* Number of sectors for FAT area */
-
-    fs->csize = fs->win[BPB_SecPerClus];             /* Number of sectors per cluster */
-    if (!fs->csize || (fs->csize & (fs->csize - 1))) /* (Must be power of 2) */
-        return FR_NO_FILESYSTEM;
-
-    fs->n_rootdir = LD_WORD(fs->win + BPB_RootEntCnt); /* Number of root directory entries */
-    if (fs->n_rootdir % (SS(fs) / SZ_DIRE))            /* (Must be sector aligned) */
-        return FR_NO_FILESYSTEM;
-
-    tsect = LD_WORD(fs->win + BPB_TotSec16); /* Number of sectors on the volume */
-    if (!tsect)
-        tsect = LD_DWORD(fs->win + BPB_TotSec32);
-
-    nrsv = LD_WORD(fs->win + BPB_RsvdSecCnt); /* Number of reserved sectors */
-    if (!nrsv)
-        return FR_NO_FILESYSTEM; /* (Must not be 0) */
-
-    /* Determine the FAT sub type */
-    sysect = nrsv + fasize + fs->n_rootdir / (SS(fs) / SZ_DIRE); /* RSV + FAT + DIR */
-    if (tsect < sysect)
-        return FR_NO_FILESYSTEM;          /* (Invalid volume size) */
-    nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
-    if (!nclst)
-        return FR_NO_FILESYSTEM; /* (Invalid volume size) */
-    fmt = FS_FAT12;
-    if (nclst >= MIN_FAT16)
-        fmt = FS_FAT16;
-    if (nclst >= MIN_FAT32)
-        fmt = FS_FAT32;
-
-    /* Boundaries and Limits */
-    fs->n_fatent = nclst + 2;      /* Number of FAT entries */
-    fs->volbase = bsect;           /* Volume start sector */
-    fs->fatbase = bsect + nrsv;    /* FAT start sector */
-    fs->database = bsect + sysect; /* Data start sector */
-    if (fmt == FS_FAT32) {
-        if (fs->n_rootdir)
-            return FR_NO_FILESYSTEM;                    /* (BPB_RootEntCnt must be 0) */
-        fs->dirbase = LD_DWORD(fs->win + BPB_RootClus); /* Root directory start cluster */
-        szbfat = fs->n_fatent * 4;                      /* (Needed FAT size) */
-    } else {
-        if (!fs->n_rootdir)
-            return FR_NO_FILESYSTEM;        /* (BPB_RootEntCnt must not be 0) */
-        fs->dirbase = fs->fatbase + fasize; /* Root directory start sector */
-        szbfat = (fmt == FS_FAT16) ?        /* (Needed FAT size) */
-                     fs->n_fatent * 2
-                                   : fs->n_fatent * 3 / 2 + (fs->n_fatent & 1);
-    }
-    if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) /* (BPB_FATSz must not be less than the size needed) */
-        return FR_NO_FILESYSTEM;
-
-#if !_FS_READONLY
-    /* Initialize cluster allocation information */
-    fs->last_clust = fs->free_clust = 0xFFFFFFFF;
-
-    /* Get fsinfo if available */
-    fs->fsi_flag = 0x80;
-#if (_FS_NOFSINFO & 3) != 3
-    if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */
-        && LD_WORD(fs->win + BPB_FSInfo) == 1 && move_window(fs, bsect + 1) == FR_OK) {
-        fs->fsi_flag = 0;
-        if (LD_WORD(fs->win + BS_55AA) == 0xAA55 /* Load FSINFO data if available */
-            && LD_DWORD(fs->win + FSI_LeadSig) == 0x41615252 && LD_DWORD(fs->win + FSI_StrucSig) == 0x61417272) {
-#if (_FS_NOFSINFO & 1) == 0
-            fs->free_clust = LD_DWORD(fs->win + FSI_Free_Count);
-#endif
-#if (_FS_NOFSINFO & 2) == 0
-            fs->last_clust = LD_DWORD(fs->win + FSI_Nxt_Free);
-#endif
-        }
-    }
-#endif
-#endif
-    fs->fs_type = fmt; /* FAT sub-type */
-    fs->id = ++Fsid;   /* File system mount ID */
-#if _FS_RPATH
-    fs->cdir = 0; /* Set current directory to root */
-#endif
-#if _FS_LOCK /* Clear file lock semaphores */
-    clear_lock(fs);
-#endif
-
-    return FR_OK;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Check if the file/directory object is valid or not                    */
-/*-----------------------------------------------------------------------*/
-
-static FRESULT
-validate(          /* FR_OK(0): The object is valid, !=0: Invalid */
-         void *obj /* Pointer to the object FIL/DIR to check validity */
-         )
-{
-    FIL *fil = (FIL *)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */
-
-    if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id)
-        return FR_INVALID_OBJECT;
-
-    ENTER_FF(fil->fs); /* Lock file system */
-
-    if (disk_status(fil->fs->drv) & STA_NOINIT)
-        return FR_NOT_READY;
-
-    return FR_OK;
-}
-
-/*--------------------------------------------------------------------------
-
-   Public Functions
-
---------------------------------------------------------------------------*/
-
-/*-----------------------------------------------------------------------*/
-/* Mount/Unmount a Logical Drive                                         */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_mount(FATFS *fs,         /* Pointer to the file system object (NULL:unmount)*/
-        const TCHAR *path, /* Logical drive number to be mounted/unmounted */
-        BYTE opt           /* 0:Do not mount (delayed mount), 1:Mount immediately */
-        )
-{
-    FATFS *cfs;
-    int vol;
-    FRESULT res;
-    const TCHAR *rp = path;
-
-    vol = get_ldnumber(&rp);
-    if (vol < 0)
-        return FR_INVALID_DRIVE;
-    cfs = FatFs[vol]; /* Pointer to fs object */
-
-    if (cfs) {
-#if _FS_LOCK
-        clear_lock(cfs);
-#endif
-#if _FS_REENTRANT /* Discard sync object of the current volume */
-        if (!ff_del_syncobj(cfs->sobj))
-            return FR_INT_ERR;
-#endif
-        cfs->fs_type = 0; /* Clear old fs object */
-    }
-
-    if (fs) {
-        fs->fs_type = 0; /* Clear new fs object */
-#if _FS_REENTRANT        /* Create sync object for the new volume */
-        if (!ff_cre_syncobj((BYTE)vol, &fs->sobj))
-            return FR_INT_ERR;
-#endif
-    }
-    FatFs[vol] = fs; /* Register new fs object */
-
-    if (!fs || opt != 1)
-        return FR_OK; /* Do not mount now, it will be mounted later */
-
-    res = find_volume(&fs, &path, 0); /* Force mounted the volume */
-    LEAVE_FF(fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Open or Create a File                                                 */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_open(FIL *fp,           /* Pointer to the blank file object */
-       const TCHAR *path, /* Pointer to the file name */
-       BYTE mode          /* Access mode and file open mode flags */
-       )
-{
-    FRESULT res;
-    DIR dj;
-    BYTE *dir;
-    DEFINE_NAMEBUF;
-#if !_FS_READONLY
-    DWORD dw, cl;
-#endif
-
-    if (!fp)
-        return FR_INVALID_OBJECT;
-    fp->fs = 0; /* Clear file object */
-
-/* Get logical drive number */
-#if !_FS_READONLY
-    mode &= FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
-    res = find_volume(&dj.fs, &path, (BYTE)(mode & ~FA_READ));
-#else
-    mode &= FA_READ;
-    res = find_volume(&dj.fs, &path, 0);
-#endif
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        dir = dj.dir;
-#if !_FS_READONLY /* R/W configuration */
-        if (res == FR_OK) {
-            if (!dir) /* Default directory itself */
-                res = FR_INVALID_NAME;
-#if _FS_LOCK
-            else
-                res = chk_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
-#endif
-        }
-        /* Create or Open a file */
-        if (mode & (FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW)) {
-            if (res != FR_OK) {        /* No file, create new */
-                if (res == FR_NO_FILE) /* There is no file to open, create a new entry */
-#if _FS_LOCK
-                    res = enq_lock() ? dir_register(&dj) : FR_TOO_MANY_OPEN_FILES;
-#else
-                    res = dir_register(&dj);
-#endif
-                mode |= FA_CREATE_ALWAYS;                /* File is created */
-                dir = dj.dir;                            /* New entry */
-            } else {                                     /* Any object is already existing */
-                if (dir[DIR_Attr] & (AM_RDO | AM_DIR)) { /* Cannot overwrite it (R/O or DIR) */
-                    res = FR_DENIED;
-                } else {
-                    if (mode & FA_CREATE_NEW) /* Cannot create as new file */
-                        res = FR_EXIST;
-                }
-            }
-            if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
-                dw = GET_FATTIME();                          /* Created time */
-                ST_DWORD(dir + DIR_CrtTime, dw);
-                dir[DIR_Attr] = 0;               /* Reset attribute */
-                ST_DWORD(dir + DIR_FileSize, 0); /* size = 0 */
-                cl = ld_clust(dj.fs, dir);       /* Get start cluster */
-                st_clust(dir, 0);                /* cluster = 0 */
-                dj.fs->wflag = 1;
-                if (cl) { /* Remove the cluster chain if exist */
-                    dw = dj.fs->winsect;
-                    res = remove_chain(dj.fs, cl);
-                    if (res == FR_OK) {
-                        dj.fs->last_clust = cl - 1; /* Reuse the cluster hole */
-                        res = move_window(dj.fs, dw);
-                    }
-                }
-            }
-        } else {                              /* Open an existing file */
-            if (res == FR_OK) {               /* Follow succeeded */
-                if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
-                    res = FR_NO_FILE;
-                } else {
-                    if ((mode & FA_WRITE) && (dir[DIR_Attr] & AM_RDO)) /* R/O violation */
-                        res = FR_DENIED;
-                }
-            }
-        }
-        if (res == FR_OK) {
-            if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
-                mode |= FA__WRITTEN;
-            fp->dir_sect = dj.fs->winsect; /* Pointer to the directory entry */
-            fp->dir_ptr = dir;
-#if _FS_LOCK
-            fp->lockid = inc_lock(&dj, (mode & ~FA_READ) ? 1 : 0);
-            if (!fp->lockid)
-                res = FR_INT_ERR;
-#endif
-        }
-
-#else /* R/O configuration */
-        if (res == FR_OK) { /* Follow succeeded */
-            dir = dj.dir;
-            if (!dir) { /* Current directory itself */
-                res = FR_INVALID_NAME;
-            } else {
-                if (dir[DIR_Attr] & AM_DIR) /* It is a directory */
-                    res = FR_NO_FILE;
-            }
-        }
-#endif
-        FREE_BUF();
-
-        if (res == FR_OK) {
-            fp->flag = mode;                          /* File access mode */
-            fp->err = 0;                              /* Clear error flag */
-            fp->sclust = ld_clust(dj.fs, dir);        /* File start cluster */
-            fp->fsize = LD_DWORD(dir + DIR_FileSize); /* File size */
-            fp->fptr = 0;                             /* File pointer */
-            fp->dsect = 0;
-#if _USE_FASTSEEK
-            fp->cltbl = 0; /* Normal seek mode */
-#endif
-            fp->fs = dj.fs; /* Validate file object */
-            fp->id = fp->fs->id;
-        }
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Read File                                                             */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_getsector(FIL *fp,  /* Pointer to the file object */
-            UINT *sec /* Pointer to uint which will contain the sector */
-            )
-{
-    FRESULT res;
-    DWORD clst = 0, sect = 0;
-    BYTE csect;
-
-    res = validate(fp); /* Check validity */
-
-    if (res != FR_OK)
-        LEAVE_FF(fp->fs, res);
-    if (fp->err) /* Check error */
-        LEAVE_FF(fp->fs, (FRESULT)fp->err);
-    if (!(fp->flag & FA_READ)) /* Check access mode */
-        LEAVE_FF(fp->fs, FR_DENIED);
-
-    if ((fp->fptr % SS(fp->fs)) == 0) {                              /* On the sector boundary? */
-        csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
-        if (!csect) {                                                /* On the cluster boundary? */
-            if (fp->fptr == 0) {                                     /* On the top of the file? */
-                clst = fp->sclust;                                   /* Follow from the origin */
-            } else {                                                 /* Middle or end of the file */
-                clst = get_fat(fp->fs, fp->clust);                   /* Follow cluster chain on the FAT */
-            }
-
-            if (clst < 2)
-                ABORT(fp->fs, FR_INT_ERR);
-            if (clst == 0xFFFFFFFF)
-                ABORT(fp->fs, FR_DISK_ERR);
-        }
-
-        sect = clust2sect(fp->fs, clst); /* Get current sector */
-        if (!sect)
-            ABORT(fp->fs, FR_INT_ERR);
-        sect += csect;
-    }
-
-    *sec = sect;
-
-    return 0;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Read File                                                             */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_read(FIL *fp,    /* Pointer to the file object */
-       void *buff, /* Pointer to data buffer */
-       UINT btr,   /* Number of bytes to read */
-       UINT *br    /* Pointer to number of bytes read */
-       )
-{
-    FRESULT res;
-    DWORD clst, sect, remain;
-    UINT rcnt, cc;
-    BYTE csect, *rbuff = (BYTE *)buff;
-
-    *br = 0; /* Clear read byte counter */
-
-    res = validate(fp); /* Check validity */
-    if (res != FR_OK)
-        LEAVE_FF(fp->fs, res);
-    if (fp->err) /* Check error */
-        LEAVE_FF(fp->fs, (FRESULT)fp->err);
-    if (!(fp->flag & FA_READ)) /* Check access mode */
-        LEAVE_FF(fp->fs, FR_DENIED);
-    remain = fp->fsize - fp->fptr;
-    if (btr > remain)
-        btr = (UINT)remain; /* Truncate btr by remaining bytes */
-
-    for (; btr; /* Repeat until all data read */
-         rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
-        if ((fp->fptr % SS(fp->fs)) == 0) {                              /* On the sector boundary? */
-            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
-            if (!csect) {                                                /* On the cluster boundary? */
-                if (fp->fptr == 0) {                                     /* On the top of the file? */
-                    clst = fp->sclust;                                   /* Follow from the origin */
-                } else {                                                 /* Middle or end of the file */
-#if _USE_FASTSEEK
-                    if (fp->cltbl)
-                        clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
-                    else
-#endif
-                        clst = get_fat(fp->fs, fp->clust); /* Follow cluster chain on the FAT */
-                }
-                if (clst < 2)
-                    ABORT(fp->fs, FR_INT_ERR);
-                if (clst == 0xFFFFFFFF)
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->clust = clst; /* Update current cluster */
-            }
-            sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
-            if (!sect)
-                ABORT(fp->fs, FR_INT_ERR);
-            sect += csect;
-            cc = btr / SS(fp->fs);              /* When remaining bytes >= sector size, */
-            if (cc) {                           /* Read maximum contiguous sectors directly */
-                if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
-                    cc = fp->fs->csize - csect;
-                if (disk_read(fp->fs->drv, rbuff, sect, cc) != RES_OK)
-                    ABORT(fp->fs, FR_DISK_ERR);
-#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
-#if _FS_TINY
-                if (fp->fs->wflag && fp->fs->winsect - sect < cc)
-                    mem_cpy(rbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), fp->fs->win, SS(fp->fs));
-#else
-                if ((fp->flag & FA__DIRTY) && fp->dsect - sect < cc)
-                    mem_cpy(rbuff + ((fp->dsect - sect) * SS(fp->fs)), fp->buf, SS(fp->fs));
-#endif
-#endif
-                rcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
-                continue;
-            }
-#if !_FS_TINY
-            if (fp->dsect != sect) { /* Load data sector if not in cache */
-#if !_FS_READONLY
-                if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
-                    if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                        ABORT(fp->fs, FR_DISK_ERR);
-                    fp->flag &= ~FA__DIRTY;
-                }
-#endif
-                if (disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK) /* Fill sector cache */
-                    ABORT(fp->fs, FR_DISK_ERR);
-            }
-#endif
-            fp->dsect = sect;
-        }
-        rcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Get partial sector data from sector buffer */
-        if (rcnt > btr)
-            rcnt = btr;
-#if _FS_TINY
-        if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
-            ABORT(fp->fs, FR_DISK_ERR);
-        mem_cpy(rbuff, &fp->fs->win[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
-#else
-        mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fp->fs)], rcnt); /* Pick partial sector */
-#endif
-    }
-
-    LEAVE_FF(fp->fs, FR_OK);
-}
-
-#if !_FS_READONLY
-/*-----------------------------------------------------------------------*/
-/* Write File                                                            */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_write(FIL *fp,          /* Pointer to the file object */
-        const void *buff, /* Pointer to the data to be written */
-        UINT btw,         /* Number of bytes to write */
-        UINT *bw          /* Pointer to number of bytes written */
-        )
-{
-    FRESULT res;
-    DWORD clst, sect;
-    UINT wcnt, cc;
-    const BYTE *wbuff = (const BYTE *)buff;
-    BYTE csect;
-
-    *bw = 0; /* Clear write byte counter */
-
-    res = validate(fp); /* Check validity */
-    if (res != FR_OK)
-        LEAVE_FF(fp->fs, res);
-    if (fp->err) /* Check error */
-        LEAVE_FF(fp->fs, (FRESULT)fp->err);
-    if (!(fp->flag & FA_WRITE)) /* Check access mode */
-        LEAVE_FF(fp->fs, FR_DENIED);
-    if (fp->fptr + btw < fp->fptr)
-        btw = 0; /* File size cannot reach 4GB */
-
-    for (; btw; /* Repeat until all data written */
-         wbuff += wcnt, fp->fptr += wcnt, *bw += wcnt, btw -= wcnt) {
-        if ((fp->fptr % SS(fp->fs)) == 0) {                              /* On the sector boundary? */
-            csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
-            if (!csect) {                                                /* On the cluster boundary? */
-                if (fp->fptr == 0) {                                     /* On the top of the file? */
-                    clst = fp->sclust;                                   /* Follow from the origin */
-                    if (clst == 0)                                       /* When no cluster is allocated, */
-                        clst = create_chain(fp->fs, 0);                  /* Create a new cluster chain */
-                } else {                                                 /* Middle or end of the file */
-#if _USE_FASTSEEK
-                    if (fp->cltbl)
-                        clst = clmt_clust(fp, fp->fptr); /* Get cluster# from the CLMT */
-                    else
-#endif
-                        clst = create_chain(fp->fs, fp->clust); /* Follow or stretch cluster chain on the FAT */
-                }
-                if (clst == 0)
-                    break; /* Could not allocate a new cluster (disk full) */
-                if (clst == 1)
-                    ABORT(fp->fs, FR_INT_ERR);
-                if (clst == 0xFFFFFFFF)
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->clust = clst; /* Update current cluster */
-                if (fp->sclust == 0)
-                    fp->sclust = clst; /* Set start cluster if the first write */
-            }
-#if _FS_TINY
-            if (fp->fs->winsect == fp->dsect && sync_window(fp->fs)) /* Write-back sector cache */
-                ABORT(fp->fs, FR_DISK_ERR);
-#else
-            if (fp->flag & FA__DIRTY) { /* Write-back sector cache */
-                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->flag &= ~FA__DIRTY;
-            }
-#endif
-            sect = clust2sect(fp->fs, fp->clust); /* Get current sector */
-            if (!sect)
-                ABORT(fp->fs, FR_INT_ERR);
-            sect += csect;
-            cc = btw / SS(fp->fs);              /* When remaining bytes >= sector size, */
-            if (cc) {                           /* Write maximum contiguous sectors directly */
-                if (csect + cc > fp->fs->csize) /* Clip at cluster boundary */
-                    cc = fp->fs->csize - csect;
-                if (disk_write(fp->fs->drv, wbuff, sect, cc) != RES_OK)
-                    ABORT(fp->fs, FR_DISK_ERR);
-#if _FS_MINIMIZE <= 2
-#if _FS_TINY
-                if (fp->fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
-                    mem_cpy(fp->fs->win, wbuff + ((fp->fs->winsect - sect) * SS(fp->fs)), SS(fp->fs));
-                    fp->fs->wflag = 0;
-                }
-#else
-                if (fp->dsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
-                    mem_cpy(fp->buf, wbuff + ((fp->dsect - sect) * SS(fp->fs)), SS(fp->fs));
-                    fp->flag &= ~FA__DIRTY;
-                }
-#endif
-#endif
-                wcnt = SS(fp->fs) * cc; /* Number of bytes transferred */
-                continue;
-            }
-#if _FS_TINY
-            if (fp->fptr >= fp->fsize) { /* Avoid silly cache filling at growing edge */
-                if (sync_window(fp->fs))
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->fs->winsect = sect;
-            }
-#else
-            if (fp->dsect != sect) { /* Fill sector cache with file data */
-                if (fp->fptr < fp->fsize && disk_read(fp->fs->drv, fp->buf, sect, 1) != RES_OK)
-                    ABORT(fp->fs, FR_DISK_ERR);
-            }
-#endif
-            fp->dsect = sect;
-        }
-        wcnt = SS(fp->fs) - ((UINT)fp->fptr % SS(fp->fs)); /* Put partial sector into file I/O buffer */
-        if (wcnt > btw)
-            wcnt = btw;
-#if _FS_TINY
-        if (move_window(fp->fs, fp->dsect) != FR_OK) /* Move sector window */
-            ABORT(fp->fs, FR_DISK_ERR);
-        mem_cpy(&fp->fs->win[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
-        fp->fs->wflag = 1;
-#else
-        mem_cpy(&fp->buf[fp->fptr % SS(fp->fs)], wbuff, wcnt); /* Fit partial sector */
-        fp->flag |= FA__DIRTY;
-#endif
-    }
-
-    if (fp->fptr > fp->fsize)
-        fp->fsize = fp->fptr; /* Update file size if needed */
-    fp->flag |= FA__WRITTEN;  /* Set file change flag */
-
-    LEAVE_FF(fp->fs, FR_OK);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Synchronize the File                                                  */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_sync(FIL *fp /* Pointer to the file object */
-       )
-{
-    FRESULT res;
-    DWORD tm;
-    BYTE *dir;
-
-    res = validate(fp); /* Check validity of the object */
-    if (res == FR_OK) {
-        if (fp->flag & FA__WRITTEN) { /* Has the file been written? */
-                                      /* Write-back dirty buffer */
-#if !_FS_TINY
-            if (fp->flag & FA__DIRTY) {
-                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                    LEAVE_FF(fp->fs, FR_DISK_ERR);
-                fp->flag &= ~FA__DIRTY;
-            }
-#endif
-            /* Update the directory entry */
-            res = move_window(fp->fs, fp->dir_sect);
-            if (res == FR_OK) {
-                dir = fp->dir_ptr;
-                dir[DIR_Attr] |= AM_ARC;                 /* Set archive bit */
-                ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
-                st_clust(dir, fp->sclust);               /* Update start cluster */
-                tm = GET_FATTIME();                      /* Update updated time */
-                ST_DWORD(dir + DIR_WrtTime, tm);
-                ST_WORD(dir + DIR_LstAccDate, 0);
-                fp->flag &= ~FA__WRITTEN;
-                fp->fs->wflag = 1;
-                res = sync_fs(fp->fs);
-            }
-        }
-    }
-
-    LEAVE_FF(fp->fs, res);
-}
-
-#endif /* !_FS_READONLY */
-
-/*-----------------------------------------------------------------------*/
-/* Close File                                                            */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_close(FIL *fp /* Pointer to the file object to be closed */
-        )
-{
-    FRESULT res;
-
-#if !_FS_READONLY
-    res = f_sync(fp); /* Flush cached data */
-    if (res == FR_OK)
-#endif
-    {
-        res = validate(fp); /* Lock volume */
-        if (res == FR_OK) {
-#if _FS_REENTRANT
-            FATFS *fs = fp->fs;
-#endif
-#if _FS_LOCK
-            res = dec_lock(fp->lockid); /* Decrement file open counter */
-            if (res == FR_OK)
-#endif
-                fp->fs = 0; /* Invalidate file object */
-#if _FS_REENTRANT
-            unlock_fs(fs, FR_OK); /* Unlock volume */
-#endif
-        }
-    }
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Change Current Directory or Current Drive, Get Current Directory      */
-/*-----------------------------------------------------------------------*/
-
-#if _FS_RPATH >= 1
-#if _VOLUMES >= 2
-FRESULT
-f_chdrive(const TCHAR *path /* Drive number */
-          )
-{
-    int vol;
-
-    vol = get_ldnumber(&path);
-    if (vol < 0)
-        return FR_INVALID_DRIVE;
-
-    CurrVol = (BYTE)vol;
-
-    return FR_OK;
-}
-#endif
-
-FRESULT
-f_chdir(const TCHAR *path /* Pointer to the directory path */
-        )
-{
-    FRESULT res;
-    DIR dj;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 0);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the path */
-        FREE_BUF();
-        if (res == FR_OK) { /* Follow completed */
-            if (!dj.dir) {
-                dj.fs->cdir = dj.sclust; /* Start directory itself */
-            } else {
-                if (dj.dir[DIR_Attr] & AM_DIR) /* Reached to the directory */
-                    dj.fs->cdir = ld_clust(dj.fs, dj.dir);
-                else
-                    res = FR_NO_PATH; /* Reached but a file */
-            }
-        }
-        if (res == FR_NO_FILE)
-            res = FR_NO_PATH;
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-#if _FS_RPATH >= 2
-FRESULT
-f_getcwd(TCHAR *buff, /* Pointer to the directory path */
-         UINT len     /* Size of path */
-         )
-{
-    FRESULT res;
-    DIR dj;
-    UINT i, n;
-    DWORD ccl;
-    TCHAR *tp;
-    FILINFO fno;
-    DEFINE_NAMEBUF;
-
-    *buff = 0;
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, (const TCHAR **)&buff, 0); /* Get current volume */
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        i = len;                         /* Bottom of buffer (directory stack base) */
-        dj.sclust = dj.fs->cdir;         /* Start to follow upper directory from current directory */
-        while ((ccl = dj.sclust) != 0) { /* Repeat while current directory is a sub-directory */
-            res = dir_sdi(&dj, 1);       /* Get parent directory */
-            if (res != FR_OK)
-                break;
-            res = dir_read(&dj, 0);
-            if (res != FR_OK)
-                break;
-            dj.sclust = ld_clust(dj.fs, dj.dir); /* Goto parent directory */
-            res = dir_sdi(&dj, 0);
-            if (res != FR_OK)
-                break;
-            do { /* Find the entry links to the child directory */
-                res = dir_read(&dj, 0);
-                if (res != FR_OK)
-                    break;
-                if (ccl == ld_clust(dj.fs, dj.dir))
-                    break; /* Found the entry */
-                res = dir_next(&dj, 0);
-            } while (res == FR_OK);
-            if (res == FR_NO_FILE)
-                res = FR_INT_ERR; /* It cannot be 'not found'. */
-            if (res != FR_OK)
-                break;
-#if _USE_LFN
-            fno.lfname = buff;
-            fno.lfsize = i;
-#endif
-            get_fileinfo(&dj, &fno); /* Get the directory name and push it to the buffer */
-            tp = fno.fname;
-#if _USE_LFN
-            if (*buff)
-                tp = buff;
-#endif
-            for (n = 0; tp[n]; n++)
-                ;
-            if (i < n + 3) {
-                res = FR_NOT_ENOUGH_CORE;
-                break;
-            }
-            while (n)
-                buff[--i] = tp[--n];
-            buff[--i] = '/';
-        }
-        tp = buff;
-        if (res == FR_OK) {
-#if _VOLUMES >= 2
-            *tp++ = '0' + CurrVol; /* Put drive number */
-            *tp++ = ':';
-#endif
-            if (i == len) { /* Root-directory */
-                *tp++ = '/';
-            } else { /* Sub-directroy */
-                do   /* Add stacked path str */
-                    *tp++ = buff[i++];
-                while (i < len);
-            }
-        }
-        *tp = 0;
-        FREE_BUF();
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-#endif /* _FS_RPATH >= 2 */
-#endif /* _FS_RPATH >= 1 */
-
-#if _FS_MINIMIZE <= 2
-/*-----------------------------------------------------------------------*/
-/* Seek File R/W Pointer                                                 */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_lseek(FIL *fp,  /* Pointer to the file object */
-        DWORD ofs /* File pointer from top of file */
-        )
-{
-    FRESULT res;
-    DWORD clst, bcs, nsect, ifptr;
-#if _USE_FASTSEEK
-    DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
-#endif
-
-    res = validate(fp); /* Check validity of the object */
-    if (res != FR_OK)
-        LEAVE_FF(fp->fs, res);
-    if (fp->err) /* Check error */
-        LEAVE_FF(fp->fs, (FRESULT)fp->err);
-
-#if _USE_FASTSEEK
-    if (fp->cltbl) {                 /* Fast seek */
-        if (ofs == CREATE_LINKMAP) { /* Create CLMT */
-            tbl = fp->cltbl;
-            tlen = *tbl++;
-            ulen = 2;        /* Given table size and required table size */
-            cl = fp->sclust; /* Top of the chain */
-            if (cl) {
-                do {
-                    /* Get a fragment */
-                    tcl = cl;
-                    ncl = 0;
-                    ulen += 2; /* Top, length and used items */
-                    do {
-                        pcl = cl;
-                        ncl++;
-                        cl = get_fat(fp->fs, cl);
-                        if (cl <= 1)
-                            ABORT(fp->fs, FR_INT_ERR);
-                        if (cl == 0xFFFFFFFF)
-                            ABORT(fp->fs, FR_DISK_ERR);
-                    } while (cl == pcl + 1);
-                    if (ulen <= tlen) { /* Store the length and top of the fragment */
-                        *tbl++ = ncl;
-                        *tbl++ = tcl;
-                    }
-                } while (cl < fp->fs->n_fatent); /* Repeat until end of chain */
-            }
-            *fp->cltbl = ulen; /* Number of items used */
-            if (ulen <= tlen)
-                *tbl = 0; /* Terminate table */
-            else
-                res = FR_NOT_ENOUGH_CORE; /* Given table size is smaller than required */
-
-        } else {                 /* Fast seek */
-            if (ofs > fp->fsize) /* Clip offset at the file size */
-                ofs = fp->fsize;
-            fp->fptr = ofs; /* Set file pointer */
-            if (ofs) {
-                fp->clust = clmt_clust(fp, ofs - 1);
-                dsc = clust2sect(fp->fs, fp->clust);
-                if (!dsc)
-                    ABORT(fp->fs, FR_INT_ERR);
-                dsc += (ofs - 1) / SS(fp->fs) & (fp->fs->csize - 1);
-                if (fp->fptr % SS(fp->fs) && dsc != fp->dsect) { /* Refill sector cache if needed */
-#if !_FS_TINY
-#if !_FS_READONLY
-                    if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
-                        if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                            ABORT(fp->fs, FR_DISK_ERR);
-                        fp->flag &= ~FA__DIRTY;
-                    }
-#endif
-                    if (disk_read(fp->fs->drv, fp->buf, dsc, 1) != RES_OK) /* Load current sector */
-                        ABORT(fp->fs, FR_DISK_ERR);
-#endif
-                    fp->dsect = dsc;
-                }
-            }
-        }
-    } else
-#endif
-
-    /* Normal Seek */
-    {
-        if (ofs > fp->fsize /* In read-only mode, clip offset with the file size */
-#if !_FS_READONLY
-            && !(fp->flag & FA_WRITE)
-#endif
-                )
-            ofs = fp->fsize;
-
-        ifptr = fp->fptr;
-        fp->fptr = nsect = 0;
-        if (ofs) {
-            bcs = (DWORD)fp->fs->csize * SS(fp->fs);                 /* Cluster size (byte) */
-            if (ifptr > 0 && (ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
-                fp->fptr = (ifptr - 1) & ~(bcs - 1);                 /* start from the current cluster */
-                ofs -= fp->fptr;
-                clst = fp->clust;
-            } else {               /* When seek to back cluster, */
-                clst = fp->sclust; /* start from the first cluster */
-#if !_FS_READONLY
-                if (clst == 0) { /* If no cluster chain, create a new chain */
-                    clst = create_chain(fp->fs, 0);
-                    if (clst == 1)
-                        ABORT(fp->fs, FR_INT_ERR);
-                    if (clst == 0xFFFFFFFF)
-                        ABORT(fp->fs, FR_DISK_ERR);
-                    fp->sclust = clst;
-                }
-#endif
-                fp->clust = clst;
-            }
-            if (clst != 0) {
-                while (ofs > bcs) { /* Cluster following loop */
-#if !_FS_READONLY
-                    if (fp->flag & FA_WRITE) {             /* Check if in write mode or not */
-                        clst = create_chain(fp->fs, clst); /* Force stretch if in write mode */
-                        if (clst == 0) {                   /* When disk gets full, clip file size */
-                            ofs = bcs;
-                            break;
-                        }
-                    } else
-#endif
-                        clst = get_fat(fp->fs, clst); /* Follow cluster chain if not in write mode */
-                    if (clst == 0xFFFFFFFF)
-                        ABORT(fp->fs, FR_DISK_ERR);
-                    if (clst <= 1 || clst >= fp->fs->n_fatent)
-                        ABORT(fp->fs, FR_INT_ERR);
-                    fp->clust = clst;
-                    fp->fptr += bcs;
-                    ofs -= bcs;
-                }
-                fp->fptr += ofs;
-                if (ofs % SS(fp->fs)) {
-                    nsect = clust2sect(fp->fs, clst); /* Current sector */
-                    if (!nsect)
-                        ABORT(fp->fs, FR_INT_ERR);
-                    nsect += ofs / SS(fp->fs);
-                }
-            }
-        }
-        if (fp->fptr % SS(fp->fs) && nsect != fp->dsect) { /* Fill sector cache if needed */
-#if !_FS_TINY
-#if !_FS_READONLY
-            if (fp->flag & FA__DIRTY) { /* Write-back dirty sector cache */
-                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->flag &= ~FA__DIRTY;
-            }
-#endif
-            if (disk_read(fp->fs->drv, fp->buf, nsect, 1) != RES_OK) /* Fill sector cache */
-                ABORT(fp->fs, FR_DISK_ERR);
-#endif
-            fp->dsect = nsect;
-        }
-#if !_FS_READONLY
-        if (fp->fptr > fp->fsize) { /* Set file change flag if the file size is extended */
-            fp->fsize = fp->fptr;
-            fp->flag |= FA__WRITTEN;
-        }
-#endif
-    }
-
-    LEAVE_FF(fp->fs, res);
-}
-
-#if _FS_MINIMIZE <= 1
-/*-----------------------------------------------------------------------*/
-/* Create a Directory Object                                             */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_opendir(DIR *dp,          /* Pointer to directory object to create */
-          const TCHAR *path /* Pointer to the directory path */
-          )
-{
-    FRESULT res;
-    FATFS *fs;
-    DEFINE_NAMEBUF;
-
-    if (!dp)
-        return FR_INVALID_OBJECT;
-
-    /* Get logical drive number */
-    res = find_volume(&fs, &path, 0);
-    if (res == FR_OK) {
-        dp->fs = fs;
-        INIT_BUF(*dp);
-        res = follow_path(dp, path); /* Follow the path to the directory */
-        FREE_BUF();
-        if (res == FR_OK) {                     /* Follow completed */
-            if (dp->dir) {                      /* It is not the origin directory itself */
-                if (dp->dir[DIR_Attr] & AM_DIR) /* The object is a sub directory */
-                    dp->sclust = ld_clust(fs, dp->dir);
-                else /* The object is a file */
-                    res = FR_NO_PATH;
-            }
-            if (res == FR_OK) {
-                dp->id = fs->id;
-                res = dir_sdi(dp, 0); /* Rewind directory */
-#if _FS_LOCK
-                if (res == FR_OK) {
-                    if (dp->sclust) {
-                        dp->lockid = inc_lock(dp, 0); /* Lock the sub directory */
-                        if (!dp->lockid)
-                            res = FR_TOO_MANY_OPEN_FILES;
-                    } else {
-                        dp->lockid = 0; /* Root directory need not to be locked */
-                    }
-                }
-#endif
-            }
-        }
-        if (res == FR_NO_FILE)
-            res = FR_NO_PATH;
-    }
-    if (res != FR_OK)
-        dp->fs = 0; /* Invalidate the directory object if function faild */
-
-    LEAVE_FF(fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Close Directory                                                       */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_closedir(DIR *dp /* Pointer to the directory object to be closed */
-           )
-{
-    FRESULT res;
-
-    res = validate(dp);
-    if (res == FR_OK) {
-#if _FS_REENTRANT
-        FATFS *fs = dp->fs;
-#endif
-#if _FS_LOCK
-        if (dp->lockid) /* Decrement sub-directory open counter */
-            res = dec_lock(dp->lockid);
-        if (res == FR_OK)
-#endif
-            dp->fs = 0; /* Invalidate directory object */
-#if _FS_REENTRANT
-        unlock_fs(fs, FR_OK); /* Unlock volume */
-#endif
-    }
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Read Directory Entries in Sequence                                    */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_readdir(DIR *dp,     /* Pointer to the open directory object */
-          FILINFO *fno /* Pointer to file information to return */
-          )
-{
-    FRESULT res;
-    DEFINE_NAMEBUF;
-
-    res = validate(dp); /* Check validity of the object */
-    if (res == FR_OK) {
-        if (!fno) {
-            res = dir_sdi(dp, 0); /* Rewind the directory object */
-        } else {
-            INIT_BUF(*dp);
-            res = dir_read(dp, 0);   /* Read an item */
-            if (res == FR_NO_FILE) { /* Reached end of directory */
-                dp->sect = 0;
-                res = FR_OK;
-            }
-            if (res == FR_OK) {        /* A valid entry is found */
-                get_fileinfo(dp, fno); /* Get the object information */
-                res = dir_next(dp, 0); /* Increment index for next */
-                if (res == FR_NO_FILE) {
-                    dp->sect = 0;
-                    res = FR_OK;
-                }
-            }
-            FREE_BUF();
-        }
-    }
-
-    LEAVE_FF(dp->fs, res);
-}
-
-#if _USE_FIND
-/*-----------------------------------------------------------------------*/
-/* Find next file                                                        */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_findnext(DIR *dp,     /* Pointer to the open directory object */
-           FILINFO *fno /* Pointer to the file information structure */
-           )
-{
-    FRESULT res;
-
-    for (;;) {
-        res = f_readdir(dp, fno); /* Get a directory item */
-        if (res != FR_OK || !fno || !fno->fname[0])
-            break; /* Terminate if any error or end of directory */
-#if _USE_LFN
-        if (fno->lfname && pattern_matching(dp->pat, fno->lfname, 0, 0))
-            break; /* Test for LFN if exist */
-#endif
-        if (pattern_matching(dp->pat, fno->fname, 0, 0))
-            break; /* Test for SFN */
-    }
-    return res;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Find first file                                                       */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_findfirst(DIR *dp,             /* Pointer to the blank directory object */
-            FILINFO *fno,        /* Pointer to the file information structure */
-            const TCHAR *path,   /* Pointer to the directory to open */
-            const TCHAR *pattern /* Pointer to the matching pattern */
-            )
-{
-    FRESULT res;
-
-    dp->pat = pattern;         /* Save pointer to pattern string */
-    res = f_opendir(dp, path); /* Open the target directory */
-    if (res == FR_OK)
-        res = f_findnext(dp, fno); /* Find the first item */
-    return res;
-}
-
-#endif /* _USE_FIND */
-
-#if _FS_MINIMIZE == 0
-/*-----------------------------------------------------------------------*/
-/* Get File Status                                                       */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_stat(const TCHAR *path, /* Pointer to the file path */
-       FILINFO *fno       /* Pointer to file information to return */
-       )
-{
-    FRESULT res;
-    DIR dj;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 0);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        if (res == FR_OK) {           /* Follow completed */
-            if (dj.dir) {             /* Found an object */
-                if (fno)
-                    get_fileinfo(&dj, fno);
-            } else { /* It is root directory */
-                res = FR_INVALID_NAME;
-            }
-        }
-        FREE_BUF();
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-#if !_FS_READONLY
-/*-----------------------------------------------------------------------*/
-/* Get Number of Free Clusters                                           */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_getfree(const TCHAR *path, /* Path name of the logical drive number */
-          DWORD *nclst,      /* Pointer to a variable to return number of free clusters */
-          FATFS **fatfs      /* Pointer to return pointer to corresponding file system object */
-          )
-{
-    FRESULT res;
-    FATFS *fs;
-    DWORD n, clst, sect, stat;
-    UINT i;
-    BYTE fat, *p;
-
-    /* Get logical drive number */
-    res = find_volume(fatfs, &path, 0);
-    fs = *fatfs;
-    if (res == FR_OK) {
-        /* If free_clust is valid, return it without full cluster scan */
-        if (fs->free_clust <= fs->n_fatent - 2) {
-            *nclst = fs->free_clust;
-        } else {
-            /* Get number of free clusters */
-            fat = fs->fs_type;
-            n = 0;
-            if (fat == FS_FAT12) {
-                clst = 2;
-                do {
-                    stat = get_fat(fs, clst);
-                    if (stat == 0xFFFFFFFF) {
-                        res = FR_DISK_ERR;
-                        break;
-                    }
-                    if (stat == 1) {
-                        res = FR_INT_ERR;
-                        break;
-                    }
-                    if (stat == 0)
-                        n++;
-                } while (++clst < fs->n_fatent);
-            } else {
-                clst = fs->n_fatent;
-                sect = fs->fatbase;
-                i = 0;
-                p = 0;
-                do {
-                    if (!i) {
-                        res = move_window(fs, sect++);
-                        if (res != FR_OK)
-                            break;
-                        p = fs->win;
-                        i = SS(fs);
-                    }
-                    if (fat == FS_FAT16) {
-                        if (LD_WORD(p) == 0)
-                            n++;
-                        p += 2;
-                        i -= 2;
-                    } else {
-                        if ((LD_DWORD(p) & 0x0FFFFFFF) == 0)
-                            n++;
-                        p += 4;
-                        i -= 4;
-                    }
-                } while (--clst);
-            }
-            fs->free_clust = n;
-            fs->fsi_flag |= 1;
-            *nclst = n;
-        }
-    }
-    LEAVE_FF(fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Truncate File                                                         */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_truncate(FIL *fp /* Pointer to the file object */
-           )
-{
-    FRESULT res;
-    DWORD ncl;
-
-    res = validate(fp); /* Check validity of the object */
-    if (res == FR_OK) {
-        if (fp->err) { /* Check error */
-            res = (FRESULT)fp->err;
-        } else {
-            if (!(fp->flag & FA_WRITE)) /* Check access mode */
-                res = FR_DENIED;
-        }
-    }
-    if (res == FR_OK) {
-        if (fp->fsize > fp->fptr) {
-            fp->fsize = fp->fptr; /* Set file size to current R/W point */
-            fp->flag |= FA__WRITTEN;
-            if (fp->fptr == 0) { /* When set file size to zero, remove entire cluster chain */
-                res = remove_chain(fp->fs, fp->sclust);
-                fp->sclust = 0;
-            } else { /* When truncate a part of the file, remove remaining clusters */
-                ncl = get_fat(fp->fs, fp->clust);
-                res = FR_OK;
-                if (ncl == 0xFFFFFFFF)
-                    res = FR_DISK_ERR;
-                if (ncl == 1)
-                    res = FR_INT_ERR;
-                if (res == FR_OK && ncl < fp->fs->n_fatent) {
-                    res = put_fat(fp->fs, fp->clust, 0x0FFFFFFF);
-                    if (res == FR_OK)
-                        res = remove_chain(fp->fs, ncl);
-                }
-            }
-#if !_FS_TINY
-            if (res == FR_OK && (fp->flag & FA__DIRTY)) {
-                if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
-                    res = FR_DISK_ERR;
-                else
-                    fp->flag &= ~FA__DIRTY;
-            }
-#endif
-        }
-        if (res != FR_OK)
-            fp->err = (FRESULT)res;
-    }
-
-    LEAVE_FF(fp->fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Delete a File or Directory                                            */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_unlink(const TCHAR *path /* Pointer to the file or directory path */
-         )
-{
-    FRESULT res;
-    DIR dj, sdj;
-    BYTE *dir;
-    DWORD dclst = 0;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 1);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
-            res = FR_INVALID_NAME; /* Cannot remove dot entry */
-#if _FS_LOCK
-        if (res == FR_OK)
-            res = chk_lock(&dj, 2); /* Cannot remove open object */
-#endif
-        if (res == FR_OK) { /* The object is accessible */
-            dir = dj.dir;
-            if (!dir) {
-                res = FR_INVALID_NAME; /* Cannot remove the origin directory */
-            } else {
-                if (dir[DIR_Attr] & AM_RDO)
-                    res = FR_DENIED; /* Cannot remove R/O object */
-            }
-            if (res == FR_OK) {
-                dclst = ld_clust(dj.fs, dir);
-                if (dclst && (dir[DIR_Attr] & AM_DIR)) { /* Is it a sub-directory ? */
-#if _FS_RPATH
-                    if (dclst == dj.fs->cdir) { /* Is it the current directory? */
-                        res = FR_DENIED;
-                    } else
-#endif
-                    {
-                        mem_cpy(&sdj, &dj, sizeof(DIR)); /* Open the sub-directory */
-                        sdj.sclust = dclst;
-                        res = dir_sdi(&sdj, 2);
-                        if (res == FR_OK) {
-                            res = dir_read(&sdj, 0); /* Read an item (excluding dot entries) */
-                            if (res == FR_OK)
-                                res = FR_DENIED; /* Not empty? (cannot remove) */
-                            if (res == FR_NO_FILE)
-                                res = FR_OK; /* Empty? (can remove) */
-                        }
-                    }
-                }
-            }
-            if (res == FR_OK) {
-                res = dir_remove(&dj);     /* Remove the directory entry */
-                if (res == FR_OK && dclst) /* Remove the cluster chain if exist */
-                    res = remove_chain(dj.fs, dclst);
-                if (res == FR_OK)
-                    res = sync_fs(dj.fs);
-            }
-        }
-        FREE_BUF();
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Create a Directory                                                    */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_mkdir(const TCHAR *path /* Pointer to the directory path */
-        )
-{
-    FRESULT res;
-    DIR dj;
-    BYTE *dir, n;
-    DWORD dsc, dcl, pcl, tm = GET_FATTIME();
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 1);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        if (res == FR_OK)
-            res = FR_EXIST; /* Any object with same name is already existing */
-        if (_FS_RPATH && res == FR_NO_FILE && (dj.fn[NSFLAG] & NS_DOT))
-            res = FR_INVALID_NAME;
-        if (res == FR_NO_FILE) {          /* Can create a new directory */
-            dcl = create_chain(dj.fs, 0); /* Allocate a cluster for the new directory table */
-            res = FR_OK;
-            if (dcl == 0)
-                res = FR_DENIED; /* No space to allocate a new cluster */
-            if (dcl == 1)
-                res = FR_INT_ERR;
-            if (dcl == 0xFFFFFFFF)
-                res = FR_DISK_ERR;
-            if (res == FR_OK) /* Flush FAT */
-                res = sync_window(dj.fs);
-            if (res == FR_OK) { /* Initialize the new directory table */
-                dsc = clust2sect(dj.fs, dcl);
-                dir = dj.fs->win;
-                mem_set(dir, 0, SS(dj.fs));
-                mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
-                dir[DIR_Name] = '.';
-                dir[DIR_Attr] = AM_DIR;
-                ST_DWORD(dir + DIR_WrtTime, tm);
-                st_clust(dir, dcl);
-                mem_cpy(dir + SZ_DIRE, dir, SZ_DIRE); /* Create ".." entry */
-                dir[SZ_DIRE + 1] = '.';
-                pcl = dj.sclust;
-                if (dj.fs->fs_type == FS_FAT32 && pcl == dj.fs->dirbase)
-                    pcl = 0;
-                st_clust(dir + SZ_DIRE, pcl);
-                for (n = dj.fs->csize; n; n--) { /* Write dot entries and clear following sectors */
-                    dj.fs->winsect = dsc++;
-                    dj.fs->wflag = 1;
-                    res = sync_window(dj.fs);
-                    if (res != FR_OK)
-                        break;
-                    mem_set(dir, 0, SS(dj.fs));
-                }
-            }
-            if (res == FR_OK)
-                res = dir_register(&dj); /* Register the object to the directoy */
-            if (res != FR_OK) {
-                remove_chain(dj.fs, dcl); /* Could not register, remove cluster chain */
-            } else {
-                dir = dj.dir;
-                dir[DIR_Attr] = AM_DIR;          /* Attribute */
-                ST_DWORD(dir + DIR_WrtTime, tm); /* Created time */
-                st_clust(dir, dcl);              /* Table start cluster */
-                dj.fs->wflag = 1;
-                res = sync_fs(dj.fs);
-            }
-        }
-        FREE_BUF();
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Change Attribute                                                      */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_chmod(const TCHAR *path, /* Pointer to the file path */
-        BYTE attr,         /* Attribute bits */
-        BYTE mask          /* Attribute mask to change */
-        )
-{
-    FRESULT res;
-    DIR dj;
-    BYTE *dir;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 1);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        FREE_BUF();
-        if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
-            res = FR_INVALID_NAME;
-        if (res == FR_OK) {
-            dir = dj.dir;
-            if (!dir) { /* Is it a root directory? */
-                res = FR_INVALID_NAME;
-            } else {                                                           /* File or sub directory */
-                mask &= AM_RDO | AM_HID | AM_SYS | AM_ARC;                     /* Valid attribute mask */
-                dir[DIR_Attr] = (attr & mask) | (dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
-                dj.fs->wflag = 1;
-                res = sync_fs(dj.fs);
-            }
-        }
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Rename File/Directory                                                 */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_rename(const TCHAR *path_old, /* Pointer to the object to be renamed */
-         const TCHAR *path_new  /* Pointer to the new name */
-         )
-{
-    FRESULT res;
-    DIR djo, djn;
-    BYTE buf[21], *dir;
-    DWORD dw;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number of the source object */
-    res = find_volume(&djo.fs, &path_old, 1);
-    if (res == FR_OK) {
-        djn.fs = djo.fs;
-        INIT_BUF(djo);
-        res = follow_path(&djo, path_old); /* Check old object */
-        if (_FS_RPATH && res == FR_OK && (djo.fn[NSFLAG] & NS_DOT))
-            res = FR_INVALID_NAME;
-#if _FS_LOCK
-        if (res == FR_OK)
-            res = chk_lock(&djo, 2);
-#endif
-        if (res == FR_OK) { /* Old object is found */
-            if (!djo.dir) { /* Is root dir? */
-                res = FR_NO_FILE;
-            } else {
-                mem_cpy(buf, djo.dir + DIR_Attr, 21);  /* Save information about object except name */
-                mem_cpy(&djn, &djo, sizeof(DIR));      /* Duplicate the directory object */
-                if (get_ldnumber(&path_new) >= 0)      /* Snip drive number off and ignore it */
-                    res = follow_path(&djn, path_new); /* and make sure if new object name is not conflicting */
-                else
-                    res = FR_INVALID_DRIVE;
-                if (res == FR_OK)
-                    res = FR_EXIST;           /* The new object name is already existing */
-                if (res == FR_NO_FILE) {      /* It is a valid path and no name collision */
-                    res = dir_register(&djn); /* Register the new entry */
-                    if (res == FR_OK) {
-                        /* Start of critical section where any interruption can cause a cross-link */
-                        dir = djn.dir; /* Copy information about object except name */
-                        mem_cpy(dir + 13, buf + 2, 19);
-                        dir[DIR_Attr] = buf[0] | AM_ARC;
-                        djo.fs->wflag = 1;
-                        if ((dir[DIR_Attr] & AM_DIR) && djo.sclust != djn.sclust) { /* Update .. entry in the sub-directory if needed */
-                            dw = clust2sect(djo.fs, ld_clust(djo.fs, dir));
-                            if (!dw) {
-                                res = FR_INT_ERR;
-                            } else {
-                                res = move_window(djo.fs, dw);
-                                dir = djo.fs->win + SZ_DIRE * 1; /* Ptr to .. entry */
-                                if (res == FR_OK && dir[1] == '.') {
-                                    st_clust(dir, djn.sclust);
-                                    djo.fs->wflag = 1;
-                                }
-                            }
-                        }
-                        if (res == FR_OK) {
-                            res = dir_remove(&djo); /* Remove old entry */
-                            if (res == FR_OK)
-                                res = sync_fs(djo.fs);
-                        }
-                        /* End of critical section */
-                    }
-                }
-            }
-        }
-        FREE_BUF();
-    }
-
-    LEAVE_FF(djo.fs, res);
-}
-
-/*-----------------------------------------------------------------------*/
-/* Change Timestamp                                                      */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_utime(const TCHAR *path, /* Pointer to the file/directory name */
-        const FILINFO *fno /* Pointer to the time stamp to be set */
-        )
-{
-    FRESULT res;
-    DIR dj;
-    BYTE *dir;
-    DEFINE_NAMEBUF;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 1);
-    if (res == FR_OK) {
-        INIT_BUF(dj);
-        res = follow_path(&dj, path); /* Follow the file path */
-        FREE_BUF();
-        if (_FS_RPATH && res == FR_OK && (dj.fn[NSFLAG] & NS_DOT))
-            res = FR_INVALID_NAME;
-        if (res == FR_OK) {
-            dir = dj.dir;
-            if (!dir) { /* Root directory */
-                res = FR_INVALID_NAME;
-            } else { /* File or sub-directory */
-                ST_WORD(dir + DIR_WrtTime, fno->ftime);
-                ST_WORD(dir + DIR_WrtDate, fno->fdate);
-                dj.fs->wflag = 1;
-                res = sync_fs(dj.fs);
-            }
-        }
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-#endif /* !_FS_READONLY */
-#endif /* _FS_MINIMIZE == 0 */
-#endif /* _FS_MINIMIZE <= 1 */
-#endif /* _FS_MINIMIZE <= 2 */
-
-#if _USE_LABEL
-/*-----------------------------------------------------------------------*/
-/* Get volume label                                                      */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_getlabel(const TCHAR *path, /* Path name of the logical drive number */
-           TCHAR *label,      /* Pointer to a buffer to return the volume label */
-           DWORD *vsn         /* Pointer to a variable to return the volume serial number */
-           )
-{
-    FRESULT res;
-    DIR dj;
-    UINT i, j;
-#if _USE_LFN && _LFN_UNICODE
-    WCHAR w;
-#endif
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &path, 0);
-
-    /* Get volume label */
-    if (res == FR_OK && label) {
-        dj.sclust = 0; /* Open root directory */
-        res = dir_sdi(&dj, 0);
-        if (res == FR_OK) {
-            res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
-            if (res == FR_OK) {     /* A volume label is exist */
-#if _USE_LFN && _LFN_UNICODE
-                i = j = 0;
-                do {
-                    w = (i < 11) ? dj.dir[i++] : ' ';
-                    if (IsDBCS1(w) && i < 11 && IsDBCS2(dj.dir[i]))
-                        w = w << 8 | dj.dir[i++];
-                    label[j++] = ff_convert(w, 1); /* OEM -> Unicode */
-                } while (j < 11);
-#else
-                mem_cpy(label, dj.dir, 11);
-#endif
-                j = 11;
-                do {
-                    label[j] = 0;
-                    if (!j)
-                        break;
-                } while (label[--j] == ' ');
-            }
-            if (res == FR_NO_FILE) { /* No label, return nul string */
-                label[0] = 0;
-                res = FR_OK;
-            }
-        }
-    }
-
-    /* Get volume serial number */
-    if (res == FR_OK && vsn) {
-        res = move_window(dj.fs, dj.fs->volbase);
-        if (res == FR_OK) {
-            i = dj.fs->fs_type == FS_FAT32 ? BS_VolID32 : BS_VolID;
-            *vsn = LD_DWORD(&dj.fs->win[i]);
-        }
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-#if !_FS_READONLY
-/*-----------------------------------------------------------------------*/
-/* Set volume label                                                      */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_setlabel(const TCHAR *label /* Pointer to the volume label to set */
-           )
-{
-    FRESULT res;
-    DIR dj;
-    BYTE vn[11];
-    UINT i, j, sl;
-    WCHAR w;
-    DWORD tm;
-
-    /* Get logical drive number */
-    res = find_volume(&dj.fs, &label, 1);
-    if (res)
-        LEAVE_FF(dj.fs, res);
-
-    /* Create a volume label in directory form */
-    vn[0] = 0;
-    for (sl = 0; label[sl]; sl++)
-        ; /* Get name length */
-    for (; sl && label[sl - 1] == ' '; sl--)
-        ;     /* Remove trailing spaces */
-    if (sl) { /* Create volume label in directory form */
-        i = j = 0;
-        do {
-#if _USE_LFN && _LFN_UNICODE
-            w = ff_convert(ff_wtoupper(label[i++]), 0);
-#else
-            w = (BYTE)label[i++];
-            if (IsDBCS1(w))
-                w = (j < 10 && i < sl && IsDBCS2(label[i])) ? w << 8 | (BYTE)label[i++] : 0;
-#if _USE_LFN
-            w = ff_convert(ff_wtoupper(ff_convert(w, 1)), 0);
-#else
-            if (IsLower(w))
-                w -= 0x20; /* To upper ASCII characters */
-#ifdef _EXCVT
-            if (w >= 0x80)
-                w = ExCvt[w - 0x80]; /* To upper extended characters (SBCS cfg) */
-#else
-            if (!_DF1S && w >= 0x80)
-                w = 0; /* Reject extended characters (ASCII cfg) */
-#endif
-#endif
-#endif
-            if (!w || chk_chr("\"*+,.:;<=>\?[]|\x7F", w) || j >= (UINT)((w >= 0x100) ? 10 : 11)) /* Reject invalid characters for volume label */
-                LEAVE_FF(dj.fs, FR_INVALID_NAME);
-            if (w >= 0x100)
-                vn[j++] = (BYTE)(w >> 8);
-            vn[j++] = (BYTE)w;
-        } while (i < sl);
-        while (j < 11)
-            vn[j++] = ' '; /* Fill remaining name field */
-        if (vn[0] == DDEM)
-            LEAVE_FF(dj.fs, FR_INVALID_NAME); /* Reject illegal name (heading DDEM) */
-    }
-
-    /* Set volume label */
-    dj.sclust = 0; /* Open root directory */
-    res = dir_sdi(&dj, 0);
-    if (res == FR_OK) {
-        res = dir_read(&dj, 1); /* Get an entry with AM_VOL */
-        if (res == FR_OK) {     /* A volume label is found */
-            if (vn[0]) {
-                mem_cpy(dj.dir, vn, 11); /* Change the volume label name */
-                tm = GET_FATTIME();
-                ST_DWORD(dj.dir + DIR_WrtTime, tm);
-            } else {
-                dj.dir[0] = DDEM; /* Remove the volume label */
-            }
-            dj.fs->wflag = 1;
-            res = sync_fs(dj.fs);
-        } else { /* No volume label is found or error */
-            if (res == FR_NO_FILE) {
-                res = FR_OK;
-                if (vn[0]) {                 /* Create volume label as new */
-                    res = dir_alloc(&dj, 1); /* Allocate an entry for volume label */
-                    if (res == FR_OK) {
-                        mem_set(dj.dir, 0, SZ_DIRE); /* Set volume label */
-                        mem_cpy(dj.dir, vn, 11);
-                        dj.dir[DIR_Attr] = AM_VOL;
-                        tm = GET_FATTIME();
-                        ST_DWORD(dj.dir + DIR_WrtTime, tm);
-                        dj.fs->wflag = 1;
-                        res = sync_fs(dj.fs);
-                    }
-                }
-            }
-        }
-    }
-
-    LEAVE_FF(dj.fs, res);
-}
-
-#endif /* !_FS_READONLY */
-#endif /* _USE_LABEL */
-
-/*-----------------------------------------------------------------------*/
-/* Forward data to the stream directly (available on only tiny cfg)      */
-/*-----------------------------------------------------------------------*/
-#if _USE_FORWARD && _FS_TINY
-
-FRESULT
-f_forward(FIL *fp,                          /* Pointer to the file object */
-          UINT (*func)(const BYTE *, UINT), /* Pointer to the streaming function */
-          UINT btf,                         /* Number of bytes to forward */
-          UINT *bf                          /* Pointer to number of bytes forwarded */
-          )
-{
-    FRESULT res;
-    DWORD remain, clst, sect;
-    UINT rcnt;
-    BYTE csect;
-
-    *bf = 0; /* Clear transfer byte counter */
-
-    res = validate(fp); /* Check validity of the object */
-    if (res != FR_OK)
-        LEAVE_FF(fp->fs, res);
-    if (fp->err) /* Check error */
-        LEAVE_FF(fp->fs, (FRESULT)fp->err);
-    if (!(fp->flag & FA_READ)) /* Check access mode */
-        LEAVE_FF(fp->fs, FR_DENIED);
-
-    remain = fp->fsize - fp->fptr;
-    if (btf > remain)
-        btf = (UINT)remain; /* Truncate btf by remaining bytes */
-
-    for (; btf && (*func)(0, 0); /* Repeat until all data transferred or stream becomes busy */
-         fp->fptr += rcnt, *bf += rcnt, btf -= rcnt) {
-        csect = (BYTE)(fp->fptr / SS(fp->fs) & (fp->fs->csize - 1)); /* Sector offset in the cluster */
-        if ((fp->fptr % SS(fp->fs)) == 0) {                          /* On the sector boundary? */
-            if (!csect) {                                            /* On the cluster boundary? */
-                clst = (fp->fptr == 0) ?                             /* On the top of the file? */
-                           fp->sclust
-                                       : get_fat(fp->fs, fp->clust);
-                if (clst <= 1)
-                    ABORT(fp->fs, FR_INT_ERR);
-                if (clst == 0xFFFFFFFF)
-                    ABORT(fp->fs, FR_DISK_ERR);
-                fp->clust = clst; /* Update current cluster */
-            }
-        }
-        sect = clust2sect(fp->fs, fp->clust); /* Get current data sector */
-        if (!sect)
-            ABORT(fp->fs, FR_INT_ERR);
-        sect += csect;
-        if (move_window(fp->fs, sect) != FR_OK) /* Move sector window */
-            ABORT(fp->fs, FR_DISK_ERR);
-        fp->dsect = sect;
-        rcnt = SS(fp->fs) - (WORD)(fp->fptr % SS(fp->fs)); /* Forward data from sector window */
-        if (rcnt > btf)
-            rcnt = btf;
-        rcnt = (*func)(&fp->fs->win[(WORD)fp->fptr % SS(fp->fs)], rcnt);
-        if (!rcnt)
-            ABORT(fp->fs, FR_INT_ERR);
-    }
-
-    LEAVE_FF(fp->fs, FR_OK);
-}
-#endif /* _USE_FORWARD */
-
-#if _USE_MKFS && !_FS_READONLY
-/*-----------------------------------------------------------------------*/
-/* Create file system on the logical drive                               */
-/*-----------------------------------------------------------------------*/
-#define N_ROOTDIR 512 /* Number of root directory entries for FAT12/16 */
-#define N_FATS 1      /* Number of FATs (1 or 2) */
-
-FRESULT
-f_mkfs(const TCHAR *path, /* Logical drive number */
-       BYTE sfd,          /* Partitioning rule 0:FDISK, 1:SFD */
-       UINT au            /* Size of allocation unit in unit of byte or sector */
-       )
-{
-    static const WORD vst[] = { 1024, 512, 256, 128, 64, 32, 16, 8, 4, 2, 0 };
-    static const WORD cst[] = { 32768, 16384, 8192, 4096, 2048, 16384, 8192, 4096, 2048, 1024, 512 };
-    int vol;
-    BYTE fmt, md, sys, *tbl, pdrv, part;
-    DWORD n_clst, vs, n, wsect;
-    UINT i;
-    DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
-    DWORD n_vol, n_rsv, n_fat, n_dir;  /* Size */
-    FATFS *fs;
-    DSTATUS stat;
-#if _USE_TRIM
-    DWORD eb[2];
-#endif
-
-    /* Check mounted drive and clear work area */
-    if (sfd > 1)
-        return FR_INVALID_PARAMETER;
-    vol = get_ldnumber(&path);
-    if (vol < 0)
-        return FR_INVALID_DRIVE;
-    fs = FatFs[vol];
-    if (!fs)
-        return FR_NOT_ENABLED;
-    fs->fs_type = 0;
-    pdrv = LD2PD(vol); /* Physical drive */
-    part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/
-
-    /* Get disk statics */
-    stat = disk_initialize(pdrv);
-    if (stat & STA_NOINIT)
-        return FR_NOT_READY;
-    if (stat & STA_PROTECT)
-        return FR_WRITE_PROTECTED;
-#if _MAX_SS != _MIN_SS /* Get disk sector size */
-    if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK || SS(fs) > _MAX_SS || SS(fs) < _MIN_SS)
-        return FR_DISK_ERR;
-#endif
-    if (_MULTI_PARTITION && part) {
-        /* Get partition information from partition table in the MBR */
-        if (disk_read(pdrv, fs->win, 0, 1) != RES_OK)
-            return FR_DISK_ERR;
-        if (LD_WORD(fs->win + BS_55AA) != 0xAA55)
-            return FR_MKFS_ABORTED;
-        tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
-        if (!tbl[4])
-            return FR_MKFS_ABORTED; /* No partition? */
-        b_vol = LD_DWORD(tbl + 8);  /* Volume start sector */
-        n_vol = LD_DWORD(tbl + 12); /* Volume size */
-    } else {
-        /* Create a partition in this function */
-        if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128)
-            return FR_DISK_ERR;
-        b_vol = (sfd) ? 0 : 63; /* Volume start sector */
-        n_vol -= b_vol;         /* Volume size */
-    }
-
-    if (au & (au - 1))
-        au = 0;
-    if (!au) { /* AU auto selection */
-        vs = n_vol / (2000 / (SS(fs) / 512));
-        for (i = 0; vs < vst[i]; i++)
-            ;
-        au = cst[i];
-    }
-    if (au >= _MIN_SS)
-        au /= SS(fs); /* Number of sectors per cluster */
-    if (!au)
-        au = 1;
-    if (au > 128)
-        au = 128;
-
-    /* Pre-compute number of clusters and FAT sub-type */
-    n_clst = n_vol / au;
-    fmt = FS_FAT12;
-    if (n_clst >= MIN_FAT16)
-        fmt = FS_FAT16;
-    if (n_clst >= MIN_FAT32)
-        fmt = FS_FAT32;
-
-    /* Determine offset and size of FAT structure */
-    if (fmt == FS_FAT32) {
-        n_fat = ((n_clst * 4) + 8 + SS(fs) - 1) / SS(fs);
-        n_rsv = 32;
-        n_dir = 0;
-    } else {
-        n_fat = (fmt == FS_FAT12) ? (n_clst * 3 + 1) / 2 + 3 : (n_clst * 2) + 4;
-        n_fat = (n_fat + SS(fs) - 1) / SS(fs);
-        n_rsv = 1;
-        n_dir = (DWORD)N_ROOTDIR * SZ_DIRE / SS(fs);
-    }
-    b_fat = b_vol + n_rsv;          /* FAT area start sector */
-    b_dir = b_fat + n_fat * N_FATS; /* Directory area start sector */
-    b_data = b_dir + n_dir;         /* Data area start sector */
-    if (n_vol < b_data + au - b_vol)
-        return FR_MKFS_ABORTED; /* Too small volume */
-
-    /* Align data start sector to erase block boundary (for flash memory media) */
-    if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &n) != RES_OK || !n || n > 32768)
-        n = 1;
-    n = (b_data + n - 1) & ~(n - 1); /* Next nearest erase block from current data start */
-    n = (n - b_data) / N_FATS;
-    if (fmt == FS_FAT32) { /* FAT32: Move FAT offset */
-        n_rsv += n;
-        b_fat += n;
-    } else { /* FAT12/16: Expand FAT size */
-        n_fat += n;
-    }
-
-    /* Determine number of clusters and final check of validity of the FAT sub-type */
-    n_clst = (n_vol - n_rsv - n_fat * N_FATS - n_dir) / au;
-    if ((fmt == FS_FAT16 && n_clst < MIN_FAT16) || (fmt == FS_FAT32 && n_clst < MIN_FAT32))
-        return FR_MKFS_ABORTED;
-
-    /* Determine system ID in the partition table */
-    if (fmt == FS_FAT32) {
-        sys = 0x0C; /* FAT32X */
-    } else {
-        if (fmt == FS_FAT12 && n_vol < 0x10000) {
-            sys = 0x01; /* FAT12(<65536) */
-        } else {
-            sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */
-        }
-    }
-
-    if (_MULTI_PARTITION && part) {
-        /* Update system ID in the partition table */
-        tbl = &fs->win[MBR_Table + (part - 1) * SZ_PTE];
-        tbl[4] = sys;
-        if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to teh MBR */
-            return FR_DISK_ERR;
-        md = 0xF8;
-    } else {
-        if (sfd) { /* No partition table (SFD) */
-            md = 0xF0;
-        } else { /* Create partition table (FDISK) */
-            mem_set(fs->win, 0, SS(fs));
-            tbl = fs->win + MBR_Table; /* Create partition table for single partition in the drive */
-            tbl[1] = 1;                /* Partition start head */
-            tbl[2] = 1;                /* Partition start sector */
-            tbl[3] = 0;                /* Partition start cylinder */
-            tbl[4] = sys;              /* System type */
-            tbl[5] = 254;              /* Partition end head */
-            n = (b_vol + n_vol) / 63 / 255;
-            tbl[6] = (BYTE)(n >> 2 | 63);                  /* Partition end sector */
-            tbl[7] = (BYTE)n;                              /* End cylinder */
-            ST_DWORD(tbl + 8, 63);                         /* Partition start in LBA */
-            ST_DWORD(tbl + 12, n_vol);                     /* Partition size in LBA */
-            ST_WORD(fs->win + BS_55AA, 0xAA55);            /* MBR signature */
-            if (disk_write(pdrv, fs->win, 0, 1) != RES_OK) /* Write it to the MBR */
-                return FR_DISK_ERR;
-            md = 0xF8;
-        }
-    }
-
-    /* Create BPB in the VBR */
-    tbl = fs->win; /* Clear sector */
-    mem_set(tbl, 0, SS(fs));
-    mem_cpy(tbl, "\xEB\xFE\x90"
-                 "MSDOS5.0",
-            11); /* Boot jump code, OEM name */
-    i = SS(fs);  /* Sector size */
-    ST_WORD(tbl + BPB_BytsPerSec, i);
-    tbl[BPB_SecPerClus] = (BYTE)au;        /* Sectors per cluster */
-    ST_WORD(tbl + BPB_RsvdSecCnt, n_rsv);  /* Reserved sectors */
-    tbl[BPB_NumFATs] = N_FATS;             /* Number of FATs */
-    i = (fmt == FS_FAT32) ? 0 : N_ROOTDIR; /* Number of root directory entries */
-    ST_WORD(tbl + BPB_RootEntCnt, i);
-    if (n_vol < 0x10000) { /* Number of total sectors */
-        ST_WORD(tbl + BPB_TotSec16, n_vol);
-    } else {
-        ST_DWORD(tbl + BPB_TotSec32, n_vol);
-    }
-    tbl[BPB_Media] = md;                /* Media descriptor */
-    ST_WORD(tbl + BPB_SecPerTrk, 63);   /* Number of sectors per track */
-    ST_WORD(tbl + BPB_NumHeads, 255);   /* Number of heads */
-    ST_DWORD(tbl + BPB_HiddSec, b_vol); /* Hidden sectors */
-    n = GET_FATTIME();                  /* Use current time as VSN */
-    if (fmt == FS_FAT32) {
-        ST_DWORD(tbl + BS_VolID32, n);      /* VSN */
-        ST_DWORD(tbl + BPB_FATSz32, n_fat); /* Number of sectors per FAT */
-        ST_DWORD(tbl + BPB_RootClus, 2);    /* Root directory start cluster (2) */
-        ST_WORD(tbl + BPB_FSInfo, 1);       /* FSINFO record offset (VBR + 1) */
-        ST_WORD(tbl + BPB_BkBootSec, 6);    /* Backup boot record offset (VBR + 6) */
-        tbl[BS_DrvNum32] = 0x80;            /* Drive number */
-        tbl[BS_BootSig32] = 0x29;           /* Extended boot signature */
-        mem_cpy(tbl + BS_VolLab32, "NO NAME    "
-                                   "FAT32   ",
-                19); /* Volume label, FAT signature */
-    } else {
-        ST_DWORD(tbl + BS_VolID, n);       /* VSN */
-        ST_WORD(tbl + BPB_FATSz16, n_fat); /* Number of sectors per FAT */
-        tbl[BS_DrvNum] = 0x80;             /* Drive number */
-        tbl[BS_BootSig] = 0x29;            /* Extended boot signature */
-        mem_cpy(tbl + BS_VolLab, "NO NAME    "
-                                 "FAT     ",
-                19); /* Volume label, FAT signature */
-    }
-    ST_WORD(tbl + BS_55AA, 0xAA55);                /* Signature (Offset is fixed here regardless of sector size) */
-    if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
-        return FR_DISK_ERR;
-    if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */
-        disk_write(pdrv, tbl, b_vol + 6, 1);
-
-    /* Initialize FAT area */
-    wsect = b_fat;
-    for (i = 0; i < N_FATS; i++) { /* Initialize each FAT copy */
-        mem_set(tbl, 0, SS(fs));   /* 1st sector of the FAT  */
-        n = md;                    /* Media descriptor byte */
-        if (fmt != FS_FAT32) {
-            n |= (fmt == FS_FAT12) ? 0x00FFFF00 : 0xFFFFFF00;
-            ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT12/16) */
-        } else {
-            n |= 0xFFFFFF00;
-            ST_DWORD(tbl + 0, n); /* Reserve cluster #0-1 (FAT32) */
-            ST_DWORD(tbl + 4, 0xFFFFFFFF);
-            ST_DWORD(tbl + 8, 0x0FFFFFFF); /* Reserve cluster #2 for root directory */
-        }
-        if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
-            return FR_DISK_ERR;
-        mem_set(tbl, 0, SS(fs));      /* Fill following FAT entries with zero */
-        for (n = 1; n < n_fat; n++) { /* This loop may take a time on FAT32 volume due to many single sector writes */
-            if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
-                return FR_DISK_ERR;
-        }
-    }
-
-    /* Initialize root directory */
-    i = (fmt == FS_FAT32) ? au : (UINT)n_dir;
-    do {
-        if (disk_write(pdrv, tbl, wsect++, 1) != RES_OK)
-            return FR_DISK_ERR;
-    } while (--i);
-
-#if _USE_TRIM /* Erase data area if needed */
-    {
-        eb[0] = wsect;
-        eb[1] = wsect + (n_clst - ((fmt == FS_FAT32) ? 1 : 0)) * au - 1;
-        disk_ioctl(pdrv, CTRL_TRIM, eb);
-    }
-#endif
-
-    /* Create FSINFO if needed */
-    if (fmt == FS_FAT32) {
-        ST_DWORD(tbl + FSI_LeadSig, 0x41615252);
-        ST_DWORD(tbl + FSI_StrucSig, 0x61417272);
-        ST_DWORD(tbl + FSI_Free_Count, n_clst - 1); /* Number of free clusters */
-        ST_DWORD(tbl + FSI_Nxt_Free, 2);            /* Last allocated cluster# */
-        ST_WORD(tbl + BS_55AA, 0xAA55);
-        disk_write(pdrv, tbl, b_vol + 1, 1); /* Write original (VBR + 1) */
-        disk_write(pdrv, tbl, b_vol + 7, 1); /* Write backup (VBR + 7) */
-    }
-
-    return (disk_ioctl(pdrv, CTRL_SYNC, 0) == RES_OK) ? FR_OK : FR_DISK_ERR;
-}
-
-#if _MULTI_PARTITION
-/*-----------------------------------------------------------------------*/
-/* Create partition table on the physical drive                          */
-/*-----------------------------------------------------------------------*/
-
-FRESULT
-f_fdisk(BYTE pdrv,         /* Physical drive number */
-        const DWORD szt[], /* Pointer to the size table for each partitions */
-        void *work         /* Pointer to the working buffer */
-        )
-{
-    UINT i, n, sz_cyl, tot_cyl, b_cyl, e_cyl, p_cyl;
-    BYTE s_hd, e_hd, *p, *buf = (BYTE *)work;
-    DSTATUS stat;
-    DWORD sz_disk, sz_part, s_part;
-
-    stat = disk_initialize(pdrv);
-    if (stat & STA_NOINIT)
-        return FR_NOT_READY;
-    if (stat & STA_PROTECT)
-        return FR_WRITE_PROTECTED;
-    if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_disk))
-        return FR_DISK_ERR;
-
-    /* Determine CHS in the table regardless of the drive geometry */
-    for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2)
-        ;
-    if (n == 256)
-        n--;
-    e_hd = n - 1;
-    sz_cyl = 63 * n;
-    tot_cyl = sz_disk / sz_cyl;
-
-    /* Create partition table */
-    mem_set(buf, 0, _MAX_SS);
-    p = buf + MBR_Table;
-    b_cyl = 0;
-    for (i = 0; i < 4; i++, p += SZ_PTE) {
-        p_cyl = (szt[i] <= 100U) ? (DWORD)tot_cyl * szt[i] / 100 : szt[i] / sz_cyl;
-        if (!p_cyl)
-            continue;
-        s_part = (DWORD)sz_cyl * b_cyl;
-        sz_part = (DWORD)sz_cyl * p_cyl;
-        if (i == 0) { /* Exclude first track of cylinder 0 */
-            s_hd = 1;
-            s_part += 63;
-            sz_part -= 63;
-        } else {
-            s_hd = 0;
-        }
-        e_cyl = b_cyl + p_cyl - 1;
-        if (e_cyl >= tot_cyl)
-            return FR_INVALID_PARAMETER;
-
-        /* Set partition table */
-        p[1] = s_hd;                      /* Start head */
-        p[2] = (BYTE)((b_cyl >> 2) + 1);  /* Start sector */
-        p[3] = (BYTE)b_cyl;               /* Start cylinder */
-        p[4] = 0x06;                      /* System type (temporary setting) */
-        p[5] = e_hd;                      /* End head */
-        p[6] = (BYTE)((e_cyl >> 2) + 63); /* End sector */
-        p[7] = (BYTE)e_cyl;               /* End cylinder */
-        ST_DWORD(p + 8, s_part);          /* Start sector in LBA */
-        ST_DWORD(p + 12, sz_part);        /* Partition size */
-
-        /* Next partition */
-        b_cyl += p_cyl;
-    }
-    ST_WORD(p, 0xAA55);
-
-    /* Write it to the MBR */
-    return (disk_write(pdrv, buf, 0, 1) != RES_OK || disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) ? FR_DISK_ERR : FR_OK;
-}
-
-#endif /* _MULTI_PARTITION */
-#endif /* _USE_MKFS && !_FS_READONLY */
-
-#if _USE_STRFUNC
-/*-----------------------------------------------------------------------*/
-/* Get a string from the file                                            */
-/*-----------------------------------------------------------------------*/
-
-TCHAR *
-f_gets(TCHAR *buff, /* Pointer to the string buffer to read */
-       int len,     /* Size of string buffer (characters) */
-       FIL *fp      /* Pointer to the file object */
-       )
-{
-    int n = 0;
-    TCHAR c, *p = buff;
-    BYTE s[2];
-    UINT rc;
-
-    while (n < len - 1) { /* Read characters until buffer gets filled */
-#if _USE_LFN && _LFN_UNICODE
-#if _STRF_ENCODE == 3 /* Read a character in UTF-8 */
-        f_read(fp, s, 1, &rc);
-        if (rc != 1)
-            break;
-        c = s[0];
-        if (c >= 0x80) {
-            if (c < 0xC0)
-                continue;   /* Skip stray trailer */
-            if (c < 0xE0) { /* Two-byte sequence */
-                f_read(fp, s, 1, &rc);
-                if (rc != 1)
-                    break;
-                c = (c & 0x1F) << 6 | (s[0] & 0x3F);
-                if (c < 0x80)
-                    c = '?';
-            } else {
-                if (c < 0xF0) { /* Three-byte sequence */
-                    f_read(fp, s, 2, &rc);
-                    if (rc != 2)
-                        break;
-                    c = c << 12 | (s[0] & 0x3F) << 6 | (s[1] & 0x3F);
-                    if (c < 0x800)
-                        c = '?';
-                } else { /* Reject four-byte sequence */
-                    c = '?';
-                }
-            }
-        }
-#elif _STRF_ENCODE == 2 /* Read a character in UTF-16BE */
-        f_read(fp, s, 2, &rc);
-        if (rc != 2)
-            break;
-        c = s[1] + (s[0] << 8);
-#elif _STRF_ENCODE == 1 /* Read a character in UTF-16LE */
-        f_read(fp, s, 2, &rc);
-        if (rc != 2)
-            break;
-        c = s[0] + (s[1] << 8);
-#else                   /* Read a character in ANSI/OEM */
-        f_read(fp, s, 1, &rc);
-        if (rc != 1)
-            break;
-        c = s[0];
-        if (IsDBCS1(c)) {
-            f_read(fp, s, 1, &rc);
-            if (rc != 1)
-                break;
-            c = (c << 8) + s[0];
-        }
-        c = ff_convert(c, 1); /* OEM -> Unicode */
-        if (!c)
-            c = '?';
-#endif
-#else /* Read a character without conversion */
-        f_read(fp, s, 1, &rc);
-        if (rc != 1)
-            break;
-        c = s[0];
-#endif
-        if (_USE_STRFUNC == 2 && c == '\r')
-            continue; /* Strip '\r' */
-        *p++ = c;
-        n++;
-        if (c == '\n')
-            break; /* Break on EOL */
-    }
-    *p = 0;
-    return n ? buff : 0; /* When no data read (eof or error), return with error. */
-}
-
-#if !_FS_READONLY
-#include <stdarg.h>
-/*-----------------------------------------------------------------------*/
-/* Put a character to the file                                           */
-/*-----------------------------------------------------------------------*/
-
-typedef struct
-{
-    FIL *fp;
-    int idx, nchr;
-    BYTE buf[64];
-} putbuff;
-
-static void
-putc_bfd(putbuff *pb, TCHAR c)
-{
-    UINT bw;
-    int i;
-
-    if (_USE_STRFUNC == 2 && c == '\n') /* LF -> CRLF conversion */
-        putc_bfd(pb, '\r');
-
-    i = pb->idx; /* Buffer write index (-1:error) */
-    if (i < 0)
-        return;
-
-#if _USE_LFN && _LFN_UNICODE
-#if _STRF_ENCODE == 3 /* Write a character in UTF-8 */
-    if (c < 0x80) {   /* 7-bit */
-        pb->buf[i++] = (BYTE)c;
-    } else {
-        if (c < 0x800) { /* 11-bit */
-            pb->buf[i++] = (BYTE)(0xC0 | c >> 6);
-        } else { /* 16-bit */
-            pb->buf[i++] = (BYTE)(0xE0 | c >> 12);
-            pb->buf[i++] = (BYTE)(0x80 | (c >> 6 & 0x3F));
-        }
-        pb->buf[i++] = (BYTE)(0x80 | (c & 0x3F));
-    }
-#elif _STRF_ENCODE == 2 /* Write a character in UTF-16BE */
-    pb->buf[i++] = (BYTE)(c >> 8);
-    pb->buf[i++] = (BYTE)c;
-#elif _STRF_ENCODE == 1 /* Write a character in UTF-16LE */
-    pb->buf[i++] = (BYTE)c;
-    pb->buf[i++] = (BYTE)(c >> 8);
-#else                   /* Write a character in ANSI/OEM */
-    c = ff_convert(c, 0); /* Unicode -> OEM */
-    if (!c)
-        c = '?';
-    if (c >= 0x100)
-        pb->buf[i++] = (BYTE)(c >> 8);
-    pb->buf[i++] = (BYTE)c;
-#endif
-#else /* Write a character without conversion */
-    pb->buf[i++] = (BYTE)c;
-#endif
-
-    if (i >= (int)(sizeof pb->buf) - 3) { /* Write buffered characters to the file */
-        f_write(pb->fp, pb->buf, (UINT)i, &bw);
-        i = (bw == (UINT)i) ? 0 : -1;
-    }
-    pb->idx = i;
-    pb->nchr++;
-}
-
-int
-f_putc(TCHAR c, /* A character to be output */
-       FIL *fp  /* Pointer to the file object */
-       )
-{
-    putbuff pb;
-    UINT nw;
-
-    pb.fp = fp; /* Initialize output buffer */
-    pb.nchr = pb.idx = 0;
-
-    putc_bfd(&pb, c); /* Put a character */
-
-    if (pb.idx >= 0 /* Flush buffered characters to the file */
-        && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && (UINT)pb.idx == nw)
-        return pb.nchr;
-    return EOF;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Put a string to the file                                              */
-/*-----------------------------------------------------------------------*/
-
-int
-f_puts(const TCHAR *str, /* Pointer to the string to be output */
-       FIL *fp           /* Pointer to the file object */
-       )
-{
-    putbuff pb;
-    UINT nw;
-
-    pb.fp = fp; /* Initialize output buffer */
-    pb.nchr = pb.idx = 0;
-
-    while (*str) /* Put the string */
-        putc_bfd(&pb, *str++);
-
-    if (pb.idx >= 0 /* Flush buffered characters to the file */
-        && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && (UINT)pb.idx == nw)
-        return pb.nchr;
-    return EOF;
-}
-
-/*-----------------------------------------------------------------------*/
-/* Put a formatted string to the file                                    */
-/*-----------------------------------------------------------------------*/
-
-int
-f_printf(FIL *fp,          /* Pointer to the file object */
-         const TCHAR *fmt, /* Pointer to the format string */
-         ...               /* Optional arguments... */
-         )
-{
-    va_list arp;
-    BYTE f, r;
-    UINT nw, i, j, w;
-    DWORD v;
-    TCHAR c, d, s[16], *p;
-    putbuff pb;
-
-    pb.fp = fp; /* Initialize output buffer */
-    pb.nchr = pb.idx = 0;
-
-    va_start(arp, fmt);
-
-    for (;;) {
-        c = *fmt++;
-        if (c == 0)
-            break;      /* End of string */
-        if (c != '%') { /* Non escape character */
-            putc_bfd(&pb, c);
-            continue;
-        }
-        w = f = 0;
-        c = *fmt++;
-        if (c == '0') { /* Flag: '0' padding */
-            f = 1;
-            c = *fmt++;
-        } else {
-            if (c == '-') { /* Flag: left justified */
-                f = 2;
-                c = *fmt++;
-            }
-        }
-        while (IsDigit(c)) { /* Precision */
-            w = w * 10 + c - '0';
-            c = *fmt++;
-        }
-        if (c == 'l' || c == 'L') { /* Prefix: Size is long int */
-            f |= 4;
-            c = *fmt++;
-        }
-        if (!c)
-            break;
-        d = c;
-        if (IsLower(d))
-            d -= 0x20;
-        switch (d) {  /* Type is... */
-            case 'S': /* String */
-                p = va_arg(arp, TCHAR *);
-                for (j = 0; p[j]; j++)
-                    ;
-                if (!(f & 2)) {
-                    while (j++ < w)
-                        putc_bfd(&pb, ' ');
-                }
-                while (*p)
-                    putc_bfd(&pb, *p++);
-                while (j++ < w)
-                    putc_bfd(&pb, ' ');
-                continue;
-            case 'C': /* Character */
-                putc_bfd(&pb, (TCHAR)va_arg(arp, int));
-                continue;
-            case 'B': /* Binary */
-                r = 2;
-                break;
-            case 'O': /* Octal */
-                r = 8;
-                break;
-            case 'D': /* Signed decimal */
-            case 'U': /* Unsigned decimal */
-                r = 10;
-                break;
-            case 'X': /* Hexdecimal */
-                r = 16;
-                break;
-            default: /* Unknown type (pass-through) */
-                putc_bfd(&pb, c);
-                continue;
-        }
-
-        /* Get an argument and put it in numeral */
-        v = (f & 4) ? (DWORD)va_arg(arp, long) : ((d == 'D') ? (DWORD)(long)va_arg(arp, int) : (DWORD)va_arg(arp, unsigned int));
-        if (d == 'D' && (v & 0x80000000)) {
-            v = 0 - v;
-            f |= 8;
-        }
-        i = 0;
-        do {
-            d = (TCHAR)(v % r);
-            v /= r;
-            if (d > 9)
-                d += (c == 'x') ? 0x27 : 0x07;
-            s[i++] = d + '0';
-        } while (v && i < sizeof s / sizeof s[0]);
-        if (f & 8)
-            s[i++] = '-';
-        j = i;
-        d = (f & 1) ? '0' : ' ';
-        while (!(f & 2) && j++ < w)
-            putc_bfd(&pb, d);
-        do
-            putc_bfd(&pb, s[--i]);
-        while (i);
-        while (j++ < w)
-            putc_bfd(&pb, d);
-    }
-
-    va_end(arp);
-
-    if (pb.idx >= 0 /* Flush buffered characters to the file */
-        && f_write(pb.fp, pb.buf, (UINT)pb.idx, &nw) == FR_OK && (UINT)pb.idx == nw)
-        return pb.nchr;
-    return EOF;
-}
-
-#endif /* !_FS_READONLY */
-#endif /* _USE_STRFUNC */
diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h
deleted file mode 100644 (file)
index 3758f2f..0000000
+++ /dev/null
@@ -1,334 +0,0 @@
-/*---------------------------------------------------------------------------/
-/  FatFs - FAT file system module include R0.11     (C)ChaN, 2015
-/----------------------------------------------------------------------------/
-/ FatFs module is a free software that opened under license policy of
-/ following conditions.
-/
-/ Copyright (C) 2015, ChaN, all right reserved.
-/
-/ 1. Redistributions of source code must retain the above copyright notice,
-/    this condition and the following disclaimer.
-/
-/ This software is provided by the copyright holder and contributors "AS IS"
-/ and any warranties related to this software are DISCLAIMED.
-/ The copyright owner or contributors be NOT LIABLE for any damages caused
-/ by use of this software.
-/---------------------------------------------------------------------------*/
-
-#ifndef _FATFS
-#define _FATFS 32020 /* Revision ID */
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-#include "integer.h" /* Basic integer types */
-#include "ffconf.h"  /* FatFs configuration options */
-#if _FATFS != _FFCONF
-#error Wrong configuration file (ffconf.h).
-#endif
-
-/* Definitions of volume management */
-
-#if _MULTI_PARTITION /* Multiple partition configuration */
-typedef struct
-{
-    BYTE pd; /* Physical drive number */
-    BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
-} PARTITION;
-extern PARTITION VolToPart[];          /* Volume - Partition resolution table */
-#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
-#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
-
-#else                          /* Single partition configuration */
-#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
-#define LD2PT(vol) 0           /* Find first valid partition or in SFD */
-
-#endif
-
-/* Type of path name strings on FatFs API */
-
-#if _LFN_UNICODE /* Unicode string */
-#if !_USE_LFN
-#error _LFN_UNICODE must be 0 at non-LFN cfg.
-#endif
-#ifndef _INC_TCHAR
-typedef WCHAR TCHAR;
-#define _T(x) L##x
-#define _TEXT(x) L##x
-#endif
-
-#else /* ANSI/OEM string */
-#ifndef _INC_TCHAR
-typedef char TCHAR;
-#define _T(x) x
-#define _TEXT(x) x
-#endif
-
-#endif
-
-/* File system object structure (FATFS) */
-
-typedef struct
-{
-    BYTE fs_type;   /* FAT sub-type (0:Not mounted) */
-    BYTE drv;       /* Physical drive number */
-    BYTE csize;     /* Sectors per cluster (1,2,4...128) */
-    BYTE n_fats;    /* Number of FAT copies (1 or 2) */
-    BYTE wflag;     /* win[] flag (b0:dirty) */
-    BYTE fsi_flag;  /* FSINFO flags (b7:disabled, b0:dirty) */
-    WORD id;        /* File system mount ID */
-    WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
-#if _MAX_SS != _MIN_SS
-    WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
-#endif
-#if _FS_REENTRANT
-    _SYNC_t sobj; /* Identifier of sync object */
-#endif
-#if !_FS_READONLY
-    DWORD last_clust; /* Last allocated cluster */
-    DWORD free_clust; /* Number of free clusters */
-#endif
-#if _FS_RPATH
-    DWORD cdir; /* Current directory start cluster (0:root) */
-#endif
-    DWORD n_fatent;    /* Number of FAT entries, = number of clusters + 2 */
-    DWORD fsize;       /* Sectors per FAT */
-    DWORD volbase;     /* Volume start sector */
-    DWORD fatbase;     /* FAT start sector */
-    DWORD dirbase;     /* Root directory start sector (FAT32:Cluster#) */
-    DWORD database;    /* Data start sector */
-    DWORD winsect;     /* Current sector appearing in the win[] */
-    BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
-} FATFS;
-
-/* File object structure (FIL) */
-
-typedef struct
-{
-    FATFS *fs;    /* Pointer to the related file system object (**do not change order**) */
-    WORD id;      /* Owner file system mount ID (**do not change order**) */
-    BYTE flag;    /* Status flags */
-    BYTE err;     /* Abort flag (error code) */
-    DWORD fptr;   /* File read/write pointer (Zeroed on file open) */
-    DWORD fsize;  /* File size */
-    DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
-    DWORD clust;  /* Current cluster of fpter (not valid when fprt is 0) */
-    DWORD dsect;  /* Sector number appearing in buf[] (0:invalid) */
-#if !_FS_READONLY
-    DWORD dir_sect; /* Sector number containing the directory entry */
-    BYTE *dir_ptr;  /* Pointer to the directory entry in the win[] */
-#endif
-#if _USE_FASTSEEK
-    DWORD *cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
-#endif
-#if _FS_LOCK
-    UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
-#endif
-#if !_FS_TINY
-    BYTE buf[_MAX_SS]; /* File private data read/write window */
-#endif
-} FIL;
-
-/* Directory object structure (DIR) */
-
-typedef struct
-{
-    FATFS *fs;    /* Pointer to the owner file system object (**do not change order**) */
-    WORD id;      /* Owner file system mount ID (**do not change order**) */
-    WORD index;   /* Current read/write index number */
-    DWORD sclust; /* Table start cluster (0:Root dir) */
-    DWORD clust;  /* Current cluster */
-    DWORD sect;   /* Current sector */
-    BYTE *dir;    /* Pointer to the current SFN entry in the win[] */
-    BYTE *fn;     /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
-#if _FS_LOCK
-    UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
-#endif
-#if _USE_LFN
-    WCHAR *lfn;   /* Pointer to the LFN working buffer */
-    WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
-#endif
-#if _USE_FIND
-    const TCHAR *pat; /* Pointer to the name matching pattern */
-#endif
-} DIR;
-
-/* File information structure (FILINFO) */
-
-typedef struct
-{
-    DWORD fsize;     /* File size */
-    WORD fdate;      /* Last modified date */
-    WORD ftime;      /* Last modified time */
-    BYTE fattrib;    /* Attribute */
-    TCHAR fname[13]; /* Short file name (8.3 format) */
-#if _USE_LFN
-    TCHAR *lfname; /* Pointer to the LFN buffer */
-    UINT lfsize;   /* Size of LFN buffer in TCHAR */
-#endif
-} FILINFO;
-
-/* File function return code (FRESULT) */
-
-typedef enum {
-    FR_OK = 0,              /* (0) Succeeded */
-    FR_DISK_ERR,            /* (1) A hard error occurred in the low level disk I/O layer */
-    FR_INT_ERR,             /* (2) Assertion failed */
-    FR_NOT_READY,           /* (3) The physical drive cannot work */
-    FR_NO_FILE,             /* (4) Could not find the file */
-    FR_NO_PATH,             /* (5) Could not find the path */
-    FR_INVALID_NAME,        /* (6) The path name format is invalid */
-    FR_DENIED,              /* (7) Access denied due to prohibited access or directory full */
-    FR_EXIST,               /* (8) Access denied due to prohibited access */
-    FR_INVALID_OBJECT,      /* (9) The file/directory object is invalid */
-    FR_WRITE_PROTECTED,     /* (10) The physical drive is write protected */
-    FR_INVALID_DRIVE,       /* (11) The logical drive number is invalid */
-    FR_NOT_ENABLED,         /* (12) The volume has no work area */
-    FR_NO_FILESYSTEM,       /* (13) There is no valid FAT volume */
-    FR_MKFS_ABORTED,        /* (14) The f_mkfs() aborted due to any parameter error */
-    FR_TIMEOUT,             /* (15) Could not get a grant to access the volume within defined period */
-    FR_LOCKED,              /* (16) The operation is rejected according to the file sharing policy */
-    FR_NOT_ENOUGH_CORE,     /* (17) LFN working buffer could not be allocated */
-    FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
-    FR_INVALID_PARAMETER    /* (19) Given parameter is invalid */
-} FRESULT;
-
-/*--------------------------------------------------------------*/
-/* FatFs module application interface                           */
-
-FRESULT f_open(FIL *fp, const TCHAR *path, BYTE mode);                               /* Open or create a file */
-FRESULT f_close(FIL *fp);                                                            /* Close an open file object */
-FRESULT f_read(FIL *fp, void *buff, UINT btr, UINT *br);                             /* Read data from a file */
-FRESULT f_write(FIL *fp, const void *buff, UINT btw, UINT *bw);                      /* Write data to a file */
-FRESULT f_forward(FIL *fp, UINT (*func)(const BYTE *, UINT), UINT btf, UINT *bf);    /* Forward data to the stream */
-FRESULT f_lseek(FIL *fp, DWORD ofs);                                                 /* Move file pointer of a file object */
-FRESULT f_truncate(FIL *fp);                                                         /* Truncate file */
-FRESULT f_sync(FIL *fp);                                                             /* Flush cached data of a writing file */
-FRESULT f_opendir(DIR *dp, const TCHAR *path);                                       /* Open a directory */
-FRESULT f_closedir(DIR *dp);                                                         /* Close an open directory */
-FRESULT f_readdir(DIR *dp, FILINFO *fno);                                            /* Read a directory item */
-FRESULT f_findfirst(DIR *dp, FILINFO *fno, const TCHAR *path, const TCHAR *pattern); /* Find first file */
-FRESULT f_findnext(DIR *dp, FILINFO *fno);                                           /* Find next file */
-FRESULT f_mkdir(const TCHAR *path);                                                  /* Create a sub directory */
-FRESULT f_unlink(const TCHAR *path);                                                 /* Delete an existing file or directory */
-FRESULT f_rename(const TCHAR *path_old, const TCHAR *path_new);                      /* Rename/Move a file or directory */
-FRESULT f_stat(const TCHAR *path, FILINFO *fno);                                     /* Get file status */
-FRESULT f_chmod(const TCHAR *path, BYTE attr, BYTE mask);                            /* Change attribute of the file/dir */
-FRESULT f_utime(const TCHAR *path, const FILINFO *fno);                              /* Change times-tamp of the file/dir */
-FRESULT f_chdir(const TCHAR *path);                                                  /* Change current directory */
-FRESULT f_chdrive(const TCHAR *path);                                                /* Change current drive */
-FRESULT f_getcwd(TCHAR *buff, UINT len);                                             /* Get current directory */
-FRESULT f_getfree(const TCHAR *path, DWORD *nclst, FATFS **fatfs);                   /* Get number of free clusters on the drive */
-FRESULT f_getlabel(const TCHAR *path, TCHAR *label, DWORD *vsn);                     /* Get volume label */
-FRESULT f_setlabel(const TCHAR *label);                                              /* Set volume label */
-FRESULT f_mount(FATFS *fs, const TCHAR *path, BYTE opt);                             /* Mount/Unmount a logical drive */
-FRESULT f_mkfs(const TCHAR *path, BYTE sfd, UINT au);                                /* Create a file system on the volume */
-FRESULT f_fdisk(BYTE pdrv, const DWORD szt[], void *work);                           /* Divide a physical drive into some partitions */
-FRESULT f_getsector(FIL *fp, UINT *sec);
-int f_putc(TCHAR c, FIL *fp);                 /* Put a character to the file */
-int f_puts(const TCHAR *str, FIL *cp);        /* Put a string to the file */
-int f_printf(FIL *fp, const TCHAR *str, ...); /* Put a formatted string to the file */
-TCHAR *f_gets(TCHAR *buff, int len, FIL *fp); /* Get a string from the file */
-
-#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
-#define f_error(fp) ((fp)->err)
-#define f_tell(fp) ((fp)->fptr)
-#define f_size(fp) ((fp)->fsize)
-#define f_rewind(fp) f_lseek((fp), 0)
-#define f_rewinddir(dp) f_readdir((dp), 0)
-
-#ifndef EOF
-#define EOF (-1)
-#endif
-
-/*--------------------------------------------------------------*/
-/* Additional user defined functions                            */
-
-/* RTC function */
-#if !_FS_READONLY && !_FS_NORTC
-DWORD get_fattime(void);
-#endif
-
-/* Unicode support functions */
-#if _USE_LFN                           /* Unicode - OEM code conversion */
-WCHAR ff_convert(WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
-WCHAR ff_wtoupper(WCHAR chr);          /* Unicode upper-case conversion */
-#if _USE_LFN == 3                      /* Memory functions */
-void *ff_memalloc(UINT msize);         /* Allocate memory block */
-void ff_memfree(void *mblock);         /* Free memory block */
-#endif
-#endif
-
-/* Sync functions */
-#if _FS_REENTRANT
-int ff_cre_syncobj(BYTE vol, _SYNC_t *sobj); /* Create a sync object */
-int ff_req_grant(_SYNC_t sobj);              /* Lock sync object */
-void ff_rel_grant(_SYNC_t sobj);             /* Unlock sync object */
-int ff_del_syncobj(_SYNC_t sobj);            /* Delete a sync object */
-#endif
-
-/*--------------------------------------------------------------*/
-/* Flags and offset address                                     */
-
-/* File access control and file status flags (FIL.flag) */
-
-#define FA_READ 0x01
-#define FA_OPEN_EXISTING 0x00
-
-#if !_FS_READONLY
-#define FA_WRITE 0x02
-#define FA_CREATE_NEW 0x04
-#define FA_CREATE_ALWAYS 0x08
-#define FA_OPEN_ALWAYS 0x10
-#define FA__WRITTEN 0x20
-#define FA__DIRTY 0x40
-#endif
-
-/* FAT sub type (FATFS.fs_type) */
-
-#define FS_FAT12 1
-#define FS_FAT16 2
-#define FS_FAT32 3
-
-/* File attribute bits for directory entry */
-
-#define AM_RDO 0x01  /* Read only */
-#define AM_HID 0x02  /* Hidden */
-#define AM_SYS 0x04  /* System */
-#define AM_VOL 0x08  /* Volume label */
-#define AM_LFN 0x0F  /* LFN entry */
-#define AM_DIR 0x10  /* Directory */
-#define AM_ARC 0x20  /* Archive */
-#define AM_MASK 0x3F /* Mask of defined bits */
-
-/* Fast seek feature */
-#define CREATE_LINKMAP 0xFFFFFFFF
-
-/*--------------------------------*/
-/* Multi-byte word access macros  */
-
-#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
-#define LD_WORD(ptr) (WORD)(*(WORD *)(BYTE *)(ptr))
-#define LD_DWORD(ptr) (DWORD)(*(DWORD *)(BYTE *)(ptr))
-#define ST_WORD(ptr, val) *(WORD *)(BYTE *)(ptr) = (WORD)(val)
-#define ST_DWORD(ptr, val) *(DWORD *)(BYTE *)(ptr) = (DWORD)(val)
-#else /* Use byte-by-byte access to the FAT structure */
-#define LD_WORD(ptr) (WORD)(((WORD) * ((BYTE *)(ptr) + 1) << 8) | (WORD) * (BYTE *)(ptr))
-#define LD_DWORD(ptr)                                                                                                                                          \
-    (DWORD)(((DWORD) * ((BYTE *)(ptr) + 3) << 24) | ((DWORD) * ((BYTE *)(ptr) + 2) << 16) | ((WORD) * ((BYTE *)(ptr) + 1) << 8) | *(BYTE *)(ptr))
-#define ST_WORD(ptr, val)                                                                                                                                      \
-    *(BYTE *)(ptr) = (BYTE)(val);                                                                                                                              \
-    *((BYTE *)(ptr) + 1) = (BYTE)((WORD)(val) >> 8)
-#define ST_DWORD(ptr, val)                                                                                                                                     \
-    *(BYTE *)(ptr) = (BYTE)(val);                                                                                                                              \
-    *((BYTE *)(ptr) + 1) = (BYTE)((WORD)(val) >> 8);                                                                                                           \
-    *((BYTE *)(ptr) + 2) = (BYTE)((DWORD)(val) >> 16);                                                                                                         \
-    *((BYTE *)(ptr) + 3) = (BYTE)((DWORD)(val) >> 24)
-#endif
-
-#ifdef __cplusplus
-}
-#endif
-
-#endif /* _FATFS */
diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h
deleted file mode 100644 (file)
index 158cbd4..0000000
+++ /dev/null
@@ -1,246 +0,0 @@
-/*---------------------------------------------------------------------------/
-/  FatFs - FAT file system module configuration file  R0.11 (C)ChaN, 2015
-/---------------------------------------------------------------------------*/
-
-#define _FFCONF 32020 /* Revision ID */
-
-/*---------------------------------------------------------------------------/
-/ Functions and Buffer Configurations
-/---------------------------------------------------------------------------*/
-
-#define _FS_TINY 0
-/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
-/  At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
-/  bytes. Instead of private sector buffer eliminated from the file object,
-/  common sector buffer in the file system object (FATFS) is used for the file
-/  data transfer. */
-
-#define _FS_READONLY 0
-/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
-/  Read-only configuration removes writing API functions, f_write(), f_sync(),
-/  f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
-/  and optional writing functions as well. */
-
-#define _FS_MINIMIZE 0
-/* This option defines minimization level to remove some basic API functions.
-/
-/   0: All basic functions are enabled.
-/   1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
-/      f_truncate() and f_rename() function are removed.
-/   2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
-/   3: f_lseek() function is removed in addition to 2. */
-
-#define _USE_STRFUNC 0
-/* This option switches string functions, f_gets(), f_putc(), f_puts() and
-/  f_printf().
-/
-/  0: Disable string functions.
-/  1: Enable without LF-CRLF conversion.
-/  2: Enable with LF-CRLF conversion. */
-
-#define _USE_FIND 0
-/* This option switches filtered directory read feature and related functions,
-/  f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
-
-#define _USE_MKFS 1
-/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
-
-#define _USE_FASTSEEK 0
-/* This option switches fast seek feature. (0:Disable or 1:Enable) */
-
-#define _USE_LABEL 0
-/* This option switches volume label functions, f_getlabel() and f_setlabel().
-/  (0:Disable or 1:Enable) */
-
-#define _USE_FORWARD 0
-/* This option switches f_forward() function. (0:Disable or 1:Enable)
-/  To enable it, also _FS_TINY need to be set to 1. */
-
-/*---------------------------------------------------------------------------/
-/ Locale and Namespace Configurations
-/---------------------------------------------------------------------------*/
-
-#define _CODE_PAGE 437
-/* This option specifies the OEM code page to be used on the target system.
-/  Incorrect setting of the code page can cause a file open failure.
-/
-/   1    - ASCII (No extended character. Non-LFN cfg. only)
-/   437  - U.S.
-/   720  - Arabic
-/   737  - Greek
-/   775  - Baltic
-/   850  - Multilingual Latin 1
-/   852  - Latin 2
-/   855  - Cyrillic
-/   857  - Turkish
-/   858  - Multilingual Latin 1 + Euro
-/   862  - Hebrew
-/   866  - Russian
-/   874  - Thai
-/   932  - Japanese Shift_JIS (DBCS)
-/   936  - Simplified Chinese GBK (DBCS)
-/   949  - Korean (DBCS)
-/   950  - Traditional Chinese Big5 (DBCS)
-*/
-
-#define _USE_LFN 2
-#define _MAX_LFN 255
-/* The _USE_LFN option switches the LFN feature.
-/
-/   0: Disable LFN feature. _MAX_LFN has no effect.
-/   1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
-/   2: Enable LFN with dynamic working buffer on the STACK.
-/   3: Enable LFN with dynamic working buffer on the HEAP.
-/
-/  When enable the LFN feature, Unicode handling functions (option/unicode.c) must
-/  be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
-/  When use stack for the working buffer, take care on stack overflow. When use heap
-/  memory for the working buffer, memory management functions, ff_memalloc() and
-/  ff_memfree(), must be added to the project. */
-
-#define _LFN_UNICODE 0
-/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
-/  To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
-/  to 1. This option also affects behavior of string I/O functions. */
-
-#define _STRF_ENCODE 0
-/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
-/  be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
-/
-/  0: ANSI/OEM
-/  1: UTF-16LE
-/  2: UTF-16BE
-/  3: UTF-8
-/
-/  When _LFN_UNICODE is 0, this option has no effect. */
-
-#define _FS_RPATH 0
-/* This option configures relative path feature.
-/
-/   0: Disable relative path feature and remove related functions.
-/   1: Enable relative path feature. f_chdir() and f_chdrive() are available.
-/   2: f_getcwd() function is available in addition to 1.
-/
-/  Note that directory items read via f_readdir() are affected by this option. */
-
-/*---------------------------------------------------------------------------/
-/ Drive/Volume Configurations
-/---------------------------------------------------------------------------*/
-
-#define _VOLUMES 10
-/* Number of volumes (logical drives) to be used. */
-
-#define _STR_VOLUME_ID 0
-#define _VOLUME_STRS "sdcard", "sysnand", "systwln", "systwlp", "emunand", "emutwln", "emutwlp", "imgnand", "imgtwln", "imgtwlp"
-/* _STR_VOLUME_ID option switches string volume ID feature.
-/  When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
-/  number in the path name. _VOLUME_STRS defines the drive ID strings for each
-/  logical drives. Number of items must be equal to _VOLUMES. Valid characters for
-/  the drive ID strings are: A-Z and 0-9. */
-
-#define _MULTI_PARTITION 0
-/* This option switches multi-partition feature. By default (0), each logical drive
-/  number is bound to the same physical drive number and only an FAT volume found on
-/  the physical drive will be mounted. When multi-partition feature is enabled (1),
-/  each logical drive number is bound to arbitrary physical drive and partition
-/  listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
-
-#define _MIN_SS 512
-#define _MAX_SS 512
-/* These options configure the range of sector size to be supported. (512, 1024,
-/  2048 or 4096) Always set both 512 for most systems, all type of memory cards and
-/  harddisk. But a larger value may be required for on-board flash memory and some
-/  type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
-/  to variable sector size and GET_SECTOR_SIZE command must be implemented to the
-/  disk_ioctl() function. */
-
-#define _USE_TRIM 0
-/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
-/  To enable Trim feature, also CTRL_TRIM command should be implemented to the
-/  disk_ioctl() function. */
-
-#define _FS_NOFSINFO 0
-/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
-/  option, and f_getfree() function at first time after volume mount will force
-/  a full FAT scan. Bit 1 controls the use of last allocated cluster number.
-/
-/  bit0=0: Use free cluster count in the FSINFO if available.
-/  bit0=1: Do not trust free cluster count in the FSINFO.
-/  bit1=0: Use last allocated cluster number in the FSINFO if available.
-/  bit1=1: Do not trust last allocated cluster number in the FSINFO.
-*/
-
-/*---------------------------------------------------------------------------/
-/ System Configurations
-/---------------------------------------------------------------------------*/
-
-#define _FS_NORTC 1
-#define _NORTC_MON 2
-#define _NORTC_MDAY 1
-#define _NORTC_YEAR 2015
-/* The _FS_NORTC option switches timestamp feature. If the system does not have
-/  an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
-/  the timestamp feature. All objects modified by FatFs will have a fixed timestamp
-/  defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
-/  When timestamp feature is enabled (_FS_NORTC    == 0), get_fattime() function need
-/  to be added to the project to read current time form RTC. _NORTC_MON,
-/  _NORTC_MDAY and _NORTC_YEAR have no effect.
-/  These options have no effect at read-only configuration (_FS_READONLY == 1). */
-
-#define _FS_LOCK 0
-/* The _FS_LOCK option switches file lock feature to control duplicated file open
-/  and illegal operation to open objects. This option must be 0 when _FS_READONLY
-/  is 1.
-/
-/  0:  Disable file lock feature. To avoid volume corruption, application program
-/      should avoid illegal open, remove and rename to the open objects.
-/  >0: Enable file lock feature. The value defines how many files/sub-directories
-/      can be opened simultaneously under file lock control. Note that the file
-/      lock feature is independent of re-entrancy. */
-
-#define _FS_REENTRANT 0
-#define _FS_TIMEOUT 1000
-#define _SYNC_t HANDLE
-/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
-/  module itself. Note that regardless of this option, file access to different
-/  volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
-/  and f_fdisk() function, are always not re-entrant. Only file/directory access
-/  to the same volume is under control of this feature.
-/
-/   0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
-/   1: Enable re-entrancy. Also user provided synchronization handlers,
-/      ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
-/      function, must be added to the project. Samples are available in
-/      option/syscall.c.
-/
-/  The _FS_TIMEOUT defines timeout period in unit of time tick.
-/  The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
-/  SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
-/  included somewhere in the scope of ff.c. */
-
-#define _WORD_ACCESS 0
-/* The _WORD_ACCESS option is an only platform dependent option. It defines
-/  which access method is used to the word data on the FAT volume.
-/
-/   0: Byte-by-byte access. Always compatible with all platforms.
-/   1: Word access. Do not choose this unless under both the following conditions.
-/
-/  * Address misaligned memory access is always allowed to ALL instructions.
-/  * Byte order on the memory is little-endian.
-/
-/  If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
-/  Following table shows allowable settings of some processor types.
-/
-/  ARM7TDMI   0   *2          ColdFire   0    *1         V850E      0    *2
-/  Cortex-M3  0   *3          Z80        0/1             V850ES     0/1
-/  Cortex-M0  0   *2          x86        0/1             TLCS-870   0/1
-/  AVR        0/1             RX600(LE)  0/1             TLCS-900   0/1
-/  AVR32      0   *1          RL78       0    *2         R32C       0    *2
-/  PIC18      0/1             SH-2       0    *1         M16C       0/1
-/  PIC24      0   *2          H8S        0    *1         MSP430     0    *2
-/  PIC32      0   *1          H8/300H    0    *1         8051       0/1
-/
-/  *1:Big-endian.
-/  *2:Unaligned memory access is not supported.
-/  *3:Some compilers generate LDM/STM for mem_cpy function.
-*/
diff --git a/source/fatfs/history.txt b/source/fatfs/history.txt
deleted file mode 100644 (file)
index b101820..0000000
+++ /dev/null
@@ -1,180 +0,0 @@
-----------------------------------------------------------------------------
-  Revision history of FatFs module
-----------------------------------------------------------------------------
-
-R0.00 (February 26, 2006)
-  Prototype.
-
-
-R0.01 (April 29, 2006)
-  First stable version.
-
-
-R0.02 (June 01, 2006)
-  Added FAT12 support.
-  Removed unbuffered mode.
-  Fixed a problem on small (<32M) partition.
-
-
-R0.02a (June 10, 2006)
-  Added a configuration option (_FS_MINIMUM).
-
-
-R0.03 (September 22, 2006)
-  Added f_rename().
-  Changed option _FS_MINIMUM to _FS_MINIMIZE.
-
-
-R0.03a (December 11, 2006)
-  Improved cluster scan algorithm to write files fast.
-  Fixed f_mkdir() creates incorrect directory on FAT32.
-
-
-R0.04 (February 04, 2007)
-  Added f_mkfs().
-  Supported multiple drive system.
-  Changed some interfaces for multiple drive system.
-  Changed f_mountdrv() to f_mount().
-
-
-R0.04a (April 01, 2007)
-  Supported multiple partitions on a physical drive.
-  Added a capability of extending file size to f_lseek().
-  Added minimization level 3.
-  Fixed an endian sensitive code in f_mkfs().
-
-
-R0.04b (May 05, 2007)
-  Added a configuration option _USE_NTFLAG.
-  Added FSINFO support.
-  Fixed DBCS name can result FR_INVALID_NAME.
-  Fixed short seek (<= csize) collapses the file object.
-
-
-R0.05 (August 25, 2007)
-  Changed arguments of f_read(), f_write() and f_mkfs().
-  Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
-  Fixed f_mkdir() on FAT32 creates incorrect directory.
-
-
-R0.05a (February 03, 2008)
-  Added f_truncate() and f_utime().
-  Fixed off by one error at FAT sub-type determination.
-  Fixed btr in f_read() can be mistruncated.
-  Fixed cached sector is not flushed when create and close without write.
-
-
-R0.06 (April 01, 2008)
-  Added fputc(), fputs(), fprintf() and fgets().
-  Improved performance of f_lseek() on moving to the same or following cluster.
-
-
-R0.07 (April 01, 2009)
-  Merged Tiny-FatFs as a configuration option. (_FS_TINY)
-  Added long file name feature. (_USE_LFN)
-  Added multiple code page feature. (_CODE_PAGE)
-  Added re-entrancy for multitask operation. (_FS_REENTRANT)
-  Added auto cluster size selection to f_mkfs().
-  Added rewind option to f_readdir().
-  Changed result code of critical errors.
-  Renamed string functions to avoid name collision.
-
-
-R0.07a (April 14, 2009)
-  Septemberarated out OS dependent code on reentrant cfg.
-  Added multiple sector size feature.
-
-
-R0.07c (June 21, 2009)
-  Fixed f_unlink() can return FR_OK on error.
-  Fixed wrong cache control in f_lseek().
-  Added relative path feature.
-  Added f_chdir() and f_chdrive().
-  Added proper case conversion to extended character.
-
-
-R0.07e (November 03, 2009)
-  Septemberarated out configuration options from ff.h to ffconf.h.
-  Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
-  Fixed name matching error on the 13 character boundary.
-  Added a configuration option, _LFN_UNICODE.
-  Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
-
-
-R0.08 (May 15, 2010)
-  Added a memory configuration option. (_USE_LFN = 3)
-  Added file lock feature. (_FS_SHARE)
-  Added fast seek feature. (_USE_FASTSEEK)
-  Changed some types on the API, XCHAR->TCHAR.
-  Changed .fname in the FILINFO structure on Unicode cfg.
-  String functions support UTF-8 encoding files on Unicode cfg.
-
-
-R0.08a (August 16, 2010)
-  Added f_getcwd(). (_FS_RPATH = 2)
-  Added sector erase feature. (_USE_ERASE)
-  Moved file lock semaphore table from fs object to the bss.
-  Fixed f_mkfs() creates wrong FAT32 volume.
-
-
-R0.08b (January 15, 2011)
-  Fast seek feature is also applied to f_read() and f_write().
-  f_lseek() reports required table size on creating CLMP.
-  Extended format syntax of f_printf().
-  Ignores duplicated directory separators in given path name.
-
-
-R0.09 (September 06, 2011)
-  f_mkfs() supports multiple partition to complete the multiple partition feature.
-  Added f_fdisk().
-
-
-R0.09a (August 27, 2012)
-  Changed f_open() and f_opendir() reject null object pointer to avoid crash.
-  Changed option name _FS_SHARE to _FS_LOCK.
-  Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
-
-
-R0.09b (January 24, 2013)
-  Added f_setlabel() and f_getlabel().
-
-
-R0.10 (October 02, 2013)
-  Added selection of character encoding on the file. (_STRF_ENCODE)
-  Added f_closedir().
-  Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
-  Added forced mount feature with changes of f_mount().
-  Improved behavior of volume auto detection.
-  Improved write throughput of f_puts() and f_printf().
-  Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
-  Fixed f_write() can be truncated when the file size is close to 4GB.
-  Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
-
-
-R0.10a (January 15, 2014)
-  Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
-  Added a configuration option of minimum sector size. (_MIN_SS)
-  2nd argument of f_rename() can have a drive number and it will be ignored.
-  Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
-  Fixed f_close() invalidates the file object without volume lock.
-  Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
-  Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
-
-
-R0.10b (May 19, 2014)
-  Fixed a hard error in the disk I/O layer can collapse the directory entry.
-  Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
-
-
-R0.10c (November 09, 2014)
-  Added a configuration option for the platforms without RTC. (_FS_NORTC)
-  Changed option name _USE_ERASE to _USE_TRIM.
-  Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
-  Fixed a potential problem of FAT access that can appear on disk error.
-  Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
-
-
-R0.11 (February 09, 2015)
-  Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
-  Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
-  Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
diff --git a/source/fatfs/integer.h b/source/fatfs/integer.h
deleted file mode 100644 (file)
index 1bfa223..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*-------------------------------------------*/
-/* Integer type definitions for FatFs module */
-/*-------------------------------------------*/
-
-#ifndef _FF_INTEGER
-#define _FF_INTEGER
-
-#ifdef _WIN32 /* FatFs development platform */
-
-#include <windows.h>
-#include <tchar.h>
-
-#else /* Embedded platform */
-
-/* This type MUST be 8 bit */
-typedef unsigned char BYTE;
-
-/* These types MUST be 16 bit */
-typedef short SHORT;
-typedef unsigned short WORD;
-typedef unsigned short WCHAR;
-
-/* These types MUST be 16 bit or 32 bit */
-typedef int INT;
-typedef unsigned int UINT;
-
-/* These types MUST be 32 bit */
-typedef long LONG;
-typedef unsigned long DWORD;
-
-#endif
-
-#endif
diff --git a/source/fatfs/sdmmc.c b/source/fatfs/sdmmc.c
deleted file mode 100644 (file)
index 8415180..0000000
+++ /dev/null
@@ -1,667 +0,0 @@
-/*
- * This Source Code Form is subject to the terms of the Mozilla Public
- * License, v. 2.0. If a copy of the MPL was not distributed with this file,
- * You can obtain one at http://mozilla.org/MPL/2.0/.
- *
- * Copyright (c) 2014, Normmatt
- *
- * Alternatively, the contents of this file may be used under the terms
- * of the GNU General Public License Version 2, as described below:
- *
- * This file is free software: you may copy, redistribute and/or modify
- * it under the terms of the GNU General Public License as published by the
- * Free Software Foundation, either version 2 of the License, or (at your
- * option) any later version.
- *
- * This file is distributed in the hope that it will be useful, but
- * WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
- * Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program. If not, see http://www.gnu.org/licenses/.
- */
-
-// LEGAL - Note that despite the above notice, it must be used under
-// MPL 2.0 here. GPLv2 and GPLv3 are not compatible, and his software
-// delcares specifically GPLv2. We have to treat it as MPL 2.0 to
-// not violate any licensing.
-
-#include <stdint.h>
-#include <stddef.h>
-#include <inttypes.h>
-
-#include "sdmmc.h"
-//#include "DrawCharacter.h"
-
-// Uncomment to enable 32bit fifo support?
-// not currently working
-//#define DATA32_SUPPORT
-
-#define TRUE 1
-#define FALSE 0
-
-#define bool int
-
-#define NO_INLINE __attribute__((noinline))
-
-#define RGB(r, g, b) (r << 24 | b << 16 | g << 8 | r)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-void waitcycles(uint32_t val);
-#ifdef __cplusplus
-};
-#endif
-
-//#define DEBUG_SDMMC
-
-#ifdef DEBUG_SDMMC
-extern uint8_t *topScreen;
-extern void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor);
-#define DEBUGPRINT(scr, str, hex, x, y, color, bg) DrawHexWithName(scr, str, hex, x, y, color, bg)
-#else
-#define DEBUGPRINT(...)
-#endif
-
-// extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args);
-// extern "C" void inittarget(struct mmcdevice *ctx);
-// extern "C" int SD_Init();
-// extern "C" int SD_Init2();
-// extern "C" int Nand_Init2();
-// extern "C" void InitSD();
-
-struct mmcdevice handelNAND;
-struct mmcdevice handelSD;
-
-mmcdevice *
-getMMCDevice(int drive)
-{
-    if (drive == 0)
-        return &handelNAND;
-    return &handelSD;
-}
-
-int
-geterror(struct mmcdevice *ctx)
-{
-    return (ctx->error << 29) >> 31;
-}
-
-void
-inittarget(struct mmcdevice *ctx)
-{
-    sdmmc_mask16(REG_SDPORTSEL, 0x3, (uint16_t)ctx->devicenumber);
-    setckl(ctx->clk);
-    if (ctx->SDOPT == 0) {
-        sdmmc_mask16(REG_SDOPT, 0, 0x8000);
-    } else {
-        sdmmc_mask16(REG_SDOPT, 0x8000, 0);
-    }
-}
-
-void NO_INLINE
-sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args)
-{
-    bool getSDRESP = (cmd << 15) >> 31;
-    uint16_t flags = (cmd << 15) >> 31;
-    const bool readdata = cmd & 0x20000;
-    const bool writedata = cmd & 0x40000;
-
-    if (readdata || writedata) {
-        flags |= TMIO_STAT0_DATAEND;
-    }
-
-    ctx->error = 0;
-    while ((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY))
-        ; // mmc working?
-    sdmmc_write16(REG_SDIRMASK0, 0);
-    sdmmc_write16(REG_SDIRMASK1, 0);
-    sdmmc_write16(REG_SDSTATUS0, 0);
-    sdmmc_write16(REG_SDSTATUS1, 0);
-#ifdef DATA32_SUPPORT
-//    if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800);
-//    if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000);
-//    sdmmc_mask16(REG_DATACTL32,0x1800,2);
-#else
-    sdmmc_mask16(REG_DATACTL32, 0x1800, 0);
-#endif
-    sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF);
-    sdmmc_write16(REG_SDCMDARG1, args >> 16);
-    sdmmc_write16(REG_SDCMD, cmd & 0xFFFF);
-
-    uint32_t size = ctx->size;
-    uint16_t *dataPtr = (uint16_t *)ctx->data;
-#ifdef DATA32_SUPPORT
-    uint32_t *dataPtr32 = (uint32_t *)ctx->data;
-#endif
-
-    bool useBuf = (NULL != dataPtr);
-#ifdef DATA32_SUPPORT
-    bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr))));
-#endif
-
-    uint16_t status0 = 0;
-    while (1) {
-        volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1);
-#ifdef DATA32_SUPPORT
-        volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32);
-        if ((ctl32 & 0x100))
-#else
-        if ((status1 & TMIO_STAT1_RXRDY))
-#endif
-        {
-            if (readdata) {
-                if (useBuf) {
-                    sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
-                    // sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
-                    if (size > 0x1FF) {
-#ifdef DATA32_SUPPORT
-                        if (useBuf32) {
-                            for (int i = 0; i < 0x200; i += 4) {
-                                *dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
-                            }
-                        } else {
-#endif
-                            for (int i = 0; i < 0x200; i += 2) {
-                                *dataPtr++ = sdmmc_read16(REG_SDFIFO);
-                            }
-#ifdef DATA32_SUPPORT
-                        }
-#endif
-                        size -= 0x200;
-                    }
-                }
-
-                sdmmc_mask16(REG_DATACTL32, 0x800, 0);
-            }
-        }
-#ifdef DATA32_SUPPORT
-        if (!(ctl32 & 0x200))
-#else
-        if ((status1 & TMIO_STAT1_TXRQ))
-#endif
-        {
-            if (writedata) {
-                if (useBuf) {
-                    sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
-                    // sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
-                    if (size > 0x1FF) {
-#ifdef DATA32_SUPPORT
-                        for (int i = 0; i < 0x200; i += 4) {
-                            sdmmc_write32(REG_SDFIFO32, *dataPtr32++);
-                        }
-#else
-                        for (int i = 0; i < 0x200; i += 2) {
-                            sdmmc_write16(REG_SDFIFO, *dataPtr++);
-                        }
-#endif
-                        size -= 0x200;
-                    }
-                }
-
-                sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
-            }
-        }
-        if (status1 & TMIO_MASK_GW) {
-            ctx->error |= 4;
-            break;
-        }
-
-        if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
-            status0 = sdmmc_read16(REG_SDSTATUS0);
-            if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND) {
-                ctx->error |= 0x1;
-            }
-            if (status0 & TMIO_STAT0_DATAEND) {
-                ctx->error |= 0x2;
-            }
-
-            if ((status0 & flags) == flags)
-                break;
-        }
-    }
-    ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
-    ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
-    sdmmc_write16(REG_SDSTATUS0, 0);
-    sdmmc_write16(REG_SDSTATUS1, 0);
-
-    if (getSDRESP != 0) {
-        ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
-        ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
-        ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
-        ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16);
-    }
-}
-
-int NO_INLINE
-sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in)
-{
-    if (handelSD.isSDHC == 0)
-        sector_no <<= 9;
-    inittarget(&handelSD);
-    sdmmc_write16(REG_SDSTOP, 0x100);
-#ifdef DATA32_SUPPORT
-    sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
-    sdmmc_write16(REG_SDBLKLEN32, 0x200);
-#endif
-    sdmmc_write16(REG_SDBLKCOUNT, numsectors);
-    handelSD.data = in;
-    handelSD.size = numsectors << 9;
-    sdmmc_send_command(&handelSD, 0x52C19, sector_no);
-    return geterror(&handelSD);
-}
-
-int NO_INLINE
-sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
-{
-    if (handelSD.isSDHC == 0)
-        sector_no <<= 9;
-    inittarget(&handelSD);
-    sdmmc_write16(REG_SDSTOP, 0x100);
-#ifdef DATA32_SUPPORT
-    sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
-    sdmmc_write16(REG_SDBLKLEN32, 0x200);
-#endif
-    sdmmc_write16(REG_SDBLKCOUNT, numsectors);
-    handelSD.data = out;
-    handelSD.size = numsectors << 9;
-    sdmmc_send_command(&handelSD, 0x33C12, sector_no);
-    return geterror(&handelSD);
-}
-
-int NO_INLINE
-sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
-{
-    if (handelNAND.isSDHC == 0)
-        sector_no <<= 9;
-    inittarget(&handelNAND);
-    sdmmc_write16(REG_SDSTOP, 0x100);
-#ifdef DATA32_SUPPORT
-    sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
-    sdmmc_write16(REG_SDBLKLEN32, 0x200);
-#endif
-    sdmmc_write16(REG_SDBLKCOUNT, numsectors);
-    handelNAND.data = out;
-    handelNAND.size = numsectors << 9;
-    sdmmc_send_command(&handelNAND, 0x33C12, sector_no);
-    inittarget(&handelSD);
-    return geterror(&handelNAND);
-}
-
-int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) // experimental
-{
-    if (handelNAND.isSDHC == 0)
-        sector_no <<= 9;
-    inittarget(&handelNAND);
-    sdmmc_write16(REG_SDSTOP, 0x100);
-#ifdef DATA32_SUPPORT
-    sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
-    sdmmc_write16(REG_SDBLKLEN32, 0x200);
-#endif
-    sdmmc_write16(REG_SDBLKCOUNT, numsectors);
-    handelNAND.data = in;
-    handelNAND.size = numsectors << 9;
-    sdmmc_send_command(&handelNAND, 0x52C19, sector_no);
-    inittarget(&handelSD);
-    return geterror(&handelNAND);
-}
-
-static uint32_t
-calcSDSize(uint8_t *csd, int type)
-{
-    uint32_t result = 0;
-    if (type == -1)
-        type = csd[14] >> 6;
-    switch (type) {
-        case 0: {
-            uint32_t block_len = csd[9] & 0xf;
-            block_len = 1 << block_len;
-            uint32_t mult = (csd[4] >> 7) | ((csd[5] & 3) << 1);
-            mult = 1 << (mult + 2);
-            result = csd[8] & 3;
-            result = (result << 8) | csd[7];
-            result = (result << 2) | (csd[6] >> 6);
-            result = (result + 1) * mult * block_len / 512;
-        } break;
-        case 1:
-            result = csd[7] & 0x3f;
-            result = (result << 8) | csd[6];
-            result = (result << 8) | csd[5];
-            result = (result + 1) * 1024;
-            break;
-    }
-    return result;
-}
-
-void
-InitSD()
-{
-    // NAND
-    handelNAND.isSDHC = 0;
-    handelNAND.SDOPT = 0;
-    handelNAND.res = 0;
-    handelNAND.initarg = 1;
-    handelNAND.clk = 0x80;
-    handelNAND.devicenumber = 1;
-
-    // SD
-    handelSD.isSDHC = 0;
-    handelSD.SDOPT = 0;
-    handelSD.res = 0;
-    handelSD.initarg = 0;
-    handelSD.clk = 0x80;
-    handelSD.devicenumber = 0;
-
-    // sdmmc_mask16(0x100,0x800,0);
-    // sdmmc_mask16(0x100,0x1000,0);
-    // sdmmc_mask16(0x100,0x0,0x402);
-    // sdmmc_mask16(0xD8,0x22,0x2);
-    // sdmmc_mask16(0x100,0x2,0);
-    // sdmmc_mask16(0xD8,0x22,0);
-    // sdmmc_write16(0x104,0);
-    // sdmmc_write16(0x108,1);
-    // sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this
-    // sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this
-    // sdmmc_mask16(0x20,0,0x31D);
-    // sdmmc_mask16(0x22,0,0x837F);
-    // sdmmc_mask16(0xFC,0,0xDB);
-    // sdmmc_mask16(0xFE,0,0xDB);
-    ////sdmmc_write16(REG_SDCLKCTL,0x20);
-    ////sdmmc_write16(REG_SDOPT,0x40EE);
-    ////sdmmc_mask16(0x02,0x3,0);
-    // sdmmc_write16(REG_SDCLKCTL,0x40);
-    // sdmmc_write16(REG_SDOPT,0x40EB);
-    // sdmmc_mask16(0x02,0x3,0);
-    // sdmmc_write16(REG_SDBLKLEN,0x200);
-    // sdmmc_write16(REG_SDSTOP,0);
-
-    *(volatile uint16_t *)0x10006100 &= 0xF7FFu; // SDDATACTL32
-    *(volatile uint16_t *)0x10006100 &= 0xEFFFu; // SDDATACTL32
-#ifdef DATA32_SUPPORT
-    *(volatile uint16_t *)0x10006100 |= 0x402u; // SDDATACTL32
-#else
-    *(volatile uint16_t *)0x10006100 |= 0x402u;  // SDDATACTL32
-#endif
-    *(volatile uint16_t *)0x100060D8 = (*(volatile uint16_t *)0x100060D8 & 0xFFDD) | 2;
-#ifdef DATA32_SUPPORT
-    *(volatile uint16_t *)0x10006100 &= 0xFFFFu; // SDDATACTL32
-    *(volatile uint16_t *)0x100060D8 &= 0xFFDFu; // SDDATACTL
-    *(volatile uint16_t *)0x10006104 = 512;      // SDBLKLEN32
-#else
-    *(volatile uint16_t *)0x10006100 &= 0xFFFDu; // SDDATACTL32
-    *(volatile uint16_t *)0x100060D8 &= 0xFFDDu; // SDDATACTL
-    *(volatile uint16_t *)0x10006104 = 0;        // SDBLKLEN32
-#endif
-    *(volatile uint16_t *)0x10006108 = 1;                    // SDBLKCOUNT32
-    *(volatile uint16_t *)0x100060E0 &= 0xFFFEu;             // SDRESET
-    *(volatile uint16_t *)0x100060E0 |= 1u;                  // SDRESET
-    *(volatile uint16_t *)0x10006020 |= TMIO_MASK_ALL;       // SDIR_MASK0
-    *(volatile uint16_t *)0x10006022 |= TMIO_MASK_ALL >> 16; // SDIR_MASK1
-    *(volatile uint16_t *)0x100060FC |= 0xDBu;               // SDCTL_RESERVED7
-    *(volatile uint16_t *)0x100060FE |= 0xDBu;               // SDCTL_RESERVED8
-    *(volatile uint16_t *)0x10006002 &= 0xFFFCu;             // SDPORTSEL
-#ifdef DATA32_SUPPORT
-    *(volatile uint16_t *)0x10006024 = 0x20;
-    *(volatile uint16_t *)0x10006028 = 0x40EE;
-#else
-    *(volatile uint16_t *)0x10006024 = 0x40;     // Nintendo sets this to 0x20
-    *(volatile uint16_t *)0x10006028 = 0x40EB;   // Nintendo sets this to 0x40EE
-#endif
-    *(volatile uint16_t *)0x10006002 &= 0xFFFCu; ////SDPORTSEL
-    *(volatile uint16_t *)0x10006026 = 512;      // SDBLKLEN
-    *(volatile uint16_t *)0x10006008 = 0;        // SDSTOP
-
-    inittarget(&handelSD);
-}
-
-int
-Nand_Init()
-{
-    inittarget(&handelNAND);
-    waitcycles(0xF000);
-
-    DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0, 0);
-
-    DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    do {
-        do {
-            sdmmc_send_command(&handelNAND, 0x10701, 0x100000);
-            DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-            DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-            DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-        } while (!(handelNAND.error & 1));
-    } while ((handelNAND.ret[0] & 0x80000000) == 0);
-
-    DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x10602, 0x0);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x10403, handelNAND.initarg << 0x10);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x10609, handelNAND.initarg << 0x10);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    handelNAND.total_size = calcSDSize((uint8_t *)&handelNAND.ret[0], 0);
-    handelNAND.clk = 1;
-    setckl(1);
-
-    sdmmc_send_command(&handelNAND, 0x10407, handelNAND.initarg << 0x10);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    handelNAND.SDOPT = 1;
-
-    sdmmc_send_command(&handelNAND, 0x10506, 0x3B70100);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x10506, 0x3B90100);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x1040D, handelNAND.initarg << 0x10);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelNAND, 0x10410, 0x200);
-    if ((handelNAND.error & 0x4))
-        return -1;
-
-    handelNAND.clk |= 0x200;
-
-    inittarget(&handelSD);
-
-    return 0;
-}
-
-int
-SD_Init()
-{
-    inittarget(&handelSD);
-    // waitcycles(0x3E8);
-    // waitcycles(0xF000);
-
-    waitcycles(1u << 19); // Card needs a little bit of time to be detected, it seems
-    if (!(*((volatile uint16_t *)0x1000601c) & TMIO_STAT0_SIGSTATE))
-        return -1; // check if card inserted
-
-    DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    sdmmc_send_command(&handelSD, 0, 0);
-    DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    sdmmc_send_command(&handelSD, 0x10408, 0x1AA);
-    // uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E;
-    uint32_t temp = (handelSD.error & 0x1) << 0x1E;
-
-    DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    // int count = 0;
-    uint32_t temp2 = 0;
-    do {
-        do {
-            sdmmc_send_command(&handelSD, 0x10437, handelSD.initarg << 0x10);
-            sdmmc_send_command(&handelSD, 0x10769, 0x00FF8000 | temp);
-            temp2 = 1;
-        } while (!(handelSD.error & 1));
-
-        // DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
-        // DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
-        // DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
-    } while ((handelSD.ret[0] & 0x80000000) == 0);
-    // do
-    //{
-    //    sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
-    //    sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
-    //
-    //    DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
-    //    DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
-    //    DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
-    //}
-    // while(!(handelSD.ret[0] & 0x80000000));
-
-    if (!((handelSD.ret[0] >> 30) & 1) || !temp)
-        temp2 = 0;
-
-    handelSD.isSDHC = temp2;
-    // handelSD.isSDHC = (handelSD.ret[0] & 0x40000000);
-
-    DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10602, 0);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10403, 0);
-    if ((handelSD.error & 0x4))
-        return -1;
-    handelSD.initarg = handelSD.ret[0] >> 0x10;
-
-    DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10609, handelSD.initarg << 0x10);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    handelSD.total_size = calcSDSize((uint8_t *)&handelSD.ret[0], -1);
-    handelSD.clk = 1;
-    setckl(1);
-
-    DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10507, handelSD.initarg << 0x10);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10437, handelSD.initarg << 0x10);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    handelSD.SDOPT = 1;
-    sdmmc_send_command(&handelSD, 0x10446, 0x2);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x1040D, handelSD.initarg << 0x10);
-    if ((handelSD.error & 0x4))
-        return -1;
-
-    DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    sdmmc_send_command(&handelSD, 0x10410, 0x200);
-    if ((handelSD.error & 0x4))
-        return -1;
-    handelSD.clk |= 0x200;
-
-    return 0;
-}
-
-int
-sdmmc_sdcard_init()
-{
-    DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    InitSD();
-    // SD_Init2();
-    // Nand_Init();
-    Nand_Init();
-    DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-    if (SD_Init() != 0)
-        return FALSE;
-    DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4 * 8, RGB(40, 40, 40), RGB(208, 208, 208));
-
-    return TRUE;
-}
-
-int
-sdmmc_get_cid(int isNand, uint32_t *info)
-{
-    struct mmcdevice *device;
-    if (isNand)
-        device = &handelNAND;
-    else
-        device = &handelSD;
-
-    inittarget(device);
-    // use cmd7 to put sd card in standby mode
-    // CMD7
-    {
-        sdmmc_send_command(device, 0x10507, 0);
-        // if((device->error & 0x4)) return -1;
-    }
-
-    // get sd card info
-    // use cmd10 to read CID
-    {
-        sdmmc_send_command(device, 0x1060A, device->initarg << 0x10);
-        // if((device->error & 0x4)) return -2;
-
-        for (int i = 0; i < 4; ++i) {
-            info[i] = device->ret[i];
-        }
-    }
-
-    // put sd card back to transfer mode
-    // CMD7
-    {
-        sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
-        // if((device->error & 0x4)) return -3;
-    }
-
-    if (isNand) {
-        inittarget(&handelSD);
-    }
-
-    return 0;
-}
diff --git a/source/fatfs/sdmmc.h b/source/fatfs/sdmmc.h
deleted file mode 100644 (file)
index 3b7400d..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-#ifndef __SDMMC_H__
-#define __SDMMC_H__
-
-#define TRUE 1
-#define FALSE 0
-
-#include <stdint.h>
-
-#define SDMMC_BASE 0x10006000
-
-#define REG_SDCMD 0x00
-#define REG_SDPORTSEL 0x02
-#define REG_SDCMDARG 0x04
-#define REG_SDCMDARG0 0x04
-#define REG_SDCMDARG1 0x06
-#define REG_SDSTOP 0x08
-#define REG_SDBLKCOUNT 0x0a
-
-#define REG_SDRESP0 0x0c
-#define REG_SDRESP1 0x0e
-#define REG_SDRESP2 0x10
-#define REG_SDRESP3 0x12
-#define REG_SDRESP4 0x14
-#define REG_SDRESP5 0x16
-#define REG_SDRESP6 0x18
-#define REG_SDRESP7 0x1a
-
-#define REG_SDSTATUS0 0x1c
-#define REG_SDSTATUS1 0x1e
-
-#define REG_SDIRMASK0 0x20
-#define REG_SDIRMASK1 0x22
-#define REG_SDCLKCTL 0x24
-
-#define REG_SDBLKLEN 0x26
-#define REG_SDOPT 0x28
-#define REG_SDFIFO 0x30
-
-#define REG_DATACTL 0xd8
-#define REG_SDRESET 0xe0
-#define REG_SDPROTECTED 0xf6 // bit 0 determines if sd is protected or not?
-
-#define REG_DATACTL32 0x100
-#define REG_SDBLKLEN32 0x104
-#define REG_SDBLKCOUNT32 0x108
-#define REG_SDFIFO32 0x10C
-
-#define REG_CLK_AND_WAIT_CTL 0x138
-#define REG_RESET_SDIO 0x1e0
-
-#define TMIO_STAT0_CMDRESPEND 0x0001
-#define TMIO_STAT0_DATAEND 0x0004
-#define TMIO_STAT0_CARD_REMOVE 0x0008
-#define TMIO_STAT0_CARD_INSERT 0x0010
-#define TMIO_STAT0_SIGSTATE 0x0020
-#define TMIO_STAT0_WRPROTECT 0x0080
-#define TMIO_STAT0_CARD_REMOVE_A 0x0100
-#define TMIO_STAT0_CARD_INSERT_A 0x0200
-#define TMIO_STAT0_SIGSTATE_A 0x0400
-#define TMIO_STAT1_CMD_IDX_ERR 0x0001
-#define TMIO_STAT1_CRCFAIL 0x0002
-#define TMIO_STAT1_STOPBIT_ERR 0x0004
-#define TMIO_STAT1_DATATIMEOUT 0x0008
-#define TMIO_STAT1_RXOVERFLOW 0x0010
-#define TMIO_STAT1_TXUNDERRUN 0x0020
-#define TMIO_STAT1_CMDTIMEOUT 0x0040
-#define TMIO_STAT1_RXRDY 0x0100
-#define TMIO_STAT1_TXRQ 0x0200
-#define TMIO_STAT1_ILL_FUNC 0x2000
-#define TMIO_STAT1_CMD_BUSY 0x4000
-#define TMIO_STAT1_ILL_ACCESS 0x8000
-
-// Comes from TWLSDK mongoose.tef DWARF info
-#define SDMC_NORMAL 0x00000000
-#define SDMC_ERR_COMMAND 0x00000001
-#define SDMC_ERR_CRC 0x00000002
-#define SDMC_ERR_END 0x00000004
-#define SDMC_ERR_TIMEOUT 0x00000008
-#define SDMC_ERR_FIFO_OVF 0x00000010
-#define SDMC_ERR_FIFO_UDF 0x00000020
-#define SDMC_ERR_WP 0x00000040
-#define SDMC_ERR_ABORT 0x00000080
-#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
-#define SDMC_ERR_PARAM 0x00000200
-#define SDMC_ERR_R1_STATUS 0x00000800
-#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
-#define SDMC_ERR_RESET 0x00002000
-#define SDMC_ERR_ILA 0x00004000
-#define SDMC_ERR_INFO_DETECT 0x00008000
-
-#define SDMC_STAT_ERR_UNKNOWN 0x00080000
-#define SDMC_STAT_ERR_CC 0x00100000
-#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
-#define SDMC_STAT_ERR_CRC 0x00800000
-#define SDMC_STAT_ERR_OTHER 0xf9c70008
-
-#define TMIO_MASK_ALL 0x837f031d
-
-#define TMIO_MASK_GW                                                                                                                                           \
-    (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR |         \
-     TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
-
-#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
-#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
-
-#ifdef __cplusplus
-extern "C" {
-#endif
-
-typedef struct mmcdevice
-{
-    uint8_t *data;
-    uint32_t size;
-    uint32_t error;
-    uint16_t stat0;
-    uint16_t stat1;
-    uint32_t ret[4];
-    uint32_t initarg;
-    uint32_t isSDHC;
-    uint32_t clk;
-    uint32_t SDOPT;
-    uint32_t devicenumber;
-    uint32_t total_size; // size in sectors of the device
-    uint32_t res;
-} mmcdevice;
-
-int sdmmc_sdcard_init();
-int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
-int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
-int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
-int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
-
-int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
-int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
-
-int sdmmc_get_cid(int isNand, uint32_t *info);
-
-mmcdevice *getMMCDevice(int drive);
-
-void InitSD();
-int Nand_Init();
-int SD_Init();
-
-#ifdef __cplusplus
-};
-#endif
-
-//---------------------------------------------------------------------------------
-static inline uint16_t
-sdmmc_read16(uint16_t reg)
-{
-    //---------------------------------------------------------------------------------
-    return *(volatile uint16_t *)(SDMMC_BASE + reg);
-}
-
-//---------------------------------------------------------------------------------
-static inline void
-sdmmc_write16(uint16_t reg, uint16_t val)
-{
-    //---------------------------------------------------------------------------------
-    *(volatile uint16_t *)(SDMMC_BASE + reg) = val;
-}
-
-//---------------------------------------------------------------------------------
-static inline uint32_t
-sdmmc_read32(uint16_t reg)
-{
-    //---------------------------------------------------------------------------------
-    return *(volatile uint32_t *)(SDMMC_BASE + reg);
-}
-
-//---------------------------------------------------------------------------------
-static inline void
-sdmmc_write32(uint16_t reg, uint32_t val)
-{
-    //---------------------------------------------------------------------------------
-    *(volatile uint32_t *)(SDMMC_BASE + reg) = val;
-}
-
-//---------------------------------------------------------------------------------
-static inline void
-sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set)
-{
-    //---------------------------------------------------------------------------------
-    uint16_t val = sdmmc_read16(reg);
-    val &= ~clear;
-    val |= set;
-    sdmmc_write16(reg, val);
-}
-
-static inline void
-setckl(uint32_t data)
-{
-    sdmmc_mask16(REG_SDCLKCTL, 0x100, 0);
-    sdmmc_mask16(REG_SDCLKCTL, 0x2FF, data & 0x2FF);
-    sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
-}
-
-#endif
index e5f61202339829d6a21d21dc9b8a48ab5ae27004..78d0b9f29899859c7794bf1a403002551e760368 100644 (file)
@@ -313,8 +313,6 @@ void* find_section_key() {
                                0x32, 0xfd, 0xff, 0x03, 0x74, 0xd7, 0x45, 0x2c};
     uint8_t sha256check[32] = {0};
 
-    uint64_t hash_dat = 0;
-
     for(; search_size > 0; search_size -= 4) {
         // Is candidate?
         if (key_loc[search_size] == 0xDD) {
index a3f33cf797297177b0210286e93a7af1fae85f79..5f4785c3aefabaaa3117f64bb791022738d465a0 100644 (file)
@@ -74,7 +74,7 @@ static int current_menu_index_patches = 0;
 int
 list_patches_build_back(char *fpath, int desc_is_path)
 {
-    FILINFO fno = {.lfname = NULL };
+    FILINFO fno;
 
     // this code handles directory content deletion
     if (f_stat(fpath, &fno) != FR_OK)
@@ -86,9 +86,8 @@ list_patches_build_back(char *fpath, int desc_is_path)
         if (f_opendir(&pdir, fpath) != FR_OK)
             return 1;
 
-        *(fname++) = '/';
-        fno.lfname = fname;
-        fno.lfsize = fpath + 255 - fname;
+        fname[0] = '/';
+        fname++;
 
         while (f_readdir(&pdir, &fno) == FR_OK) {
             if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
@@ -102,7 +101,8 @@ list_patches_build_back(char *fpath, int desc_is_path)
         }
 
         f_closedir(&pdir);
-        *(--fname) = '\0';
+        --fname;
+        fname[0] = 0;
     } else {
         struct system_patch p;
         read_file(&p, fpath, sizeof(struct system_patch));
index 20237a0f6944f883df0ab729e15a7e4368df51d3..b766e7acf04eb3a9a10807171e58593c59a6194a 100644 (file)
@@ -9,30 +9,13 @@
 #include "../std/abort.h"
 #include "../firm/firm.h"
 #include "../firm/fcram.h"
-#include "../fatfs/sdmmc.h"
+#include <ctr9/io.h>
 #include "../firm/headers.h"
 #include "../patch_format.h"
 #include "../config.h"
 
 uint8_t *emunand_temp = (uint8_t *)FCRAM_JUNK_LOC;
 
-void
-verify_loop_emunand(char *filename)
-{
-    // FIXME - This won't work unless the NAND file is completely contiguous on disk, sadly.
-    // Technically speaking if I were to defrag my SD this would work, I suspect.
-    // For now, this will remain as dead code.
-
-    uint32_t offset = get_file_sector(filename); // Get the sector of the file
-
-    // Check for RedNAND image on SD
-    if (!sdmmc_sdcard_readsectors(offset, 1, emunand_temp) && *(uint32_t *)(emunand_temp + 0x100) == NCSD_MAGIC) {
-        fprintf(stderr, "emunand: found NCSD magic\n");
-    } else {
-        abort("emunand: selected NAND image is not valid.\n");
-    }
-}
-
 void
 verify_emunand(uint32_t index, uint32_t *off, uint32_t *head)
 {
index 95a5bfe298e8d6fbd22bc09abf12e8cdc3a3c39a..51b4e234ff53072b8feccf7b75397d65bc85c68b 100644 (file)
@@ -5,7 +5,7 @@
 #include "../std/abort.h"
 #include "../firm/firm.h"
 #include "../firm/fcram.h"
-#include "../fatfs/sdmmc.h"
+#include <ctr9/io.h>
 #include "../firm/headers.h"
 #include "../patch_format.h"
 
index 548321cfb6cc1f06dc06bdbba543ffafaca55fe4..89b169344ddfda715727c20d54244020880c7684 100644 (file)
@@ -4,12 +4,13 @@
 #include <assert.h>
 #include <stdarg.h>
 #include "memory.h"
-#include "../fatfs/ff.h"
+#include <ctr9/io.h>
 #include "../firm/fcram.h"
 #include "fs.h"
 #include "unused.h"
 #include "../config.h"
 #include "../patch_format.h"
+#include "abort.h"
 
 static unsigned int top_cursor_x = 0, top_cursor_y = 0;
 static unsigned int bottom_cursor_x = 0, bottom_cursor_y = 0;
@@ -207,7 +208,7 @@ void set_font(const char* filename) {
 
     FILE* f = fopen(filename, "r");
 
-    if (!f) return;
+    if (!f) abort("Failed to load font file!\n");
 
     unsigned int new_w, new_h;
 
@@ -215,8 +216,7 @@ void set_font(const char* filename) {
     fread(&new_h, 1, 4, f);
 
     if (new_w == 0 || new_h == 0) {
-        fprintf(stderr, "Invalid font file: w/h is 0 - not loaded\n");
-        return;
+        abort("Invalid font file: w/h is 0 - not loaded\n");
     }
 
     unsigned int c_font_w = (new_w / 8) + (new_w % 8 ? 1 : 0);
index c7a1f3f483d73103eee4ed5bccbf366359278234..20016cb9f8eb8119dcc44fc227a45b19eca1d67f 100644 (file)
@@ -1,12 +1,17 @@
 #include <stddef.h>
 #include "fs.h"
 #include "memory.h"
-#include "../fatfs/ff.h"
+#include <ctr9/io.h>
 #include "draw.h"
 #include "memory.h"
 #include "../config.h"
 
+// ctr_nand_interface nand_io;
+// ctr_nand_crypto_interface ctr_io;
+// ctr_nand_crypto_interface twl_io;
+static ctr_sd_interface sd_io;
 static FATFS fs;
+static int set_up_fs = 0;
 
 FILE files[MAX_FILES_OPEN];
 
@@ -15,7 +20,7 @@ FILE files[MAX_FILES_OPEN];
 int
 rrmdir_back(char *fpath)
 {
-    FILINFO fno = {.lfname = NULL };
+    FILINFO fno;
 
     // this code handles directory content deletion
     if (f_stat(fpath, &fno) != FR_OK)
@@ -29,8 +34,6 @@ rrmdir_back(char *fpath)
 
         fname[0] = '/';
         fname++;
-        fno.lfname = fname;
-        fno.lfsize = fpath + 255 - fname;
 
         while (f_readdir(&pdir, &fno) == FR_OK) {
             if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
@@ -44,6 +47,7 @@ rrmdir_back(char *fpath)
         }
 
         f_closedir(&pdir);
+
         --fname;
         fname[0] = 0;
     }
@@ -62,7 +66,15 @@ rrmdir(char *name)
 int
 fmount(void)
 {
-    if (f_mount(&fs, "0:", 1))
+    if(!set_up_fs && ctr_fatfs_initialize(NULL, NULL, NULL, &sd_io))
+        return 1;
+
+    set_up_fs = 1;
+
+    if (f_mount(&fs, "SD:", 1))
+        return 1;
+
+    if (f_chdrive("SD:"))
         return 1;
 
     for (int i = 0; i < MAX_FILES_OPEN; i++)
@@ -78,7 +90,7 @@ fumount(void)
         if (files[i].is_open)
             fclose(&files[i]);
 
-    if (f_mount(NULL, "0:", 1))
+    if (f_mount(NULL, "SD:", 1))
         return 1;
 
     config.options[OPTION_SAVE_LOGS] = 0; // FS unmounted, can't log anymore
@@ -234,26 +246,3 @@ read_file(void *data, char *path, size_t size)
 
     return read;
 }
-
-//    DWORD fptr;   /* File read/write pointer (Zeroed on file open) */
-//    DWORD fsize;  /* File size */
-//    DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
-//    DWORD clust;  /* Current cluster of fpter (not valid when fprt is 0) */
-//    DWORD dsect;  /* Sector number appearing in buf[] (0:invalid) */
-
-size_t
-get_file_sector(char *path)
-{
-    FILE *temp = fopen(path, "r");
-
-    if (!temp || !temp->is_open)
-        return 0;
-
-    UINT sector;
-
-    f_getsector(&temp->handle, &sector);
-
-    fclose(temp);
-
-    return sector;
-}
index e40e150107c30012da6cec7eb3db8e158c37e27a..b3cdf03466aefe190e234b93eacfcac67413a034 100644 (file)
@@ -3,7 +3,7 @@
 
 #include "types.h"
 #include "memory.h"
-#include "../fatfs/ff.h"
+#include <ctr9/io.h>
 
 #define MAX_FILES_OPEN 64
 
@@ -43,6 +43,4 @@ size_t fread(void *buffer, size_t elementSize, size_t elementCnt, FILE *fp);
 size_t write_file(void *data, char *path, size_t size);
 size_t read_file(void *data, char *path, size_t size);
 
-size_t get_file_sector(char *path);
-
 #endif