From: chaoskagami Date: Fri, 8 Jul 2016 04:11:38 +0000 (-0400) Subject: Begin libctr9_io port, currently malfunctioning somehow X-Git-Tag: v0.2.0~30 X-Git-Url: https://chaos.moe/g/?a=commitdiff_plain;h=33fa4fc05d27ef05749c2a7f71195a8a5bb96393;p=corbenik%2Fcorbenik.git Begin libctr9_io port, currently malfunctioning somehow --- diff --git a/.gitmodules b/.gitmodules index 0dd8102..d7c0296 100644 --- a/.gitmodules +++ b/.gitmodules @@ -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 diff --git a/Makefile b/Makefile index 9cd2e97..8e250c6 100644 --- 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 index 0000000..f1e4074 --- /dev/null +++ b/external/libctr9_io @@ -0,0 +1 @@ +Subproject commit f1e407450e658883343d0877c4afcffe3bb697cc diff --git a/host/compile_ctr9_io.sh b/host/compile_ctr9_io.sh new file mode 100755 index 0000000..61a9354 --- /dev/null +++ b/host/compile_ctr9_io.sh @@ -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 ../../ diff --git a/host/copy.sh b/host/copy.sh index 18d8844..cd53e5e 100755 --- a/host/copy.sh +++ b/host/copy.sh @@ -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 diff --git a/source/chain.c b/source/chain.c index db80493..906a90e 100644 --- a/source/chain.c +++ b/source/chain.c @@ -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 index c46ac5f..0000000 --- a/source/fatfs/00readme.txt +++ /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 index 77e42fa..0000000 --- a/source/fatfs/delay.s +++ /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 index 9aedac3..0000000 --- a/source/fatfs/diskio.c +++ /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 -#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 index d116887..0000000 --- a/source/fatfs/diskio.h +++ /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 index 5eb62ec..0000000 --- a/source/fatfs/ff.c +++ /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 -/*-----------------------------------------------------------------------*/ -/* 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 index 3758f2f..0000000 --- a/source/fatfs/ff.h +++ /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 index 158cbd4..0000000 --- a/source/fatfs/ffconf.h +++ /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 index b101820..0000000 --- a/source/fatfs/history.txt +++ /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 index 1bfa223..0000000 --- a/source/fatfs/integer.h +++ /dev/null @@ -1,33 +0,0 @@ -/*-------------------------------------------*/ -/* Integer type definitions for FatFs module */ -/*-------------------------------------------*/ - -#ifndef _FF_INTEGER -#define _FF_INTEGER - -#ifdef _WIN32 /* FatFs development platform */ - -#include -#include - -#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 index 8415180..0000000 --- a/source/fatfs/sdmmc.c +++ /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 -#include -#include - -#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 index 3b7400d..0000000 --- a/source/fatfs/sdmmc.h +++ /dev/null @@ -1,199 +0,0 @@ -#ifndef __SDMMC_H__ -#define __SDMMC_H__ - -#define TRUE 1 -#define FALSE 0 - -#include - -#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 diff --git a/source/firm/firm.c b/source/firm/firm.c index e5f6120..78d0b9f 100644 --- a/source/firm/firm.c +++ b/source/firm/firm.c @@ -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) { diff --git a/source/menu.c b/source/menu.c index a3f33cf..5f4785c 100644 --- a/source/menu.c +++ b/source/menu.c @@ -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)); diff --git a/source/patch/emunand.c b/source/patch/emunand.c index 20237a0..b766e7a 100644 --- a/source/patch/emunand.c +++ b/source/patch/emunand.c @@ -9,30 +9,13 @@ #include "../std/abort.h" #include "../firm/firm.h" #include "../firm/fcram.h" -#include "../fatfs/sdmmc.h" +#include #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) { diff --git a/source/patch/reboot.c b/source/patch/reboot.c index 95a5bfe..51b4e23 100644 --- a/source/patch/reboot.c +++ b/source/patch/reboot.c @@ -5,7 +5,7 @@ #include "../std/abort.h" #include "../firm/firm.h" #include "../firm/fcram.h" -#include "../fatfs/sdmmc.h" +#include #include "../firm/headers.h" #include "../patch_format.h" diff --git a/source/std/draw.c b/source/std/draw.c index 548321c..89b1693 100644 --- a/source/std/draw.c +++ b/source/std/draw.c @@ -4,12 +4,13 @@ #include #include #include "memory.h" -#include "../fatfs/ff.h" +#include #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); diff --git a/source/std/fs.c b/source/std/fs.c index c7a1f3f..20016cb 100644 --- a/source/std/fs.c +++ b/source/std/fs.c @@ -1,12 +1,17 @@ #include #include "fs.h" #include "memory.h" -#include "../fatfs/ff.h" +#include #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, §or); - - fclose(temp); - - return sector; -} diff --git a/source/std/fs.h b/source/std/fs.h index e40e150..b3cdf03 100644 --- a/source/std/fs.h +++ b/source/std/fs.h @@ -3,7 +3,7 @@ #include "types.h" #include "memory.h" -#include "../fatfs/ff.h" +#include #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