diff --git a/injector/source/patcher.c b/injector/source/patcher.c
index 201d10c..32fb3d1 100644
--- a/injector/source/patcher.c
+++ b/injector/source/patcher.c
@@ -408,7 +408,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
- if(CONFIG(5))
+ if(CONFIG(4))
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
@@ -577,7 +577,7 @@ void patchCode(u64 progId, u8 *code, u32 size)
}
default:
- if(CONFIG(4))
+ if(CONFIG(3))
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
diff --git a/source/buttons.h b/source/buttons.h
index 05ddc7a..83f9a04 100644
--- a/source/buttons.h
+++ b/source/buttons.h
@@ -28,7 +28,7 @@
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
-#define BUTTON_A 1
+#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
@@ -42,4 +42,5 @@
#define SAFE_MODE (BUTTON_R1 | BUTTON_L1 | BUTTON_A | BUTTON_UP)
#define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_A | BUTTON_SELECT)
-#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
\ No newline at end of file
+#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)
+#define PIN_BUTTONS (BUTTON_A | BUTTON_B | BUTTON_X | BUTTON_Y | BUTTON_START)
\ No newline at end of file
diff --git a/source/config.c b/source/config.c
index d6e0b08..941ebaf 100644
--- a/source/config.c
+++ b/source/config.c
@@ -25,13 +25,11 @@
#include "screen.h"
#include "draw.h"
#include "fs.h"
-#include "i2c.h"
#include "buttons.h"
void configureCFW(const char *configPath)
{
- bool needToDeinit = initScreens();
-
+ clearScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
drawString("Press A to select, START to save", 10, 30, COLOR_WHITE);
@@ -40,13 +38,13 @@ void configureCFW(const char *configPath)
"Dev. features: None( ) ErrDisp( ) UNITINFO( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
- "( ) SysNAND is updated (A9LH-only)",
- "( ) Force A9LH detection",
+ "( ) Use SysNAND FIRM if booting with R (A9LH)",
"( ) Use second EmuNAND as default",
"( ) Enable region/language emu. and ext. .code",
"( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM",
- "( ) Enable splash screen with no screen-init" };
+ "( ) Enable splash screen with no screen-init",
+ "( ) Use a PIN" };
struct multiOption {
int posXs[4];
@@ -196,16 +194,13 @@ void configureCFW(const char *configPath)
for(u32 i = 0; i < singleOptionsAmount; i++)
config |= (singleOptions[i].enabled ? 1 : 0) << (i + 16);
- fileWrite(&config, configPath, 4);
+ if(!fileWrite(&config, configPath, 4))
+ {
+ createDirectory("luma");
+ if(!fileWrite(&config, configPath, 4))
+ error("Error writing the configuration file");
+ }
//Wait for the pressed buttons to change
while(HID_PAD == BUTTON_START);
-
- if(needToDeinit)
- {
- //Turn off backlight
- i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
- deinitScreens();
- PDN_GPU_CNT = 1;
- }
}
diff --git a/source/crypto.c b/source/crypto.c
index a7bce98..cb3806e 100755
--- a/source/crypto.c
+++ b/source/crypto.c
@@ -294,16 +294,16 @@ static void sha(void *res, const void *src, u32 size, u32 mode)
* NAND/FIRM crypto
****************************************************************/
-static u8 nandCTR[0x10],
- nandSlot;
+static u8 __attribute__((aligned(4))) nandCTR[0x10];
+static u8 nandSlot;
static u32 fatStart;
//Initialize the CTRNAND crypto
void ctrNandInit(void)
{
- u8 cid[0x10];
- u8 shaSum[0x20];
+ u8 __attribute__((aligned(4))) cid[0x10];
+ u8 __attribute__((aligned(4))) shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE);
@@ -311,7 +311,7 @@ void ctrNandInit(void)
if(isN3DS)
{
- u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
+ u8 __attribute__((aligned(4))) keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
fatStart = 0x5CAD7;
@@ -326,7 +326,7 @@ void ctrNandInit(void)
//Read and decrypt from the selected CTRNAND
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{
- u8 tmpCTR[0x10];
+ u8 __attribute__((aligned(4))) tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -350,8 +350,8 @@ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
//Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
void setRSAMod0DerivedKeys(void)
{
- const u8 keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
- const u8 keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
+ const u8 __attribute__((aligned(4))) keyX0x25[0x10] = {0xCE, 0xE7, 0xD8, 0xAB, 0x30, 0xC0, 0x0D, 0xAE, 0x85, 0x0E, 0xF5, 0xE3, 0x82, 0xAC, 0x5A, 0xF3};
+ const u8 __attribute__((aligned(4))) keyY0x2F[0x10] = {0xC3, 0x69, 0xBA, 0xA2, 0x1E, 0x18, 0x8A, 0x88, 0xA9, 0xAA, 0x94, 0xE5, 0x50, 0x6A, 0x9F, 0x16};
aes_setkey(0x25, keyX0x25, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x2F, keyY0x2F, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -374,14 +374,29 @@ void decryptExeFs(u8 *inbuf)
aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
-//ARM9Loader replacement
-//Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233
-void arm9Loader(u8 *arm9Section, u32 mode)
+/* ARM9Loader replacement
+ Originally adapted from: https://github.com/Reisyukaku/ReiNand/blob/228c378255ba693133dec6f3368e14d386f2cde7/source/crypto.c#L233 */
+void arm9Loader(u8 *arm9Section)
{
+ //Determine the arm9loader version
+ u32 a9lVersion;
+ switch(arm9Section[0x53])
+ {
+ case 0xFF:
+ a9lVersion = 0;
+ break;
+ case '1':
+ a9lVersion = 1;
+ break;
+ default:
+ a9lVersion = 2;
+ break;
+ }
+
//Firm keys
- u8 keyY[0x10],
- arm9BinCTR[0x10],
- arm9BinSlot = mode ? 0x16 : 0x15;
+ u8 __attribute__((aligned(4))) keyY[0x10];
+ u8 __attribute__((aligned(4))) arm9BinCTR[0x10];
+ u8 arm9BinSlot = a9lVersion ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10);
@@ -393,13 +408,13 @@ void arm9Loader(u8 *arm9Section, u32 mode)
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
- if(mode)
+ if(a9lVersion)
{
- const u8 key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8},
- key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
- u8 keyX[0x10];
+ const u8 __attribute__((aligned(4))) key1[0x10] = {0x07, 0x29, 0x44, 0x38, 0xF8, 0xC9, 0x75, 0x93, 0xAA, 0x0E, 0x4A, 0xB4, 0xAE, 0x84, 0xC1, 0xD8};
+ const u8 __attribute__((aligned(4))) key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
+ u8 __attribute__((aligned(4))) keyX[0x10];
- aes_setkey(0x11, mode == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes_setkey(0x11, a9lVersion == 2 ? key2 : key1, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
@@ -413,10 +428,10 @@ void arm9Loader(u8 *arm9Section, u32 mode)
aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Set >=9.6 KeyXs
- if(mode == 2)
+ if(a9lVersion == 2)
{
- u8 keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98},
- decKey[0x10];
+ u8 __attribute__((aligned(4))) keyData[0x10] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
+ u8 __attribute__((aligned(4))) decKey[0x10];
//Set keys 0x19..0x1F keyXs
aes_use_keyslot(0x11);
@@ -427,4 +442,16 @@ void arm9Loader(u8 *arm9Section, u32 mode)
keyData[0xF] += 1;
}
}
+}
+
+void computePINHash(u8 out[32], u8 *in, u32 blockCount)
+{
+ u8 __attribute__((aligned(4))) cid[0x10];
+ u8 __attribute__((aligned(4))) cipherText[0x10];
+ sdmmc_get_cid(1, (u32 *)cid);
+
+ aes_use_keyslot(4); // console-unique keyslot which keys are set by the Arm9 bootROM
+ aes(cipherText, in, blockCount, cid, AES_CBC_ENCRYPT_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+
+ sha(out, cipherText, 0x10, SHA_256_MODE);
}
\ No newline at end of file
diff --git a/source/crypto.h b/source/crypto.h
index 8866821..f8db96c 100755
--- a/source/crypto.h
+++ b/source/crypto.h
@@ -107,4 +107,6 @@ void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void setRSAMod0DerivedKeys(void);
void decryptExeFs(u8 *inbuf);
-void arm9Loader(u8 *arm9Section, u32 mode);
\ No newline at end of file
+void arm9Loader(u8 *arm9Section);
+
+void computePINHash(u8 out[32], u8 *in, u32 blockCount);
\ No newline at end of file
diff --git a/source/draw.c b/source/draw.c
index f162346..4a98161 100644
--- a/source/draw.c
+++ b/source/draw.c
@@ -46,8 +46,8 @@ bool loadSplash(void)
//Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/luma/splash.bin") +
- fileRead(fb->bottom, "/luma/splashbottom.bin") != 0)
- return true;
+ fileRead(fb->bottom, "/luma/splashbottom.bin")) return true;
+
return false;
}
diff --git a/source/fatfs/00history.txt b/source/fatfs/00history.txt
old mode 100644
new mode 100755
index 4d76198..151b694
--- a/source/fatfs/00history.txt
+++ b/source/fatfs/00history.txt
@@ -10,7 +10,7 @@ R0.00 (February 26, 2006)
R0.01 (April 29, 2006)
- First stable version.
+ The first release.
@@ -246,9 +246,22 @@ R0.11a (September 05, 2015)
R0.12 (April 12, 2016)
- Added support of exFAT file system. (_FS_EXFAT)
+ Added support for exFAT file system. (_FS_EXFAT)
Added f_expand(). (_USE_EXPAND)
Changed some members in FINFO structure and behavior of f_readdir().
- Added an option _USE_CHMOD and removed an option _WORD_ACCESS.
- Fixed errors in the case conversion teble of Unicode (cc*.c).
+ Added an option _USE_CHMOD.
+ Removed an option _WORD_ACCESS.
+ Fixed errors in the case conversion table of Unicode (cc*.c).
+
+
+
+R0.12a (July 10, 2016)
+
+ Added support for creating exFAT volume with some changes of f_mkfs().
+ Added a file open method FA_OPEN_APPEND. An f_lseek() following f_open() is no longer needed.
+ f_forward() is available regardless of _FS_TINY.
+ Fixed f_mkfs() creates wrong volume.
+ Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
+ Fixed wrong memory read in create_name().
+
diff --git a/source/fatfs/00readme.txt b/source/fatfs/00readme.txt
old mode 100644
new mode 100755
index 35536f7..42426a4
--- a/source/fatfs/00readme.txt
+++ b/source/fatfs/00readme.txt
@@ -1,4 +1,4 @@
-FatFs Module Source Files R0.12
+FatFs Module Source Files R0.12a
FILES
diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c
old mode 100644
new mode 100755
index 9656965..a190e7e
--- a/source/fatfs/ff.c
+++ b/source/fatfs/ff.c
@@ -1,11 +1,13 @@
/*----------------------------------------------------------------------------/
-/ FatFs - FAT file system module R0.12 (C)ChaN, 2016 /
+/ FatFs - Generic FAT file system module R0.12a /
/-----------------------------------------------------------------------------/
-/ FatFs module is a free software that opened under license policy of
-/ following conditions.
/
/ Copyright (C) 2016, ChaN, all right reserved.
/
+/ FatFs module is an open source software. Redistribution and use of FatFs in
+/ source and binary forms, with or without modification, are permitted provided
+/ that the following condition is met:
+
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
@@ -17,7 +19,7 @@
#include "ff.h" /* Declarations of FatFs API */
-#include "diskio.h" /* Declarations of disk I/O functions */
+#include "diskio.h" /* Declarations of device I/O functions */
/*--------------------------------------------------------------------------
@@ -26,11 +28,14 @@
---------------------------------------------------------------------------*/
-#if _FATFS != 88100 /* Revision ID */
+#if _FATFS != 80186 /* Revision ID */
#error Wrong include file (ff.h).
#endif
+#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
+
+
/* Reentrancy related */
#if _FS_REENTRANT
#if _USE_LFN == 1
@@ -43,7 +48,6 @@
#define LEAVE_FF(fs, res) return res
#endif
-#define ABORT(fs, res) { fp->err = (BYTE)(res); LEAVE_FF(fs, res); }
/* Definitions of sector size */
@@ -294,7 +298,7 @@ typedef struct {
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, \
+ 0x90,0x91,0x92,0x93,0x94,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 == 869 /* Greek 2 */
@@ -347,6 +351,18 @@ typedef struct {
#endif /* _DF1S */
+/* File attribute bits (internal use) */
+#define AM_VOL 0x08 /* Volume label */
+#define AM_LFN 0x0F /* LFN entry */
+#define AM_MASK 0x3F /* Mask of defined bits */
+
+
+/* File access control and file status flags (internal use) */
+#define FA_SEEKEND 0x20 /* Seek to end of the file on file open */
+#define FA_MODIFIED 0x40 /* File has been modified */
+#define FA_DIRTY 0x80 /* FIL.buf[] needs to be written-back */
+
+
/* Name status flags */
#define NSFLAG 11 /* Index of name status byte in fn[] */
#define NS_LOSS 0x01 /* Out of 8.3 format */
@@ -355,12 +371,15 @@ typedef struct {
#define NS_BODY 0x08 /* Lower case flag (body) */
#define NS_EXT 0x10 /* Lower case flag (ext) */
#define NS_DOT 0x20 /* Dot entry */
+#define NS_NOLFN 0x40 /* Do not find LFN */
#define NS_NONAME 0x80 /* Not followed */
-/* Limits and Boundaries (Differ from specs but correct for real DOS/Windows) */
-#define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */
-#define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */
+/* Limits and boundaries (differ from specs but correct for real DOS/Windows) */
+#define MAX_FAT12 0xFF5 /* Maximum number of FAT12 clusters */
+#define MAX_FAT16 0xFFF5 /* Maximum number of FAT16 clusters */
+#define MAX_FAT32 0xFFFFFF5 /* Maximum number of FAT32 clusters */
+#define MAX_EXFAT 0x7FFFFFFD /* Maximum number of exFAT clusters (limited by implementation) */
#define MAX_DIR 0x200000 /* Maximum size of FAT directory */
#define MAX_DIR_EX 0x10000000 /* Maximum size of exFAT directory */
@@ -369,7 +388,7 @@ typedef struct {
/ structure members because the structure is not binary compatible between
/ different platforms */
-#define BS_jmpBoot 0 /* x86 jump instruction (3-byte) */
+#define BS_JmpBoot 0 /* x86 jump instruction (3-byte) */
#define BS_OEMName 3 /* OEM name (8-byte) */
#define BPB_BytsPerSec 11 /* Sector size [byte] (WORD) */
#define BPB_SecPerClus 13 /* Cluster size [sector] (BYTE) */
@@ -389,9 +408,10 @@ typedef struct {
#define BS_VolID 39 /* Volume serial number (DWORD) */
#define BS_VolLab 43 /* Volume label string (8-byte) */
#define BS_FilSysType 54 /* File system type string (8-byte) */
-#define BPB_FATSz32 36 /* FAT size (32-bit) [sector] (DWORD) */
-#define BPB_ExtFlags 40 /* Extended flags (WORD) */
+#define BS_BootCode 62 /* Boot code (448-byte) */
+#define BPB_FATSz32 36 /* FAT32: FAT size [sector] (DWORD) */
+#define BPB_ExtFlags32 40 /* FAT32: Extended flags (WORD) */
#define BPB_FSVer32 42 /* FAT32: File system version (WORD) */
#define BPB_RootClus32 44 /* FAT32: Root directory cluster (DWORD) */
#define BPB_FSInfo32 48 /* FAT32: Offset of FSINFO sector (WORD) */
@@ -402,8 +422,9 @@ typedef struct {
#define BS_VolID32 67 /* FAT32: Volume serial number (DWORD) */
#define BS_VolLab32 71 /* FAT32: Volume label string (8-byte) */
#define BS_FilSysType32 82 /* FAT32: File system type string (8-byte) */
+#define BS_BootCode32 90 /* FAT32: Boot code (420-byte) */
-#define BPB_ZeroedEx 11 /* exFAT: Must be zero (35-byte) */
+#define BPB_ZeroedEx 11 /* exFAT: MBZ field (53-byte) */
#define BPB_VolOfsEx 64 /* exFAT: Volume offset from top of the drive [sector] (QWORD) */
#define BPB_TotSecEx 72 /* exFAT: Volume size [sector] (QWORD) */
#define BPB_FatOfsEx 80 /* exFAT: FAT offset from top of the volume [sector] (DWORD) */
@@ -420,33 +441,43 @@ typedef struct {
#define BPB_NumFATsEx 110 /* exFAT: Number of FATs (BYTE) */
#define BPB_DrvNumEx 111 /* exFAT: Physical drive number for int13h (BYTE) */
#define BPB_PercInUseEx 112 /* exFAT: Percent in use (BYTE) */
+#define BPB_RsvdEx 113 /* exFAT: Reserved (7-byte) */
+#define BS_BootCodeEx 120 /* exFAT: Boot code (390-byte) */
#define FSI_LeadSig 0 /* FAT32 FSI: Leading signature (DWORD) */
#define FSI_StrucSig 484 /* FAT32 FSI: Structure signature (DWORD) */
#define FSI_Free_Count 488 /* FAT32 FSI: Number of free clusters (DWORD) */
#define FSI_Nxt_Free 492 /* FAT32 FSI: Last allocated cluster (DWORD) */
-#define MBR_Table 446 /* MBR: Partition table offset */
+#define MBR_Table 446 /* MBR: Offset of partition table in the MBR */
#define SZ_PTE 16 /* MBR: Size of a partition table entry */
+#define PTE_Boot 0 /* MBR PTE: Boot indicator */
+#define PTE_StHead 1 /* MBR PTE: Start head */
+#define PTE_StSec 2 /* MBR PTE: Start sector */
+#define PTE_StCyl 3 /* MBR PTE: Start cylinder */
+#define PTE_System 4 /* MBR PTE: System ID */
+#define PTE_EdHead 5 /* MBR PTE: End head */
+#define PTE_EdSec 6 /* MBR PTE: End sector */
+#define PTE_EdCyl 7 /* MBR PTE: End cylinder */
+#define PTE_StLba 8 /* MBR PTE: Start in LBA */
+#define PTE_SizLba 12 /* MBR PTE: Size in LBA */
#define BS_55AA 510 /* Signature word (WORD) */
-#define DIR_Name 0 /* Short file name (11) */
-#define DIR_Attr 11 /* Attribute (1) */
-#define DIR_NTres 12 /* Lower case flag (1) */
-#define DIR_CrtTime10 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_Name 0 /* Short file name (11-byte) */
+#define DIR_Attr 11 /* Attribute (BYTE) */
+#define DIR_NTres 12 /* Lower case flag (BYTE) */
+#define DIR_CrtTime10 13 /* Created time sub-second (BYTE) */
+#define DIR_CrtTime 14 /* Created time (DWORD) */
+#define DIR_LstAccDate 18 /* Last accessed date (WORD) */
#define DIR_FstClusHI 20 /* Higher 16-bit of first cluster (WORD) */
-#define DIR_WrtTime 22 /* Modified time (2) */
-#define DIR_WrtDate 24 /* Modified date (2) */
+#define DIR_ModTime 22 /* Modified time (DWORD) */
#define DIR_FstClusLO 26 /* Lower 16-bit of first cluster (WORD) */
#define DIR_FileSize 28 /* File size (DWORD) */
-#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 /* Checksum of the SFN entry */
+#define LDIR_Ord 0 /* LFN entry order and LLE flag (BYTE) */
+#define LDIR_Attr 11 /* LFN attribute (BYTE) */
+#define LDIR_Type 12 /* LFN type (BYTE) */
+#define LDIR_Chksum 13 /* Checksum of the SFN entry (BYTE) */
#define LDIR_FstClusLO 26 /* Must be zero (WORD) */
#define XDIR_Type 0 /* Type of exFAT directory entry (BYTE) */
#define XDIR_NumLabel 1 /* Number of volume label characters (BYTE) */
@@ -455,24 +486,24 @@ typedef struct {
#define XDIR_NumSec 1 /* Number of secondary entries (BYTE) */
#define XDIR_SetSum 2 /* Sum of the set of directory entries (WORD) */
#define XDIR_Attr 4 /* File attribute (WORD) */
-#define XDIR_CrtTime 8 /* Created time (4) */
-#define XDIR_ModTime 12 /* Modified time (4) */
-#define XDIR_AccTime 16 /* Last accessed time (4) */
-#define XDIR_CrtTime10 20 /* Created time subsecond (1) */
-#define XDIR_ModTime10 21 /* Modified time subsecond (1) */
-#define XDIR_CrtTZ 22 /* Created timezone (1) */
-#define XDIR_ModTZ 23 /* Modified timezone (1) */
-#define XDIR_AccTZ 24 /* Last accessed timezone (1) */
-#define XDIR_GenFlags 33 /* Gneral flags (1) */
+#define XDIR_CrtTime 8 /* Created time (DWORD) */
+#define XDIR_ModTime 12 /* Modified time (DWORD) */
+#define XDIR_AccTime 16 /* Last accessed time (DWORD) */
+#define XDIR_CrtTime10 20 /* Created time subsecond (BYTE) */
+#define XDIR_ModTime10 21 /* Modified time subsecond (BYTE) */
+#define XDIR_CrtTZ 22 /* Created timezone (BYTE) */
+#define XDIR_ModTZ 23 /* Modified timezone (BYTE) */
+#define XDIR_AccTZ 24 /* Last accessed timezone (BYTE) */
+#define XDIR_GenFlags 33 /* Gneral secondary flags (WORD) */
#define XDIR_NumName 35 /* Number of file name characters (BYTE) */
#define XDIR_NameHash 36 /* Hash of file name (WORD) */
#define XDIR_ValidFileSize 40 /* Valid file size (QWORD) */
-#define XDIR_FstClus 52 /* First cluster of the File/Directory (DWORD) */
+#define XDIR_FstClus 52 /* First cluster of the file data (DWORD) */
#define XDIR_FileSize 56 /* File/Directory size (QWORD) */
#define SZDIRE 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 DDEM 0xE5 /* Deleted directory entry mark set to DIR_Name[0] */
#define RDDEM 0x05 /* Replacement of the character collides with DDEM */
@@ -504,12 +535,9 @@ static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */
#endif
#if _USE_LFN == 0 /* Non-LFN configuration */
-#define DEF_NAMBUF BYTE sfn[12]
-#define INIT_NAMBUF(dobj) (dobj).fn = sfn
+#define DEF_NAMBUF
+#define INIT_NAMBUF(fs)
#define FREE_NAMBUF()
-#define DEF_DIRBUF
-#define INIT_DIRBUF(fs)
-#define FREE_DIRBUF()
#else
#if _MAX_LFN < 12 || _MAX_LFN > 255
#error Wrong _MAX_LFN setting
@@ -520,45 +548,30 @@ static FILESEM Files[_FS_LOCK]; /* Open object lock semaphores */
static BYTE DirBuf[SZDIRE*19]; /* Directory entry block scratchpad buffer (19 entries in size) */
#endif
static WCHAR LfnBuf[_MAX_LFN+1]; /* LFN enabled with static working buffer */
-#define DEF_NAMBUF BYTE sfn[12]
-#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = LfnBuf; }
+#define DEF_NAMBUF
+#define INIT_NAMBUF(fs)
#define FREE_NAMBUF()
-#define DEF_DIRBUF
-#define INIT_DIRBUF(fs)
-#define FREE_DIRBUF()
#elif _USE_LFN == 2 /* LFN enabled with dynamic working buffer on the stack */
#if _FS_EXFAT
-#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19]
-#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; (dj).obj.fs->dirbuf = dbuf; }
+#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1]; BYTE dbuf[SZDIRE*19];
+#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; (fs)->dirbuf = dbuf; }
#define FREE_NAMBUF()
-#define DEF_DIRBUF BYTE dbuf[SZDIRE*19]
-#define INIT_DIRBUF(fs) fs->dirbuf = dbuf
-#define FREE_DIRBUF()
#else
-#define DEF_NAMBUF BYTE sfn[12]; WCHAR lbuf[_MAX_LFN+1]
-#define INIT_NAMBUF(dj) { (dj).fn = sfn; (dj).lfn = lbuf; }
+#define DEF_NAMBUF WCHAR lbuf[_MAX_LFN+1];
+#define INIT_NAMBUF(fs) { (fs)->lfnbuf = lbuf; }
#define FREE_NAMBUF()
-#define DEF_DIRBUF
-#define INIT_DIRBUF(fs)
-#define FREE_DIRBUF()
#endif
#elif _USE_LFN == 3 /* LFN enabled with dynamic working buffer on the heap */
#if _FS_EXFAT
-#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn
-#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; (dj).obj.fs->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); }
+#define DEF_NAMBUF WCHAR *lfn;
+#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2 + SZDIRE*19); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; (fs)->dirbuf = (BYTE*)(lfn+_MAX_LFN+1); }
#define FREE_NAMBUF() ff_memfree(lfn)
-#define DEF_DIRBUF BYTE *dirb
-#define INIT_DIRBUF(fs) { dirb = ff_memalloc(SZDIRE*19); if (!dirb) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); fs->dirbuf = dirb; }
-#define FREE_DIRBUF() ff_memfree(dirb)
#else
-#define DEF_NAMBUF BYTE sfn[12]; WCHAR *lfn
-#define INIT_NAMBUF(dj) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF((dj).obj.fs, FR_NOT_ENOUGH_CORE); (dj).fn = sfn; (dj).lfn = lfn; }
+#define DEF_NAMBUF WCHAR *lfn;
+#define INIT_NAMBUF(fs) { lfn = ff_memalloc((_MAX_LFN+1)*2); if (!lfn) LEAVE_FF(fs, FR_NOT_ENOUGH_CORE); (fs)->lfnbuf = lfn; }
#define FREE_NAMBUF() ff_memfree(lfn)
-#define DEF_DIRBUF
-#define INIT_DIRBUF(fs)
-#define FREE_DIRBUF()
#endif
#else
@@ -707,10 +720,10 @@ int chk_chr (const char* str, int chr) { /* NZ:contained, ZR:not contained */
+#if _FS_REENTRANT
/*-----------------------------------------------------------------------*/
/* Request/Release grant to access the volume */
/*-----------------------------------------------------------------------*/
-#if _FS_REENTRANT
static
int lock_fs (
FATFS* fs /* File system object */
@@ -730,15 +743,15 @@ void unlock_fs (
ff_rel_grant(fs->sobj);
}
}
+
#endif
-
+#if _FS_LOCK != 0
/*-----------------------------------------------------------------------*/
/* File lock control functions */
/*-----------------------------------------------------------------------*/
-#if _FS_LOCK != 0
static
FRESULT chk_lock ( /* Check if the file can be accessed */
@@ -843,8 +856,8 @@ void clear_lock ( /* Clear lock entries of the volume */
if (Files[i].fs == fs) Files[i].fs = 0;
}
}
-#endif
+#endif /* _FS_LOCK != 0 */
@@ -908,10 +921,11 @@ FRESULT move_window ( /* Returns FR_OK or FR_DISK_ERROR */
+#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Synchronize file system and strage device */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
+
static
FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */
@@ -942,8 +956,8 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
return res;
}
-#endif
+#endif
@@ -993,17 +1007,17 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste
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);
+ val = (clst & 1) ? (wc >> 4) : (wc & 0xFFF);
break;
case FS_FAT16 :
if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 2))) != FR_OK) break;
- val = ld_word(&fs->win[clst * 2 % SS(fs)]);
+ val = ld_word(fs->win + clst * 2 % SS(fs));
break;
case FS_FAT32 :
if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
- val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x0FFFFFFF;
+ val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x0FFFFFFF;
break;
#if _FS_EXFAT
case FS_EXFAT :
@@ -1023,11 +1037,11 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste
}
if (obj->stat != 2) { /* Get value from FAT if FAT chain is valid */
if (move_window(fs, fs->fatbase + (clst / (SS(fs) / 4))) != FR_OK) break;
- val = ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0x7FFFFFFF;
+ val = ld_dword(fs->win + clst * 4 % SS(fs)) & 0x7FFFFFFF;
break;
}
}
- /* Go default */
+ /* go next */
#endif
default:
val = 1; /* Internal error */
@@ -1040,14 +1054,14 @@ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x7FFFFFFF:Cluste
+#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* FAT access - Change value of a FAT entry */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
static
FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
- FATFS* fs, /* Corresponding object */
+ FATFS* fs, /* Corresponding file system object */
DWORD clst, /* FAT index number (cluster number) to be changed */
DWORD val /* New value to be set to the entry */
)
@@ -1063,12 +1077,12 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
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 = 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 = fs->win + bc % SS(fs);
*p = (clst & 1) ? (BYTE)(val >> 4) : ((*p & 0xF0) | ((BYTE)(val >> 8) & 0x0F));
fs->wflag = 1;
break;
@@ -1076,7 +1090,7 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
case FS_FAT16 : /* WORD aligned items */
res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 2)));
if (res != FR_OK) break;
- st_word(&fs->win[clst * 2 % SS(fs)], (WORD)val);
+ st_word(fs->win + clst * 2 % SS(fs), (WORD)val);
fs->wflag = 1;
break;
@@ -1087,15 +1101,16 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
res = move_window(fs, fs->fatbase + (clst / (SS(fs) / 4)));
if (res != FR_OK) break;
if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) {
- val = (val & 0x0FFFFFFF) | (ld_dword(&fs->win[clst * 4 % SS(fs)]) & 0xF0000000);
+ val = (val & 0x0FFFFFFF) | (ld_dword(fs->win + clst * 4 % SS(fs)) & 0xF0000000);
}
- st_dword(&fs->win[clst * 4 % SS(fs)], val);
+ st_dword(fs->win + clst * 4 % SS(fs), val);
fs->wflag = 1;
break;
}
}
return res;
}
+
#endif /* !_FS_READONLY */
@@ -1109,6 +1124,7 @@ FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
/*---------------------------------------------*/
/* exFAT: Find a contiguous free cluster block */
/*---------------------------------------------*/
+
static
DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Disk error */
FATFS* fs, /* File system object */
@@ -1126,7 +1142,7 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis
scl = val = clst; ctr = 0;
for (;;) {
if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF;
- i = val / 8 & (SS(fs) - 1); bm = 1 << (val % 8);
+ i = val / 8 % SS(fs); bm = 1 << (val % 8);
do {
do {
bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */
@@ -1145,9 +1161,11 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis
}
}
+
/*------------------------------------*/
/* exFAT: Set/Clear a block of bitmap */
/*------------------------------------*/
+
static
FRESULT change_bitmap (
FATFS* fs, /* File system object */
@@ -1163,7 +1181,7 @@ FRESULT change_bitmap (
clst -= 2; /* The first bit corresponds to cluster #2 */
sect = fs->database + clst / 8 / SS(fs); /* Sector address */
- i = clst / 8 & (SS(fs) - 1); /* Byte offset in the sector */
+ i = clst / 8 % SS(fs); /* Byte offset in the sector */
bm = 1 << (clst % 8); /* Bit mask in the byte */
for (;;) {
if (move_window(fs, sect++) != FR_OK) return FR_DISK_ERR;
@@ -1176,6 +1194,7 @@ FRESULT change_bitmap (
} while (bm <<= 1); /* Next bit */
bm = 1;
} while (++i < SS(fs)); /* Next byte */
+ i = 0;
}
}
@@ -1183,6 +1202,7 @@ FRESULT change_bitmap (
/*---------------------------------------------*/
/* Complement contiguous part of the FAT chain */
/*---------------------------------------------*/
+
static
FRESULT fill_fat_chain (
_FDID* obj /* Pointer to the corresponding object */
@@ -1191,7 +1211,7 @@ FRESULT fill_fat_chain (
FRESULT res;
DWORD cl, n;
- if (obj->stat == 3) { /* Has the object got fragmented? */
+ if (obj->stat == 3) { /* Has the object been changed 'fragmented'? */
for (cl = obj->sclust, n = obj->n_cont; n; cl++, n--) { /* Create cluster chain on the FAT */
res = put_fat(obj->fs, cl, cl + 1);
if (res != FR_OK) return res;
@@ -1201,14 +1221,14 @@ FRESULT fill_fat_chain (
return FR_OK;
}
-#endif
+#endif /* _FS_EXFAT && !_FS_READONLY */
+#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* FAT handling - Remove a cluster chain */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
static
FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
_FDID* obj, /* Corresponding object */
@@ -1244,7 +1264,7 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
res = put_fat(fs, clst, 0); /* Mark the cluster 'free' on the FAT */
if (res != FR_OK) return res;
}
- if (fs->free_clst != 0xFFFFFFFF) { /* Update FSINFO */
+ if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */
fs->free_clst++;
fs->fsi_flag |= 1;
}
@@ -1282,7 +1302,6 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
#endif
return FR_OK;
}
-#endif
@@ -1290,7 +1309,6 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
/*-----------------------------------------------------------------------*/
/* FAT handling - Stretch a chain or Create a new chain */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
static
DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
_FDID* obj, /* Corresponding object */
@@ -1365,16 +1383,17 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err
return ncl; /* Return new cluster number or error status */
}
+
#endif /* !_FS_READONLY */
+#if _USE_FASTSEEK
/*-----------------------------------------------------------------------*/
/* 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 */
@@ -1395,10 +1414,12 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
}
return cl + *tbl; /* Return the cluster number */
}
+
#endif /* _USE_FASTSEEK */
+
/*-----------------------------------------------------------------------*/
/* Directory handling - Set directory index */
/*-----------------------------------------------------------------------*/
@@ -1509,7 +1530,7 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou
}
}
dp->dptr = ofs; /* Current entry */
- dp->dir = &fs->win[ofs % SS(fs)]; /* Pointer to the entry in the win[] */
+ dp->dir = fs->win + ofs % SS(fs); /* Pointer to the entry in the win[] */
return FR_OK;
}
@@ -1517,11 +1538,11 @@ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Cou
+#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Directory handling - Reserve a block of directory entries */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
static
FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to the directory object */
@@ -1540,7 +1561,7 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
res = move_window(fs, dp->sect);
if (res != FR_OK) break;
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {
+ if ((fs->fs_type == FS_EXFAT) ? (int)((dp->dir[XDIR_Type] & 0x80) == 0) : (int)(dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0)) {
#else
if (dp->dir[DIR_Name] == DDEM || dp->dir[DIR_Name] == 0) {
#endif
@@ -1555,7 +1576,8 @@ FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
if (res == FR_NO_FILE) res = FR_DENIED; /* No directory entry to allocate */
return res;
}
-#endif
+
+#endif /* !_FS_READONLY */
@@ -1598,14 +1620,14 @@ void st_clust (
-
+#if _USE_LFN != 0
/*------------------------------------------------------------------------*/
/* FAT-LFN: LFN handling */
/*------------------------------------------------------------------------*/
-#if _USE_LFN != 0
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 */
+
/*--------------------------------------------------------*/
/* FAT-LFN: Compare a part of file name with an LFN entry */
/*--------------------------------------------------------*/
@@ -1641,8 +1663,7 @@ int cmp_lfn ( /* 1:matched, 0:not matched */
}
-
-#if _FS_MINIMIZE <= 1 || _FS_EXFAT
+#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT
/*-----------------------------------------------------*/
/* FAT-LFN: Pick a part of file name from an LFN entry */
/*-----------------------------------------------------*/
@@ -1679,6 +1700,7 @@ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
}
#endif
+
#if !_FS_READONLY
/*-----------------------------------------*/
/* FAT-LFN: Create an entry of LFN entries */
@@ -1711,15 +1733,16 @@ void put_lfn (
dir[LDIR_Ord] = ord; /* Set the LFN order */
}
-#endif
-#endif
+#endif /* !_FS_READONLY */
+#endif /* _USE_LFN != 0 */
+#if _USE_LFN != 0 && !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* FAT-LFN: Create a Numbered SFN */
/*-----------------------------------------------------------------------*/
-#if _USE_LFN != 0 && !_FS_READONLY
+
static
void gen_numname (
BYTE* dst, /* Pointer to the buffer to store numbered SFN */
@@ -1770,14 +1793,15 @@ void gen_numname (
dst[j++] = (i < 8) ? ns[i++] : ' ';
} while (j < 8);
}
-#endif
+#endif /* _USE_LFN != 0 && !_FS_READONLY */
+#if _USE_LFN != 0
/*-----------------------------------------------------------------------*/
/* FAT-LFN: Calculate checksum of an SFN entry */
/*-----------------------------------------------------------------------*/
-#if _USE_LFN != 0
+
static
BYTE sum_sfn (
const BYTE* dir /* Pointer to the SFN entry */
@@ -1789,14 +1813,14 @@ BYTE sum_sfn (
do sum = (sum >> 1) + (sum << 7) + *dir++; while (--n);
return sum;
}
-#endif
+#endif /* _USE_LFN != 0 */
#if _FS_EXFAT
/*-----------------------------------------------------------------------*/
-/* exFAT: Directory handling - Load/Store a block of directory entries */
+/* exFAT: Checksum */
/*-----------------------------------------------------------------------*/
static
@@ -1839,17 +1863,35 @@ WORD xname_sum ( /* Get check sum (to be used as hash) of the name */
}
+#if !_FS_READONLY && _USE_MKFS
+static
+DWORD xsum32 (
+ BYTE dat, /* Data to be sumed */
+ DWORD sum /* Previous value */
+)
+{
+ sum = ((sum & 1) ? 0x80000000 : 0) + (sum >> 1) + dat;
+ return sum;
+}
+#endif
+
+
+#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
/*------------------------------------------------------*/
/* exFAT: Get object information from a directory block */
/*------------------------------------------------------*/
+
static
void get_xdir_info (
BYTE* dirb, /* Pointer to the direcotry entry block 85+C0+C1s */
FILINFO* fno /* Buffer to store the extracted file information */
)
{
- UINT di, si, nc;
+ UINT di, si;
WCHAR w;
+#if !_LFN_UNICODE
+ UINT nc;
+#endif
/* Get file name */
#if _LFN_UNICODE
@@ -1885,10 +1927,13 @@ void get_xdir_info (
fno->fdate = ld_word(dirb + XDIR_ModTime + 2); /* Date */
}
+#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
+
/*-----------------------------------*/
/* exFAT: Get a directry entry block */
/*-----------------------------------*/
+
static
FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
DIR* dp /* Pointer to the reading direcotry object pointing the 85 entry */
@@ -1903,7 +1948,7 @@ FRESULT load_xdir ( /* FR_INT_ERR: invalid entry block */
res = move_window(dp->obj.fs, dp->sect);
if (res != FR_OK) return res;
if (dp->dir[XDIR_Type] != 0x85) return FR_INT_ERR;
- mem_cpy(&dirb[0], dp->dir, SZDIRE);
+ mem_cpy(dirb, dp->dir, SZDIRE);
nent = dirb[XDIR_NumSec] + 1;
/* Load C0 entry */
@@ -1974,16 +2019,17 @@ FRESULT store_xdir (
{
FRESULT res;
UINT nent;
- WORD sum;
BYTE* dirb = dp->obj.fs->dirbuf; /* Pointer to the direcotry entry block 85+C0+C1s */
/* Create set sum */
- sum = xdir_sum(dirb);
- st_word(dirb + XDIR_SetSum, sum);
+ st_word(dirb + XDIR_SetSum, xdir_sum(dirb));
nent = dirb[XDIR_NumSec] + 1;
+ /* Store the set of directory to the volume */
res = dir_sdi(dp, dp->blk_ofs);
- while (res == FR_OK && (res = move_window(dp->obj.fs, dp->sect)) == FR_OK) {
+ while (res == FR_OK) {
+ res = move_window(dp->obj.fs, dp->sect);
+ if (res != FR_OK) break;
mem_cpy(dp->dir, dirb, SZDIRE);
dp->obj.fs->wflag = 1;
if (--nent == 0) break;
@@ -1994,9 +2040,11 @@ FRESULT store_xdir (
}
+
/*-------------------------------------------*/
/* exFAT: Create a new directory enrty block */
/*-------------------------------------------*/
+
static
void create_xdir (
BYTE* dirb, /* Pointer to the direcotry entry block buffer */
@@ -2006,14 +2054,12 @@ void create_xdir (
UINT i;
BYTE nb, nc;
WCHAR chr;
- WORD hash;
mem_set(dirb, 0, 2 * SZDIRE); /* Initialize 85+C0 entry */
dirb[XDIR_Type] = 0x85;
dirb[XDIR_Type + SZDIRE] = 0xC0;
- hash = xname_sum(lfn);
- st_word(dirb + XDIR_NameHash, hash); /* Set name hash */
+ st_word(dirb + XDIR_NameHash, xname_sum(lfn)); /* Set name hash */
i = SZDIRE * 2; /* C1 offset */
nc = 0; nb = 1; chr = 1;
@@ -2029,15 +2075,17 @@ void create_xdir (
dirb[XDIR_NumName] = nc; /* Set name length */
dirb[XDIR_NumSec] = nb; /* Set number of C0+C1s */
}
-#endif
-#endif
+
+#endif /* !_FS_READONLY */
+#endif /* _FS_EXFAT */
+#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT
/*-----------------------------------------------------------------------*/
/* Read an object from the directory */
/*-----------------------------------------------------------------------*/
-#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 || _USE_LABEL || _FS_EXFAT
+
static
FRESULT dir_read (
DIR* dp, /* Pointer to the directory object */
@@ -2061,8 +2109,8 @@ FRESULT dir_read (
if (_USE_LABEL && vol) {
if (c == 0x83) break; /* Volume label entry? */
} else {
- if (c == 0x85) { /* Start of the entry block? */
- dp->blk_ofs = dp->dptr; /* Set location of block */
+ if (c == 0x85) { /* Start of the file entry block? */
+ dp->blk_ofs = dp->dptr; /* Get location of the block */
res = load_xdir(dp); /* Load the entry block */
if (res == FR_OK) {
dp->obj.attr = fs->dirbuf[XDIR_Attr] & AM_MASK; /* Get attribute */
@@ -2085,7 +2133,7 @@ FRESULT dir_read (
dp->blk_ofs = dp->dptr;
}
/* Check LFN validity and capture it */
- ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF;
+ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && pick_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
} else { /* An SFN entry is found */
if (ord || sum != sum_sfn(dp->dir)) { /* Is there a valid LFN? */
dp->blk_ofs = 0xFFFFFFFF; /* It has no LFN. */
@@ -2106,6 +2154,7 @@ FRESULT dir_read (
if (res != FR_OK) dp->sect = 0; /* Terminate the read operation on error or EOT */
return res;
}
+
#endif /* _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 */
@@ -2132,15 +2181,15 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
BYTE nc;
UINT di, ni;
- WORD hash = xname_sum(dp->lfn); /* Hash value of the name to find */
+ WORD hash = xname_sum(fs->lfnbuf); /* Hash value of the name to find */
while ((res = dir_read(dp, 0)) == FR_OK) { /* Read an item */
if (ld_word(fs->dirbuf + XDIR_NameHash) != hash) continue; /* Skip the comparison if hash value mismatched */
for (nc = fs->dirbuf[XDIR_NumName], di = SZDIRE * 2, ni = 0; nc; nc--, di += 2, ni++) { /* Compare the name */
if ((di % SZDIRE) == 0) di += 2;
- if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(dp->lfn[ni])) break;
+ if (ff_wtoupper(ld_word(fs->dirbuf + di)) != ff_wtoupper(fs->lfnbuf[ni])) break;
}
- if (nc == 0 && !dp->lfn[ni]) break; /* Name matched? */
+ if (nc == 0 && !fs->lfnbuf[ni]) break; /* Name matched? */
}
return res;
}
@@ -2160,14 +2209,14 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
ord = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */
} else {
if (a == AM_LFN) { /* An LFN entry is found */
- if (dp->lfn) {
+ if (!(dp->fn[NSFLAG] & NS_NOLFN)) {
if (c & LLEF) { /* Is it start of LFN sequence? */
sum = dp->dir[LDIR_Chksum];
c &= ~LLEF; ord = c; /* LFN start order */
dp->blk_ofs = dp->dptr; /* Start offset of LFN */
}
/* Check validity of the LFN entry and compare it with given name */
- ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(dp->lfn, dp->dir)) ? ord - 1 : 0xFF;
+ ord = (c == ord && sum == dp->dir[LDIR_Chksum] && cmp_lfn(fs->lfnbuf, dp->dir)) ? ord - 1 : 0xFF;
}
} else { /* An SFN entry is found */
if (!ord && sum == sum_sfn(dp->dir)) break; /* LFN matched? */
@@ -2188,10 +2237,11 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
+#if !_FS_READONLY
/*-----------------------------------------------------------------------*/
/* Register an object to the directory */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY
+
static
FRESULT dir_register ( /* FR_OK:succeeded, 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 */
@@ -2201,13 +2251,11 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
FATFS *fs = dp->obj.fs;
#if _USE_LFN != 0 /* LFN configuration */
UINT n, nlen, nent;
- BYTE sn[12], *fn, sum;
- WCHAR *lfn;
+ BYTE sn[12], sum;
- fn = dp->fn; lfn = dp->lfn;
- if (fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */
- for (nlen = 0; lfn[nlen]; nlen++) ; /* Get lfn length */
+ if (dp->fn[NSFLAG] & (NS_DOT | NS_NONAME)) return FR_INVALID_NAME; /* Check name validity */
+ for (nlen = 0; fs->lfnbuf[nlen]; nlen++) ; /* Get lfn length */
#if _FS_EXFAT
if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
@@ -2232,22 +2280,22 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
if (res != FR_OK) return res;
}
- create_xdir(fs->dirbuf, lfn); /* Create on-memory directory block to be written later */
+ create_xdir(fs->dirbuf, fs->lfnbuf); /* Create on-memory directory block to be written later */
return FR_OK;
}
#endif
/* At the FAT12/16/32 */
- mem_cpy(sn, fn, 12);
+ mem_cpy(sn, dp->fn, 12);
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 */
+ dp->fn[NSFLAG] = NS_NOLFN; /* Find only SFN */
for (n = 1; n < 100; n++) {
- gen_numname(fn, sn, lfn, n); /* Generate a numbered name */
+ gen_numname(dp->fn, sn, fs->lfnbuf, 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;
+ dp->fn[NSFLAG] = sn[NSFLAG];
}
/* Create an SFN with/without LFNs. */
@@ -2260,7 +2308,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
do { /* Store LFN entries in bottom first */
res = move_window(fs, dp->sect);
if (res != FR_OK) break;
- put_lfn(dp->lfn, dp->dir, (BYTE)nent, sum);
+ put_lfn(fs->lfnbuf, dp->dir, (BYTE)nent, sum);
fs->wflag = 1;
res = dir_next(dp, 0); /* Next entry */
} while (res == FR_OK && --nent);
@@ -2287,15 +2335,16 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
return res;
}
+
#endif /* !_FS_READONLY */
-
+#if !_FS_READONLY && _FS_MINIMIZE == 0
/*-----------------------------------------------------------------------*/
/* Remove an object from the directory */
/*-----------------------------------------------------------------------*/
-#if !_FS_READONLY && !_FS_MINIMIZE
+
static
FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
DIR* dp /* Directory object pointing the entry to be removed */
@@ -2306,7 +2355,7 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
#if _USE_LFN != 0 /* LFN configuration */
DWORD last = dp->dptr;
- res = dp->blk_ofs == 0xFFFFFFFF ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */
+ res = (dp->blk_ofs == 0xFFFFFFFF) ? FR_OK : dir_sdi(dp, dp->blk_ofs); /* Goto top of the entry block if LFN is exist */
if (res == FR_OK) {
do {
res = move_window(fs, dp->sect);
@@ -2334,15 +2383,16 @@ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
return res;
}
-#endif /* !_FS_READONLY */
-
+
+#endif /* !_FS_READONLY && _FS_MINIMIZE == 0 */
+#if _FS_MINIMIZE <= 1 || _FS_RPATH >= 2
/*-----------------------------------------------------------------------*/
/* 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 */
@@ -2351,9 +2401,10 @@ void get_fileinfo ( /* No return code */
{
UINT i, j;
TCHAR c;
+ DWORD tm;
#if _USE_LFN != 0
- WCHAR w, *lfn;
- WCHAR lfv;
+ WCHAR w, lfv;
+ FATFS *fs = dp->obj.fs;
#endif
@@ -2362,15 +2413,15 @@ void get_fileinfo ( /* No return code */
#if _USE_LFN != 0 /* LFN configuration */
#if _FS_EXFAT
- if (dp->obj.fs->fs_type == FS_EXFAT) { /* At the exFAT */
- get_xdir_info(dp->obj.fs->dirbuf, fno);
+ if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ get_xdir_info(fs->dirbuf, fno);
return;
} else
#endif
{ /* At the FAT12/16/32 */
if (dp->blk_ofs != 0xFFFFFFFF) { /* Get LFN if available */
- i = 0; lfn = dp->lfn;
- while ((w = *lfn++) != 0) { /* Get an LFN character */
+ i = j = 0;
+ while ((w = fs->lfnbuf[j++]) != 0) { /* Get an LFN character */
#if !_LFN_UNICODE
w = ff_convert(w, 0); /* Unicode -> OEM */
if (w == 0) { i = 0; break; } /* No LFN if it could not be converted */
@@ -2431,18 +2482,19 @@ void get_fileinfo ( /* No return code */
fno->fattrib = dp->dir[DIR_Attr]; /* Attribute */
fno->fsize = ld_dword(dp->dir + DIR_FileSize); /* Size */
- fno->fdate = ld_word(dp->dir + DIR_WrtDate); /* Date */
- fno->ftime = ld_word(dp->dir + DIR_WrtTime); /* Time */
+ tm = ld_dword(dp->dir + DIR_ModTime); /* Timestamp */
+ fno->ftime = (WORD)tm; fno->fdate = (WORD)(tm >> 16);
}
+
#endif /* _FS_MINIMIZE <= 1 || _FS_RPATH >= 2 */
-
+#if _USE_FIND && _FS_MINIMIZE <= 1
/*-----------------------------------------------------------------------*/
/* 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 */
@@ -2493,7 +2545,7 @@ int pattern_matching ( /* 0:not matched, 1:matched */
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 (recursions upto number of wildcard blocks in the pattern) */
+ 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 */
@@ -2506,8 +2558,8 @@ int pattern_matching ( /* 0:not matched, 1:matched */
return 0;
}
-#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */
+#endif /* _USE_FIND && _FS_MINIMIZE <= 1 */
@@ -2528,11 +2580,12 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
const TCHAR *p;
/* Create LFN in Unicode */
- p = *path; lfn = dp->lfn; si = di = 0;
+ p = *path; lfn = dp->obj.fs->lfnbuf; si = di = 0;
for (;;) {
w = p[si++]; /* Get a character */
- if (w < ' ' || w == '/' || w == '\\') { /* Break on end of segment */
- while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */
+ if (w < ' ') break; /* Break if end of the path name */
+ if (w == '/' || w == '\\') { /* Break if a separator is found */
+ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */
break;
}
if (di >= _MAX_LFN) return FR_INVALID_NAME; /* Reject too long name */
@@ -2550,7 +2603,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
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 */
+ cf = (w < ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
#if _FS_RPATH != 0
if ((di == 1 && lfn[di - 1] == '.') ||
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot name? */
@@ -2638,15 +2691,15 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
return FR_OK;
-#else /* Non-LFN configuration */
- BYTE b, c, d, *sfn;
+#else /* _USE_LFN != 0 : Non-LFN configuration */
+ BYTE c, d, *sfn;
UINT ni, si, i;
const char *p;
/* Create file name in directory form */
p = *path; sfn = dp->fn;
mem_set(sfn, ' ', 11);
- si = i = b = 0; ni = 8;
+ si = i = 0; ni = 8;
#if _FS_RPATH != 0
if (p[si] == '.') { /* Is this a dot entry? */
for (;;) {
@@ -2655,29 +2708,29 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
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 */
+ *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 the path */
return FR_OK;
}
#endif
for (;;) {
c = (BYTE)p[si++];
- if (c <= ' ' || c == '/' || c == '\\') { /* Break on end of segment */
- while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator */
+ if (c <= ' ') break; /* Break if end of the path name */
+ if (c == '/' || c == '\\') { /* Break if a separator is found */
+ while (p[si] == '/' || p[si] == '\\') si++; /* Skip duplicated separator if exist */
break;
}
- if (c == '.' || i >= ni) {
- if (ni != 8 || c != '.') return FR_INVALID_NAME;
- i = 8; ni = 11;
- b <<= 2; continue;
+ if (c == '.' || i >= ni) { /* End of body or over size? */
+ if (ni == 11 || c != '.') return FR_INVALID_NAME; /* Over size or invalid dot */
+ i = 8; ni = 11; /* Goto extension */
+ 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) */
+ return FR_INVALID_NAME; /* Reject extended characters (ASCII only cfg) */
#endif
#endif
}
@@ -2688,30 +2741,18 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
sfn[i++] = d;
} else { /* SBC */
if (chk_chr("\"*+,:;<=>\?[]|\x7F", c)) return FR_INVALID_NAME; /* Reject illegal chrs for SFN */
- if (IsUpper(c)) { /* ASCII large capital? */
- b |= 2;
- } else {
- if (IsLower(c)) { /* ASCII small capital? */
- b |= 1; c -= 0x20;
- }
- }
+ if (IsLower(c)) c -= 0x20; /* To upper */
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 */
-
+ *path = p + si; /* Return pointer to the next segment */
if (i == 0) 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 */
+ if (sfn[0] == DDEM) sfn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
+ sfn[NSFLAG] = (c <= ' ') ? NS_LAST : 0; /* Set last segment flag if end of the path */
return FR_OK;
-#endif
+#endif /* _USE_LFN != 0 */
}
@@ -2794,7 +2835,7 @@ FRESULT follow_path ( /* FR_OK(0): successful, !=0: error code */
} else
#endif
{
- obj->sclust = ld_clust(fs, &fs->win[dp->dptr % SS(fs)]); /* Open next directory */
+ obj->sclust = ld_clust(fs, fs->win + dp->dptr % SS(fs)); /* Open next directory */
}
}
}
@@ -2873,18 +2914,20 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
static
BYTE check_fs ( /* 0:FAT, 1:exFAT, 2:Valid BS but not FAT, 3:Not a BS, 4:Disk error */
FATFS* fs, /* File system object */
- DWORD sect /* Sector# (lba) to check if it is an FAT boot record or not */
+ DWORD sect /* Sector# (lba) to check if it is an FAT-VBR or not */
)
{
fs->wflag = 0; fs->winsect = 0xFFFFFFFF; /* Invaidate window */
if (move_window(fs, sect) != FR_OK) return 4; /* Load boot record */
- if (ld_word(&fs->win[BS_55AA]) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
+ if (ld_word(fs->win + BS_55AA) != 0xAA55) return 3; /* Check boot record signature (always placed at offset 510 even if the sector size is >512) */
- if ((ld_dword(&fs->win[BS_FilSysType]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */
- if ((ld_dword(&fs->win[BS_FilSysType32]) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */
+ if (fs->win[BS_JmpBoot] == 0xE9 || (fs->win[BS_JmpBoot] == 0xEB && fs->win[BS_JmpBoot + 2] == 0x90)) {
+ if ((ld_dword(fs->win + BS_FilSysType) & 0xFFFFFF) == 0x544146) return 0; /* Check "FAT" string */
+ if (ld_dword(fs->win + BS_FilSysType32) == 0x33544146) return 0; /* Check "FAT3" string */
+ }
#if _FS_EXFAT
- if (!mem_cmp(&fs->win[BS_OEMName], "EXFAT ", 8)) return 1;
+ if (!mem_cmp(fs->win + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11)) return 1;
#endif
return 2;
}
@@ -2948,16 +2991,16 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
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;
+ if (disk_ioctl(fs->drv, GET_SECTOR_SIZE, &SS(fs)) != RES_OK) return FR_DISK_ERR;
+ if (SS(fs) > _MAX_SS || SS(fs) < _MIN_SS || (SS(fs) & (SS(fs) - 1))) 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 == 2 || (fmt < 2 && LD2PT(vol))) { /* Not an FAT boot sector or forced partition number */
+ fmt = check_fs(fs, bsect); /* Load sector 0 and check if it is an FAT-VBR as SFD */
+ if (fmt == 2 || (fmt < 2 && LD2PT(vol) != 0)) { /* Not an FAT-VBR 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;
+ pt = fs->win + (MBR_Table + i * SZ_PTE);
+ br[i] = pt[PTE_System] ? ld_dword(pt + PTE_StLba) : 0;
}
i = LD2PT(vol); /* Partition number: 0:auto, 1-4:forced */
if (i) i--;
@@ -2975,7 +3018,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
if (fmt == 1) {
QWORD maxlba;
- for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && !fs->win[i]; i++) ; /* Check zero filler */
+ for (i = BPB_ZeroedEx; i < BPB_ZeroedEx + 53 && fs->win[i] == 0; i++) ; /* Check zero filler */
if (i < BPB_ZeroedEx + 53) return FR_NO_FILESYSTEM;
if (ld_word(fs->win + BPB_FSVerEx) != 0x100) return FR_NO_FILESYSTEM; /* Check exFAT revision (Must be 1.0) */
@@ -2983,20 +3026,20 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
if (1 << fs->win[BPB_BytsPerSecEx] != SS(fs)) /* (BPB_BytsPerSecEx must be equal to the physical sector size) */
return FR_NO_FILESYSTEM;
- maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Number of sectors on the volume */
+ maxlba = ld_qword(fs->win + BPB_TotSecEx) + bsect; /* Last LBA + 1 of the volume */
if (maxlba >= 0x100000000) return FR_NO_FILESYSTEM; /* (It cannot be handled in 32-bit LBA) */
fs->fsize = ld_dword(fs->win + BPB_FatSzEx); /* Number of sectors per FAT */
fs->n_fats = fs->win[BPB_NumFATsEx]; /* Number of FATs */
- if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Must be 1) */
+ if (fs->n_fats != 1) return FR_NO_FILESYSTEM; /* (Supports only 1 FAT) */
fs->csize = 1 << fs->win[BPB_SecPerClusEx]; /* Cluster size */
if (fs->csize == 0) return FR_NO_FILESYSTEM; /* (Must be 1..32768) */
nclst = ld_dword(fs->win + BPB_NumClusEx); /* Number of clusters */
+ if (nclst > MAX_EXFAT) return FR_NO_FILESYSTEM; /* (Too many clusters) */
fs->n_fatent = nclst + 2;
- if (fs->n_fatent >= 0x80000000) return FR_NO_FILESYSTEM; /* (Must be <= 0x7FFFFFFF) */
/* Boundaries and Limits */
fs->volbase = bsect;
@@ -3013,13 +3056,10 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
if (i == SS(fs)) return FR_NO_FILESYSTEM;
#if !_FS_READONLY
fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
-#endif
-#if _USE_LFN == 1
- fs->dirbuf = DirBuf; /* Static directory block working buuffer */
#endif
fmt = FS_EXFAT; /* FAT sub-type */
} else
-#endif
+#endif /* _FS_EXFAT */
{
if (ld_word(fs->win + BPB_BytsPerSec) != SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_BytsPerSec must be equal to the physical sector size) */
@@ -3048,9 +3088,9 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
if (tsect < sysect) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
nclst = (tsect - sysect) / fs->csize; /* Number of clusters */
if (nclst == 0) return FR_NO_FILESYSTEM; /* (Invalid volume size) */
- fmt = FS_FAT12;
- if (nclst >= MIN_FAT16) fmt = FS_FAT16;
- if (nclst >= MIN_FAT32) fmt = FS_FAT32;
+ fmt = FS_FAT32;
+ if (nclst <= MAX_FAT16) fmt = FS_FAT16;
+ if (nclst <= MAX_FAT12) fmt = FS_FAT12;
/* Boundaries and Limits */
fs->n_fatent = nclst + 2; /* Number of FAT entries */
@@ -3071,10 +3111,8 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
if (fs->fsize < (szbfat + (SS(fs) - 1)) / SS(fs)) return FR_NO_FILESYSTEM; /* (BPB_FATSz must not be less than the size needed) */
#if !_FS_READONLY
- /* Initialize cluster allocation information */
- fs->last_clst = fs->free_clst = 0xFFFFFFFF;
-
/* Get FSINFO if available */
+ fs->last_clst = fs->free_clst = 0xFFFFFFFF; /* Initialize cluster allocation information */
fs->fsi_flag = 0x80;
#if (_FS_NOFSINFO & 3) != 3
if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo32 == 1 */
@@ -3094,12 +3132,18 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
#endif
}
}
-#endif
-#endif
+#endif /* (_FS_NOFSINFO & 3) != 3 */
+#endif /* !_FS_READONLY */
}
fs->fs_type = fmt; /* FAT sub-type */
fs->id = ++Fsid; /* File system mount ID */
+#if _USE_LFN == 1
+ fs->lfnbuf = LfnBuf; /* Static LFN working buffer */
+#if _FS_EXFAT
+ fs->dirbuf = DirBuf; /* Static directory block working buuffer */
+#endif
+#endif
#if _FS_RPATH != 0
fs->cdir = 0; /* Initialize current directory */
#endif
@@ -3209,20 +3253,20 @@ FRESULT f_open (
DIR dj;
FATFS *fs;
#if !_FS_READONLY
- DWORD dw, cl;
+ DWORD dw, cl, bcs, clst, sc;
+ FSIZE_t ofs;
#endif
- DEF_NAMBUF;
+ DEF_NAMBUF
if (!fp) return FR_INVALID_OBJECT;
- fp->obj.fs = 0; /* Clear file object */
/* Get logical drive number */
- mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_OPEN_ALWAYS | FA_CREATE_NEW;
+ mode &= _FS_READONLY ? FA_READ : FA_READ | FA_WRITE | FA_CREATE_ALWAYS | FA_CREATE_NEW | FA_OPEN_ALWAYS | FA_OPEN_APPEND | FA_SEEKEND;
res = find_volume(&path, &fs, mode);
if (res == FR_OK) {
dj.obj.fs = fs;
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
#if !_FS_READONLY /* R/W configuration */
if (res == FR_OK) {
@@ -3282,7 +3326,7 @@ FRESULT f_open (
{
/* Clean directory info */
st_dword(dj.dir + DIR_CrtTime, dw); /* Set created time */
- st_dword(dj.dir + DIR_WrtTime, dw); /* Set modified time */
+ st_dword(dj.dir + DIR_ModTime, dw); /* Set modified time */
dj.dir[DIR_Attr] = AM_ARC; /* Reset attribute */
cl = ld_clust(fs, dj.dir); /* Get cluster chain */
st_clust(fs, dj.dir, 0); /* Reset file allocation info */
@@ -3313,7 +3357,7 @@ FRESULT f_open (
}
if (res == FR_OK) {
if (mode & FA_CREATE_ALWAYS) /* Set file change flag if created or overwritten */
- mode |= _FA_MODIFIED;
+ mode |= FA_MODIFIED;
fp->dir_sect = fs->winsect; /* Pointer to the directory entry */
fp->dir_ptr = dj.dir;
#if _FS_LOCK != 0
@@ -3349,20 +3393,48 @@ FRESULT f_open (
fp->obj.objsize = ld_dword(dj.dir + DIR_FileSize);
}
#if _USE_FASTSEEK
- fp->cltbl = 0; /* Normal seek mode */
+ fp->cltbl = 0; /* Disable fast seek mode */
#endif
- fp->err = 0; /* Clear error flag */
- fp->fptr = 0; /* Set file pointer */
- fp->sect = 0; /* Invalidate current data sector */
- fp->flag = mode; /* File access mode */
fp->obj.fs = fs; /* Validate the file object */
fp->obj.id = fs->id;
+ fp->flag = mode; /* Set file access mode */
+ fp->err = 0; /* Clear error flag */
+ fp->sect = 0; /* Invalidate current data sector */
+ fp->fptr = 0; /* Set file pointer top of the file */
+#if !_FS_READONLY
+#if !_FS_TINY
+ mem_set(fp->buf, 0, _MAX_SS); /* Clear sector buffer */
+#endif
+ if ((mode & FA_SEEKEND) && fp->obj.objsize > 0) { /* Seek to end of file if FA_OPEN_APPEND is specified */
+ fp->fptr = fp->obj.objsize; /* Offset to seek */
+ bcs = (DWORD)fs->csize * SS(fs); /* Cluster size in byte */
+ clst = fp->obj.sclust; /* Follow the cluster chain */
+ for (ofs = fp->obj.objsize; res == FR_OK && ofs > bcs; ofs -= bcs) {
+ clst = get_fat(&fp->obj, clst);
+ if (clst <= 1) res = FR_INT_ERR;
+ if (clst == 0xFFFFFFFF) res = FR_DISK_ERR;
+ }
+ fp->clust = clst;
+ if (res == FR_OK && ofs % SS(fs)) { /* Fill sector buffer if not on the sector boundary */
+ if ((sc = clust2sect(fs, clst)) == 0) {
+ res = FR_INT_ERR;
+ } else {
+ fp->sect = sc + (DWORD)(ofs / SS(fs));
+#if !_FS_TINY
+ if (disk_read(fs->drv, fp->buf, fp->sect, 1) != RES_OK) res = FR_DISK_ERR;
+#endif
+ }
+ }
+ }
+#endif
}
FREE_NAMBUF();
}
- LEAVE_FF(dj.obj.fs, res);
+ if (res != FR_OK) fp->obj.fs = 0; /* Invalidate file object on error */
+
+ LEAVE_FF(fs, res);
}
@@ -3396,7 +3468,7 @@ FRESULT f_read (
for ( ; btr; /* Repeat until all data read */
rbuff += rcnt, fp->fptr += rcnt, *br += rcnt, btr -= rcnt) {
- if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */
+ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */
csect = (UINT)(fp->fptr / SS(fs) & (fs->csize - 1)); /* Sector offset in the cluster */
if (csect == 0) { /* On the cluster boundary? */
if (fp->fptr == 0) { /* On the top of the file? */
@@ -3432,7 +3504,7 @@ FRESULT f_read (
mem_cpy(rbuff + ((fs->winsect - sect) * SS(fs)), fs->win, SS(fs));
}
#else
- if ((fp->flag & _FA_DIRTY) && fp->sect - sect < cc) {
+ if ((fp->flag & FA_DIRTY) && fp->sect - sect < cc) {
mem_cpy(rbuff + ((fp->sect - sect) * SS(fs)), fp->buf, SS(fs));
}
#endif
@@ -3443,11 +3515,9 @@ FRESULT f_read (
#if !_FS_TINY
if (fp->sect != sect) { /* Load data sector if not in cache */
#if !_FS_READONLY
- if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */
- if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
- fp->flag &= ~_FA_DIRTY;
+ if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
+ fp->flag &= ~FA_DIRTY;
}
#endif
if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */
@@ -3457,15 +3527,13 @@ FRESULT f_read (
#endif
fp->sect = sect;
}
- rcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Get partial sector data from sector buffer */
- if (rcnt > btr) rcnt = btr;
+ rcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */
+ if (rcnt > btr) rcnt = btr; /* Clip it by btr if needed */
#if _FS_TINY
- if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */
- ABORT(fs, FR_DISK_ERR);
- }
- mem_cpy(rbuff, &fs->win[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */
+ if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
+ mem_cpy(rbuff, fs->win + fp->fptr % SS(fs), rcnt); /* Extract partial sector */
#else
- mem_cpy(rbuff, &fp->buf[fp->fptr % SS(fs)], rcnt); /* Pick partial sector */
+ mem_cpy(rbuff, fp->buf + fp->fptr % SS(fs), rcnt); /* Extract partial sector */
#endif
}
@@ -3499,15 +3567,14 @@ FRESULT f_write (
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
- /* Check fptr wrap-around (file size cannot exceed the limit on each FAT specs) */
- if ((_FS_EXFAT && fs->fs_type == FS_EXFAT && fp->fptr + btw < fp->fptr)
- || (DWORD)fp->fptr + btw < (DWORD)fp->fptr) {
+ /* Check fptr wrap-around (file size cannot reach 4GiB on FATxx) */
+ if ((!_FS_EXFAT || fs->fs_type != FS_EXFAT) && (DWORD)(fp->fptr + btw) < (DWORD)fp->fptr) {
btw = (UINT)(0xFFFFFFFF - (DWORD)fp->fptr);
}
for ( ; btw; /* Repeat until all data written */
wbuff += wcnt, fp->fptr += wcnt, fp->obj.objsize = (fp->fptr > fp->obj.objsize) ? fp->fptr : fp->obj.objsize, *bw += wcnt, btw -= wcnt) {
- if ((fp->fptr % SS(fs)) == 0) { /* On the sector boundary? */
+ if (fp->fptr % SS(fs) == 0) { /* On the sector boundary? */
csect = (UINT)(fp->fptr / SS(fs)) & (fs->csize - 1); /* Sector offset in the cluster */
if (csect == 0) { /* On the cluster boundary? */
if (fp->fptr == 0) { /* On the top of the file? */
@@ -3532,15 +3599,11 @@ FRESULT f_write (
if (fp->obj.sclust == 0) fp->obj.sclust = clst; /* Set start cluster if the first write */
}
#if _FS_TINY
- if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) { /* Write-back sector cache */
- ABORT(fs, FR_DISK_ERR);
- }
+ if (fs->winsect == fp->sect && sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Write-back sector cache */
#else
- if (fp->flag & _FA_DIRTY) { /* Write-back sector cache */
- if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
- fp->flag &= ~_FA_DIRTY;
+ if (fp->flag & FA_DIRTY) { /* Write-back sector cache */
+ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
+ fp->flag &= ~FA_DIRTY;
}
#endif
sect = clust2sect(fs, fp->clust); /* Get current sector */
@@ -3563,7 +3626,7 @@ FRESULT f_write (
#else
if (fp->sect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
mem_cpy(fp->buf, wbuff + ((fp->sect - sect) * SS(fs)), SS(fs));
- fp->flag &= ~_FA_DIRTY;
+ fp->flag &= ~FA_DIRTY;
}
#endif
#endif
@@ -3585,21 +3648,19 @@ FRESULT f_write (
#endif
fp->sect = sect;
}
- wcnt = SS(fs) - ((UINT)fp->fptr % SS(fs)); /* Put partial sector into file I/O buffer */
- if (wcnt > btw) wcnt = btw;
+ wcnt = SS(fs) - (UINT)fp->fptr % SS(fs); /* Number of bytes left in the sector */
+ if (wcnt > btw) wcnt = btw; /* Clip it by btw if needed */
#if _FS_TINY
- if (move_window(fs, fp->sect) != FR_OK) { /* Move sector window */
- ABORT(fs, FR_DISK_ERR);
- }
- mem_cpy(&fs->win[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */
+ if (move_window(fs, fp->sect) != FR_OK) ABORT(fs, FR_DISK_ERR); /* Move sector window */
+ mem_cpy(fs->win + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */
fs->wflag = 1;
#else
- mem_cpy(&fp->buf[fp->fptr % SS(fs)], wbuff, wcnt); /* Fit partial sector */
- fp->flag |= _FA_DIRTY;
+ mem_cpy(fp->buf + fp->fptr % SS(fs), wbuff, wcnt); /* Fit data to the sector */
+ fp->flag |= FA_DIRTY;
#endif
}
- fp->flag |= _FA_MODIFIED; /* Set file change flag */
+ fp->flag |= FA_MODIFIED; /* Set file change flag */
LEAVE_FF(fs, FR_OK);
}
@@ -3619,18 +3680,15 @@ FRESULT f_sync (
FATFS *fs;
DWORD tm;
BYTE *dir;
- DEF_DIRBUF;
res = validate(fp, &fs); /* Check validity of the object */
if (res == FR_OK) {
- if (fp->flag & _FA_MODIFIED) { /* Is there any change to the file? */
+ if (fp->flag & FA_MODIFIED) { /* Is there any change to the file? */
#if !_FS_TINY
- if (fp->flag & _FA_DIRTY) { /* Write-back cached data if needed */
- if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
- LEAVE_FF(fs, FR_DISK_ERR);
- }
- fp->flag &= ~_FA_DIRTY;
+ if (fp->flag & FA_DIRTY) { /* Write-back cached data if needed */
+ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) LEAVE_FF(fs, FR_DISK_ERR);
+ fp->flag &= ~FA_DIRTY;
}
#endif
/* Update the directory entry */
@@ -3641,24 +3699,24 @@ FRESULT f_sync (
if (res == FR_OK) {
DIR dj;
- INIT_DIRBUF(fs);
+ INIT_NAMBUF(fs);
res = load_obj_dir(&dj, &fp->obj); /* Load directory entry block */
if (res == FR_OK) {
- fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */
- fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */
+ fs->dirbuf[XDIR_Attr] |= AM_ARC; /* Set archive bit */
+ fs->dirbuf[XDIR_GenFlags] = fp->obj.stat | 1; /* Update file allocation info */
st_dword(fs->dirbuf + XDIR_FstClus, fp->obj.sclust);
st_qword(fs->dirbuf + XDIR_FileSize, fp->obj.objsize);
st_qword(fs->dirbuf + XDIR_ValidFileSize, fp->obj.objsize);
- st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */
+ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Update modified time */
fs->dirbuf[XDIR_ModTime10] = 0;
st_dword(fs->dirbuf + XDIR_AccTime, 0);
res = store_xdir(&dj); /* Restore it to the directory */
if (res == FR_OK) {
res = sync_fs(fs);
- fp->flag &= ~_FA_MODIFIED;
+ fp->flag &= ~FA_MODIFIED;
}
}
- FREE_DIRBUF();
+ FREE_NAMBUF();
}
} else
#endif
@@ -3669,11 +3727,11 @@ FRESULT f_sync (
dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
st_clust(fp->obj.fs, dir, fp->obj.sclust); /* Update file allocation info */
st_dword(dir + DIR_FileSize, (DWORD)fp->obj.objsize); /* Update file size */
- st_dword(dir + DIR_WrtTime, tm); /* Update modified time */
+ st_dword(dir + DIR_ModTime, tm); /* Update modified time */
st_word(dir + DIR_LstAccDate, 0);
fs->wflag = 1;
res = sync_fs(fs); /* Restore it to the directory */
- fp->flag &= ~_FA_MODIFIED;
+ fp->flag &= ~FA_MODIFIED;
}
}
}
@@ -3723,11 +3781,11 @@ FRESULT f_close (
+#if _FS_RPATH >= 1
/*-----------------------------------------------------------------------*/
/* Change Current Directory or Current Drive, Get Current Directory */
/*-----------------------------------------------------------------------*/
-#if _FS_RPATH >= 1
#if _VOLUMES >= 2
FRESULT f_chdrive (
const TCHAR* path /* Drive number */
@@ -3753,13 +3811,13 @@ FRESULT f_chdir (
FRESULT res;
DIR dj;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
/* Get logical drive number */
res = find_volume(&path, &fs, 0);
if (res == FR_OK) {
dj.obj.fs = fs;
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the path */
if (res == FR_OK) { /* Follow completed */
if (dj.fn[NSFLAG] & NS_NONAME) {
@@ -3810,7 +3868,7 @@ FRESULT f_getcwd (
DWORD ccl;
TCHAR *tp;
FILINFO fno;
- DEF_NAMBUF;
+ DEF_NAMBUF
*buff = 0;
@@ -3818,7 +3876,7 @@ FRESULT f_getcwd (
res = find_volume((const TCHAR**)&buff, &fs, 0); /* Get current volume */
if (res == FR_OK) {
dj.obj.fs = fs;
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
i = len; /* Bottom of buffer (directory stack base) */
if (!_FS_EXFAT || fs->fs_type != FS_EXFAT) { /* (Cannot do getcwd on exFAT and returns root path) */
dj.obj.sclust = fs->cdir; /* Start to follow upper directory from current directory */
@@ -3867,6 +3925,7 @@ FRESULT f_getcwd (
LEAVE_FF(fs, res);
}
+
#endif /* _FS_RPATH >= 2 */
#endif /* _FS_RPATH >= 1 */
@@ -3897,7 +3956,7 @@ FRESULT f_lseek (
if (ofs == CREATE_LINKMAP) { /* Create CLMT */
tbl = fp->cltbl;
tlen = *tbl++; ulen = 2; /* Given table size and required table size */
- cl = fp->obj.sclust; /* Top of the chain */
+ cl = fp->obj.sclust; /* Origin of the chain */
if (cl) {
do {
/* Get a fragment */
@@ -3926,15 +3985,13 @@ FRESULT f_lseek (
fp->clust = clmt_clust(fp, ofs - 1);
dsc = clust2sect(fs, fp->clust);
if (!dsc) ABORT(fs, FR_INT_ERR);
- dsc += (ofs - 1) / SS(fs) & (fs->csize - 1);
+ dsc += (DWORD)((ofs - 1) / SS(fs)) & (fs->csize - 1);
if (fp->fptr % SS(fs) && dsc != fp->sect) { /* Refill sector cache if needed */
#if !_FS_TINY
#if !_FS_READONLY
- if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */
- if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
- ABORT(fp, FR_DISK_ERR);
- }
- fp->flag &= ~_FA_DIRTY;
+ if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fp, FR_DISK_ERR);
+ fp->flag &= ~FA_DIRTY;
}
#endif
if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */
@@ -3950,12 +4007,9 @@ FRESULT f_lseek (
/* Normal Seek */
{
- if (ofs > fp->obj.objsize /* In read-only mode, clip offset with the file size */
-#if !_FS_READONLY
- && !(fp->flag & FA_WRITE)
-#endif
- ) ofs = fp->obj.objsize;
-
+ if (ofs > fp->obj.objsize && (_FS_READONLY || !(fp->flag & FA_WRITE))) { /* In read-only mode, clip offset with the file size */
+ ofs = fp->obj.objsize;
+ }
ifptr = fp->fptr;
fp->fptr = nsect = 0;
if (ofs) {
@@ -4005,11 +4059,9 @@ FRESULT f_lseek (
if (fp->fptr % SS(fs) && nsect != fp->sect) { /* Fill sector cache if needed */
#if !_FS_TINY
#if !_FS_READONLY
- if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */
- if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
- fp->flag &= ~_FA_DIRTY;
+ if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
+ if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
+ fp->flag &= ~FA_DIRTY;
}
#endif
if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */
@@ -4021,7 +4073,7 @@ FRESULT f_lseek (
#if !_FS_READONLY
if (fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */
fp->obj.objsize = fp->fptr;
- fp->flag |= _FA_MODIFIED;
+ fp->flag |= FA_MODIFIED;
}
#endif
}
@@ -4044,7 +4096,7 @@ FRESULT f_opendir (
FRESULT res;
FATFS *fs;
_FDID *obj;
- DEF_NAMBUF;
+ DEF_NAMBUF
if (!dp) return FR_INVALID_OBJECT;
@@ -4054,7 +4106,7 @@ FRESULT f_opendir (
res = find_volume(&path, &fs, 0);
if (res == FR_OK) {
obj->fs = fs;
- INIT_NAMBUF(*dp);
+ INIT_NAMBUF(fs);
res = follow_path(dp, path); /* Follow the path to the directory */
if (res == FR_OK) { /* Follow completed */
if (!(dp->fn[NSFLAG] & NS_NONAME)) { /* It is not the origin directory itself */
@@ -4146,7 +4198,7 @@ FRESULT f_readdir (
{
FRESULT res;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
res = validate(dp, &fs); /* Check validity of the object */
@@ -4154,7 +4206,7 @@ FRESULT f_readdir (
if (!fno) {
res = dir_sdi(dp, 0); /* Rewind the directory object */
} else {
- INIT_NAMBUF(*dp);
+ INIT_NAMBUF(fs);
res = dir_read(dp, 0); /* Read an item */
if (res == FR_NO_FILE) res = FR_OK; /* Ignore end of directory */
if (res == FR_OK) { /* A valid entry is found */
@@ -4234,13 +4286,13 @@ FRESULT f_stat (
{
FRESULT res;
DIR dj;
- DEF_NAMBUF;
+ DEF_NAMBUF
/* Get logical drive number */
res = find_volume(&path, &dj.obj.fs, 0);
if (res == FR_OK) {
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(dj.obj.fs);
res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK) { /* Follow completed */
if (dj.fn[NSFLAG] & NS_NONAME) { /* It is origin directory */
@@ -4309,7 +4361,7 @@ FRESULT f_getfree (
if (!(bm & 1)) nfree++;
bm >>= 1;
}
- i = (i + 1) & (SS(fs) - 1);
+ i = (i + 1) % SS(fs);
} while (clst);
} else
#endif
@@ -4376,13 +4428,13 @@ FRESULT f_truncate (
}
}
fp->obj.objsize = fp->fptr; /* Set file size to current R/W point */
- fp->flag |= _FA_MODIFIED;
+ fp->flag |= FA_MODIFIED;
#if !_FS_TINY
- if (res == FR_OK && (fp->flag & _FA_DIRTY)) {
+ if (res == FR_OK && (fp->flag & FA_DIRTY)) {
if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) {
res = FR_DISK_ERR;
} else {
- fp->flag &= ~_FA_DIRTY;
+ fp->flag &= ~FA_DIRTY;
}
}
#endif
@@ -4410,14 +4462,14 @@ FRESULT f_unlink (
#if _FS_EXFAT
_FDID obj;
#endif
- DEF_NAMBUF;
+ DEF_NAMBUF
/* Get logical drive number */
res = find_volume(&path, &fs, FA_WRITE);
dj.obj.fs = fs;
if (res == FR_OK) {
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
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 */
@@ -4504,14 +4556,14 @@ FRESULT f_mkdir (
BYTE *dir;
UINT n;
DWORD dsc, dcl, pcl, tm;
- DEF_NAMBUF;
+ DEF_NAMBUF
/* Get logical drive number */
res = find_volume(&path, &fs, FA_WRITE);
dj.obj.fs = fs;
if (res == FR_OK) {
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
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)) {
@@ -4534,12 +4586,11 @@ FRESULT f_mkdir (
mem_set(dir + DIR_Name, ' ', 11); /* Create "." entry */
dir[DIR_Name] = '.';
dir[DIR_Attr] = AM_DIR;
- st_dword(dir + DIR_WrtTime, tm);
+ st_dword(dir + DIR_ModTime, tm);
st_clust(fs, dir, dcl);
mem_cpy(dir + SZDIRE, dir, SZDIRE); /* Create ".." entry */
dir[SZDIRE + 1] = '.'; pcl = dj.obj.sclust;
- if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase)
- pcl = 0;
+ if (fs->fs_type == FS_FAT32 && pcl == fs->dirbase) pcl = 0;
st_clust(fs, dir + SZDIRE, pcl);
}
for (n = fs->csize; n; n--) { /* Write dot entries and clear following sectors */
@@ -4553,24 +4604,24 @@ FRESULT f_mkdir (
if (res == FR_OK) res = dir_register(&dj); /* Register the object to the directoy */
if (res == FR_OK) {
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT) {
- st_dword(fs->dirbuf + XDIR_ModTime, tm);
- st_dword(fs->dirbuf + XDIR_FstClus, dcl);
- st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize);
+ if (fs->fs_type == FS_EXFAT) { /* Initialize directory entry block */
+ st_dword(fs->dirbuf + XDIR_ModTime, tm); /* Created time */
+ st_dword(fs->dirbuf + XDIR_FstClus, dcl); /* Table start cluster */
+ st_dword(fs->dirbuf + XDIR_FileSize, (DWORD)dj.obj.objsize); /* File size needs to be valid */
st_dword(fs->dirbuf + XDIR_ValidFileSize, (DWORD)dj.obj.objsize);
- fs->dirbuf[XDIR_GenFlags] = 3;
- fs->dirbuf[XDIR_Attr] = AM_DIR;
+ fs->dirbuf[XDIR_GenFlags] = 3; /* Initialize the object flag (contiguous) */
+ fs->dirbuf[XDIR_Attr] = AM_DIR; /* Attribute */
res = store_xdir(&dj);
} else
#endif
{
dir = dj.dir;
- st_dword(dir + DIR_WrtTime, tm); /* Created time */
+ st_dword(dir + DIR_ModTime, tm); /* Created time */
st_clust(fs, dir, dcl); /* Table start cluster */
dir[DIR_Attr] = AM_DIR; /* Attribute */
fs->wflag = 1;
}
- res = sync_fs(fs);
+ if (res == FR_OK) res = sync_fs(fs);
} else {
remove_chain(&dj.obj, dcl, 0); /* Could not register, remove cluster chain */
}
@@ -4598,14 +4649,14 @@ FRESULT f_rename (
FATFS *fs;
BYTE buf[_FS_EXFAT ? SZDIRE * 2 : 24], *dir;
DWORD dw;
- DEF_NAMBUF;
+ DEF_NAMBUF
get_ldnumber(&path_new); /* Ignore drive number of new name */
res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive number of the old object */
if (res == FR_OK) {
djo.obj.fs = fs;
- INIT_NAMBUF(djo);
+ INIT_NAMBUF(fs);
res = follow_path(&djo, path_old); /* Check old object */
if (res == FR_OK && (djo.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check validity of name */
#if _FS_LOCK != 0
@@ -4678,8 +4729,6 @@ FRESULT f_rename (
LEAVE_FF(fs, res);
}
-
-
#endif /* !_FS_READONLY */
#endif /* _FS_MINIMIZE == 0 */
#endif /* _FS_MINIMIZE <= 1 */
@@ -4701,13 +4750,13 @@ FRESULT f_chmod (
FRESULT res;
DIR dj;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */
dj.obj.fs = fs;
if (res == FR_OK) {
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */
if (res == FR_OK) {
@@ -4722,7 +4771,7 @@ FRESULT f_chmod (
dj.dir[DIR_Attr] = (attr & mask) | (dj.dir[DIR_Attr] & (BYTE)~mask); /* Apply attribute change */
fs->wflag = 1;
}
- res = sync_fs(fs);
+ if (res == FR_OK) res = sync_fs(fs);
}
FREE_NAMBUF();
}
@@ -4745,26 +4794,24 @@ FRESULT f_utime (
FRESULT res;
DIR dj;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive number */
dj.obj.fs = fs;
if (res == FR_OK) {
- INIT_NAMBUF(dj);
+ INIT_NAMBUF(fs);
res = follow_path(&dj, path); /* Follow the file path */
if (res == FR_OK && (dj.fn[NSFLAG] & (NS_DOT | NS_NONAME))) res = FR_INVALID_NAME; /* Check object validity */
if (res == FR_OK) {
#if _FS_EXFAT
if (fs->fs_type == FS_EXFAT) {
- st_word(fs->dirbuf + XDIR_ModTime, fno->ftime);
- st_word(fs->dirbuf + XDIR_ModTime + 2, fno->fdate);
+ st_dword(fs->dirbuf + XDIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);
res = store_xdir(&dj);
} else
#endif
{
- st_word(dj.dir + DIR_WrtTime, fno->ftime);
- st_word(dj.dir + DIR_WrtDate, fno->fdate);
+ st_dword(dj.dir + DIR_ModTime, (DWORD)fno->fdate << 16 | fno->ftime);
fs->wflag = 1;
}
if (res == FR_OK) res = sync_fs(fs);
@@ -4859,7 +4906,7 @@ FRESULT f_getlabel (
case FS_FAT32: di = BS_VolID32; break;
default: di = BS_VolID;
}
- *vsn = ld_dword(&fs->win[di]);
+ *vsn = ld_dword(fs->win + di);
}
}
@@ -5008,7 +5055,7 @@ FRESULT f_expand (
{
FRESULT res;
FATFS *fs;
- DWORD val, clst, csz, stcl, scl, ncl, tcl;
+ DWORD n, clst, stcl, scl, ncl, tcl, lclst;
res = validate(fp, &fs); /* Check validity of the object */
@@ -5017,23 +5064,22 @@ FRESULT f_expand (
#if _FS_EXFAT
if (fs->fs_type != FS_EXFAT && fsz >= 0x100000000) LEAVE_FF(fs, FR_DENIED); /* Check if in size limit */
#endif
- csz = (DWORD)fs->csize * SS(fs); /* Cluster size */
- tcl = (DWORD)(fsz / csz) + ((fsz & (csz - 1)) ? 1 : 0); /* Number of clusters required */
- stcl = fs->last_clst;
+ n = (DWORD)fs->csize * SS(fs); /* Cluster size */
+ tcl = (DWORD)(fsz / n) + ((fsz & (n - 1)) ? 1 : 0); /* Number of clusters required */
+ stcl = fs->last_clst; lclst = 0;
if (stcl < 2 || stcl >= fs->n_fatent) stcl = 2;
#if _FS_EXFAT
if (fs->fs_type == FS_EXFAT) {
scl = find_bitmap(fs, stcl, tcl); /* Find a contiguous cluster block */
if (scl == 0) res = FR_DENIED; /* No contiguous cluster block was found */
- if (scl == 1) res = FR_INT_ERR;
if (scl == 0xFFFFFFFF) res = FR_DISK_ERR;
if (res == FR_OK) {
if (opt) {
res = change_bitmap(fs, scl, tcl, 1); /* Mark the cluster block 'in use' */
- fs->last_clst = scl + tcl - 1;
+ lclst = scl + tcl - 1;
} else {
- fs->last_clst = scl - 1; /* Set suggested cluster to start next */
+ lclst = scl - 1;
}
}
} else
@@ -5041,36 +5087,42 @@ FRESULT f_expand (
{
scl = clst = stcl; ncl = 0;
for (;;) { /* Find a contiguous cluster block */
- val = get_fat(&fp->obj, clst);
+ n = get_fat(&fp->obj, clst);
if (++clst >= fs->n_fatent) clst = 2;
- if (val == 1) { res = FR_INT_ERR; break; }
- if (val == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
- if (val == 0) { /* Is it a free cluster? */
- if (++ncl == tcl) break; /* Break if a contiguous cluster block was found */
+ if (n == 1) { res = FR_INT_ERR; break; }
+ if (n == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
+ if (n == 0) { /* Is it a free cluster? */
+ if (++ncl == tcl) break; /* Break if a contiguous cluster block is found */
} else {
scl = clst; ncl = 0; /* Not a free cluster */
}
- if (clst == stcl) { res = FR_DENIED; break; } /* All cluster scanned? */
+ if (clst == stcl) { res = FR_DENIED; break; } /* No contiguous cluster? */
}
if (res == FR_OK) {
if (opt) {
- for (clst = scl; tcl; clst++, tcl--) { /* Create a cluster chain on the FAT */
- val = (tcl == 1) ? 0xFFFFFFFF : clst + 1;
- res = put_fat(fs, clst, val);
+ for (clst = scl, n = tcl; n; clst++, n--) { /* Create a cluster chain on the FAT */
+ res = put_fat(fs, clst, (n == 1) ? 0xFFFFFFFF : clst + 1);
if (res != FR_OK) break;
- fs->last_clst = clst;
+ lclst = clst;
}
} else {
- fs->last_clst = scl - 1; /* Set suggested cluster to start next */
+ lclst = scl - 1;
}
}
}
- if (opt && res == FR_OK) {
- fp->obj.sclust = scl; /* Update allocation information */
- fp->obj.objsize = fsz;
- if (_FS_EXFAT) fp->obj.stat = 2;
- fp->flag |= _FA_MODIFIED;
+ if (res == FR_OK) {
+ fs->last_clst = lclst; /* Set suggested start cluster to start next */
+ if (opt) {
+ fp->obj.sclust = scl; /* Update object allocation information */
+ fp->obj.objsize = fsz;
+ if (_FS_EXFAT) fp->obj.stat = 2; /* Set status 'contiguous chain' */
+ fp->flag |= FA_MODIFIED;
+ if (fs->free_clst < fs->n_fatent - 2) { /* Update FSINFO */
+ fs->free_clst -= tcl;
+ fs->fsi_flag |= 1;
+ }
+ }
}
LEAVE_FF(fs, res);
@@ -5080,10 +5132,10 @@ FRESULT f_expand (
+#if _USE_FORWARD
/*-----------------------------------------------------------------------*/
/* Forward data to the stream directly */
/*-----------------------------------------------------------------------*/
-#if _USE_FORWARD
FRESULT f_forward (
FIL* fp, /* Pointer to the file object */
@@ -5097,7 +5149,7 @@ FRESULT f_forward (
DWORD clst, sect;
FSIZE_t remain;
UINT rcnt, csect;
- const BYTE *dbuf;
+ BYTE *dbuf;
*bf = 0; /* Clear transfer byte counter */
@@ -5129,9 +5181,9 @@ FRESULT f_forward (
#else
if (fp->sect != sect) { /* Fill sector cache with file data */
#if !_FS_READONLY
- if (fp->flag & _FA_DIRTY) { /* Write-back dirty sector cache */
+ if (fp->flag & FA_DIRTY) { /* Write-back dirty sector cache */
if (disk_write(fs->drv, fp->buf, fp->sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
- fp->flag &= ~_FA_DIRTY;
+ fp->flag &= ~FA_DIRTY;
}
#endif
if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
@@ -5153,259 +5205,452 @@ FRESULT f_forward (
#if _USE_MKFS && !_FS_READONLY
/*-----------------------------------------------------------------------*/
-/* Create file system on the logical drive */
+/* Create FAT 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 */
+ BYTE opt, /* Format option */
+ DWORD au, /* Size of allocation unit [byte] */
+ void* work, /* Pointer to working buffer */
+ UINT len /* Size of working buffer */
)
{
- 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};
+ const UINT n_fats = 1; /* Number of FATs for FAT12/16/32 volume (1 or 2) */
+ const UINT n_rootdir = 512; /* Number of root directory entries for FAT12/16 volume */
+ static const WORD cst[] = {1, 4, 16, 64, 256, 512, 0}; /* Cluster size boundary for FAT12/16 volume (4KS unit) */
+ static const WORD cst32[] = {1, 2, 4, 8, 16, 32, 0}; /* Cluster size boundary for FAT32 volume (128KS unit) */
+ BYTE fmt, sys, *buf, *pte, pdrv, part;
+ WORD ss;
+ DWORD n, pau, n_clst, sz_blk, sect, szb_buf, sz_buf;
+ DWORD b_vol, b_fat, b_data; /* Base LBA for volume, fat, data */
+ DWORD sz_vol, sz_rsv, sz_fat, sz_dir; /* Size for volume, fat, dir, data */
+ UINT i, ns;
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];
+#if _USE_TRIM || _FS_EXFAT
+ DWORD tbl[3];
#endif
/* Check mounted drive and clear work area */
- if (sfd > 1) return FR_INVALID_PARAMETER;
- vol = get_ldnumber(&path); /* Get target volume */
+ vol = get_ldnumber(&path); /* Get target logical drive */
if (vol < 0) return FR_INVALID_DRIVE;
- fs = FatFs[vol]; /* Check if the volume has work area */
- if (!fs) return FR_NOT_ENABLED;
- fs->fs_type = 0;
+ if (FatFs[vol]) FatFs[vol]->fs_type = 0; /* Clear mounted volume */
pdrv = LD2PD(vol); /* Physical drive */
- part = LD2PT(vol); /* Partition (0:auto detect, 1-4:get from partition table)*/
+ part = LD2PT(vol); /* Partition (0:create as new, 1-4:get by partition table) */
- /* Get disk statics */
+ /* Check physical drive status */
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;
- }
+ if (disk_ioctl(pdrv, GET_BLOCK_SIZE, &sz_blk) != RES_OK || !sz_blk || sz_blk > 32768 || (sz_blk & (sz_blk - 1))) sz_blk = 1;
+#if _MAX_SS != _MIN_SS /* Get sector size of the medium */
+ if (disk_ioctl(pdrv, GET_SECTOR_SIZE, &ss) != RES_OK) return FR_DISK_ERR;
+ if (ss > _MAX_SS || ss < _MIN_SS || (ss & (ss - 1))) return FR_DISK_ERR;
+#else
+ ss = _MAX_SS;
#endif
- if (_MULTI_PARTITION && part) {
+ if ((au != 0 && au < ss) || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */
+ au /= ss; /* Cluster size in byte to in sector */
+ if (au > 32768) return FR_INVALID_PARAMETER;
+
+ /* Set size and pointer of the working buffer */
+ buf = (BYTE*)work; /* Use given working buffer */
+ if (len < ss) return FR_MKFS_ABORTED;
+ szb_buf = len & ~(ss - 1); /* Round-down by sector size [byte] */
+ sz_buf = szb_buf / ss; /* Size of sector buffer [sector] */
+
+ /* Determine where the volume to be located (b_vol, sz_vol) */
+ if (_MULTI_PARTITION && part != 0) {
/* 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 */
+ if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Load MBR */
+ if (ld_word(buf + BS_55AA) != 0xAA55) return FR_MKFS_ABORTED; /* Check MBR is valid */
+ pte = buf + (MBR_Table + (part - 1) * SZ_PTE);
+ if (!pte[PTE_System]) return FR_MKFS_ABORTED; /* No partition? */
+ b_vol = ld_dword(pte + PTE_StLba); /* Get volume start sector */
+ sz_vol = ld_dword(pte + PTE_SizLba); /* Get volume size */
} else {
/* Create a single-partition in this function */
- if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &n_vol) != RES_OK || n_vol < 128) {
- return FR_DISK_ERR;
+ if (disk_ioctl(pdrv, GET_SECTOR_COUNT, &sz_vol) != RES_OK) return FR_DISK_ERR;
+ b_vol = (opt & FM_SFD) ? 0 : 63; /* Volume start sector */
+ if (sz_vol < b_vol) return FR_MKFS_ABORTED;
+ sz_vol -= b_vol; /* Volume size */
+ }
+ if (sz_vol < 128) return FR_MKFS_ABORTED; /* Check volume size (>=128s) */
+
+ /* Pre-determine the FAT type by argument */
+ do {
+ if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */
+ if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au >= 256) { /* exFAT only, vol >= 64Ms or au >= 256s ? */
+ fmt = FS_EXFAT; break;
+ }
}
- b_vol = (sfd) ? 0 : 63; /* Volume start sector */
- n_vol -= b_vol; /* Volume size */
- }
+ if (au >= 256) return FR_INVALID_PARAMETER; /* Too large au for FAT/FAT32 */
+ if (opt & FM_FAT32) { /* FAT32 possible? */
+ if ((opt & FM_ANY) == FM_FAT32 || !(opt & FM_FAT)) { /* FAT32 only or no-FAT? */
+ fmt = FS_FAT32; break;
+ }
+ }
+ if (!(opt & FM_FAT)) return FR_INVALID_PARAMETER; /* no-FAT? */
+ fmt = FS_FAT16;
+ } while (0);
- 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;
+#if _FS_EXFAT
+ if (fmt == FS_EXFAT) { /* Create an exFAT volume */
+ DWORD sum, szb_bit, szb_case;
+ WCHAR ch, si;
+ UINT j, st;
+ BYTE b;
- /* 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;
+ if (sz_vol < 0x1000) return FR_MKFS_ABORTED; /* Too small volume? */
+#if _USE_TRIM
+ tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */
+ disk_ioctl(pdrv, CTRL_TRIM, tbl);
+#endif
+ /* Determine FAT location, data location and number of clusters */
+ if (!au) { /* au auto-selection */
+ au = 8;
+ if (sz_vol >= 0x80000) au = 64; /* >= 512KS */
+ if (sz_vol >= 0x4000000) au = 256; /* >= 64MS */
+ }
+ b_fat = b_vol + 32; /* FAT start at offset 32 */
+ sz_fat = ((sz_vol / au + 2) * 4 + ss - 1) / ss; /* Numbef of FAT sectors */
+ b_data = (b_fat + sz_fat + sz_blk - 1) & ~(sz_blk - 1); /* Align data area to the erase block boundary */
+ if (b_data >= sz_vol / 2) return FR_MKFS_ABORTED; /* Too small volume? */
+ n_clst = (sz_vol - (b_data - b_vol)) / au; /* Nunber of clusters */
+ if (n_clst <16) return FR_MKFS_ABORTED; /* Too few clusters? */
+ if (n_clst > MAX_EXFAT) return FR_MKFS_ABORTED; /* Too many clusters? */
- /* 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 * SZDIRE / 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 */
+ szb_bit = (n_clst + 7) / 8; /* Size of allocation bitmap */
+ tbl[0] = (szb_bit + au * ss - 1) / (au * ss); /* Number of bitmap clusters */
+ tbl[2] = 1; /* Number of rootdir clusters */
- /* 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;
- }
+ /* Create a compressed up-case table */
+ sect = b_data + au * tbl[0]; /* Table start sector */
+ sum = 0; /* Table checksum to be stored in the 82 entry */
+ st = si = i = j = szb_case = 0;
+ do {
+ switch (st) {
+ case 0:
+ ch = ff_wtoupper(si); /* Get an up-case char */
+ if (ch != si) {
+ si++; break; /* Store the up-case char if exist */
+ }
+ for (j = 1; (WCHAR)(si + j) && (WCHAR)(si + j) == ff_wtoupper((WCHAR)(si + j)); j++) ; /* Get run length of no-case block */
+ if (j >= 128) {
+ ch = 0xFFFF; st = 2; break; /* Compress the no-case block if run is >= 128 */
+ }
+ st = 1; /* Do not compress short run */
+ /* continue */
+ case 1:
+ ch = si++; /* Fill the short run */
+ if (--j == 0) st = 0;
+ break;
+ default:
+ ch = (WCHAR)j; si += j; /* Number of chars to skip */
+ st = 0;
+ }
+ sum = xsum32(buf[i + 0] = (BYTE)ch, sum); /* Put it into the write buffer */
+ sum = xsum32(buf[i + 1] = (BYTE)(ch >> 8), sum);
+ i += 2; szb_case += 2;
+ if (!si || i == szb_buf) { /* Write buffered data when buffer full or end of process */
+ ns = (i + ss - 1) / ss;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns; i = 0;
+ }
+ } while (si);
+ tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case clusters */
- /* 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;
+ /* Initialize the allocation bitmap */
+ mem_set(buf, 0, szb_buf); /* Set in-use flags of bitmap, up-case and root dir */
+ for (i = 0, n = tbl[0] + tbl[1] + tbl[2]; n >= 8; buf[i++] = 0xFF, n -= 8) ;
+ for (b = 1; n; buf[i] |= b, b <<= 1, n--) ;
+ sect = b_data; n = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of the sectors */
+ do { /* Fill allocation bitmap sectors */
+ ns = (n > sz_buf) ? sz_buf : n;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns;
+ mem_set(buf, 0, ss);
+ } while (n -= ns);
+
+ /* Initialize the FAT */
+ st_qword(buf, 0xFFFFFFFFFFFFFFF8); /* Entry 0 and 1 */
+ for (j = 0, i = 2; j < 3; j++) { /* Set entries of bitmap, up-case and root dir */
+ for (n = tbl[j]; n; n--) {
+ st_dword(buf + i * 4, (n >= 2) ? i + 1 : 0xFFFFFFFF);
+ i++;
+ }
+ }
+ sect = b_fat; n = sz_fat; /* Start of FAT and number of the sectors */
+ do { /* Fill FAT sectors */
+ ns = (n > sz_buf) ? sz_buf : n;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns;
+ mem_set(buf, 0, ss);
+ } while (n -= ns);
+
+ /* Initialize the root directory */
+ mem_set(buf, 0, ss);
+ buf[SZDIRE * 0 + 0] = 0x83; /* 83 entry (volume label) */
+ buf[SZDIRE * 1 + 0] = 0x81; /* 81 entry (allocation bitmap) */
+ st_dword(buf + SZDIRE * 1 + 20, 2);
+ st_dword(buf + SZDIRE * 1 + 24, szb_bit);
+ buf[SZDIRE * 2 + 0] = 0x82; /* 82 entry (up-case table) */
+ st_dword(buf + SZDIRE * 2 + 4, sum);
+ st_dword(buf + SZDIRE * 2 + 20, 2 + tbl[0]);
+ st_dword(buf + SZDIRE * 2 + 24, szb_case);
+ sect = b_data + au * (tbl[0] + tbl[1]); n = au; /* Start of directory and number of the sectors */
+ do { /* Fill root direcotry sectors */
+ ns = (n > sz_buf) ? sz_buf : n;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns;
+ mem_set(buf, 0, ss);
+ } while (n -= ns);
+
+ /* Create two set of the exFAT VBR blocks */
+ sect = b_vol;
+ for (n = 0; n < 2; n++) {
+ /* Main record (+0) */
+ mem_set(buf, 0, ss);
+ mem_cpy(buf + BS_JmpBoot, "\xEB\x76\x90" "EXFAT ", 11); /* Boot jump code (x86), OEM name */
+ st_dword(buf + BPB_VolOfsEx, b_vol); /* Volume offset in the physical drive [sector] */
+ st_dword(buf + BPB_TotSecEx, sz_vol); /* Volume size [sector] */
+ st_dword(buf + BPB_FatOfsEx, b_fat - b_vol); /* FAT offset [sector] */
+ st_dword(buf + BPB_FatSzEx, sz_fat); /* FAT size [sector] */
+ st_dword(buf + BPB_DataOfsEx, b_data - b_vol); /* Data offset [sector] */
+ st_dword(buf + BPB_NumClusEx, n_clst); /* Number of clusters */
+ st_dword(buf + BPB_RootClusEx, 2 + tbl[0] + tbl[1]); /* Root dir cluster # */
+ st_dword(buf + BPB_VolIDEx, GET_FATTIME()); /* VSN */
+ st_word(buf + BPB_FSVerEx, 0x100); /* File system version (1.00) */
+ for (buf[BPB_BytsPerSecEx] = 0, i = ss; i >>= 1; buf[BPB_BytsPerSecEx]++) ; /* Log2 of sector size [byte] */
+ for (buf[BPB_SecPerClusEx] = 0, i = au; i >>= 1; buf[BPB_SecPerClusEx]++) ; /* Log2 of cluster size [sector] */
+ buf[BPB_NumFATsEx] = 1; /* Number of FATs */
+ buf[BPB_DrvNumEx] = 0x80; /* Drive number (for int13) */
+ st_word(buf + BS_BootCodeEx, 0xFEEB); /* Boot code (x86) */
+ st_word(buf + BS_55AA, 0xAA55); /* Signature (placed here regardless of sector size) */
+ for (i = sum = 0; i < ss; i++) { /* VBR checksum */
+ if (i != BPB_VolFlagEx && i != BPB_VolFlagEx + 1 && i != BPB_PercInUseEx) sum = xsum32(buf[i], sum);
+ }
+ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
+ /* Extended bootstrap record (+1..+8) */
+ mem_set(buf, 0, ss);
+ st_word(buf + ss - 2, 0xAA55); /* Signature (placed at end of sector) */
+ for (j = 1; j < 9; j++) {
+ for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */
+ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
+ }
+ /* OEM/Reserved record (+9..+10) */
+ mem_set(buf, 0, ss);
+ for ( ; j < 11; j++) {
+ for (i = 0; i < ss; sum = xsum32(buf[i++], sum)) ; /* VBR checksum */
+ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
+ }
+ /* Sum record (+11) */
+ for (i = 0; i < ss; i += 4) st_dword(buf + i, sum); /* Fill with checksum value */
+ if (disk_write(pdrv, buf, sect++, 1) != RES_OK) return FR_DISK_ERR;
+ }
+
+ } else
+#endif
+ { /* Create an FAT12/16/32 volume */
+ do {
+ pau = au;
+ /* Pre-determine number of clusters and FAT sub-type */
+ if (fmt == FS_FAT32) { /* FAT32 volume */
+ if (!pau) { /* au auto-selection */
+ n = sz_vol / 0x20000; /* Volume size in unit of 128KS */
+ for (i = 0, pau = 1; cst32[i] && cst32[i] <= n; i++, pau <<= 1) ; /* Get from table */
+ }
+ n_clst = sz_vol / pau; /* Number of clusters */
+ sz_fat = (n_clst * 4 + 8 + ss - 1) / ss; /* FAT size [sector] */
+ sz_rsv = 32; /* Number of reserved sectors */
+ sz_dir = 0; /* No static directory */
+ if (n_clst <= MAX_FAT16 || n_clst > MAX_FAT32) return FR_MKFS_ABORTED;
+ } else { /* FAT12/16 volume */
+ if (!pau) { /* au auto-selection */
+ n = sz_vol / 0x1000; /* Volume size in unit of 4KS */
+ for (i = 0, pau = 1; cst[i] && cst[i] <= n; i++, pau <<= 1) ; /* Get from table */
+ }
+ n_clst = sz_vol / pau;
+ if (n_clst > MAX_FAT12) {
+ n = n_clst * 2 + 4; /* FAT size [byte] */
+ } else {
+ fmt = FS_FAT12;
+ n = (n_clst * 3 + 1) / 2 + 3; /* FAT size [byte] */
+ }
+ sz_fat = (n + ss - 1) / ss; /* FAT size [sector] */
+ sz_rsv = 1; /* Number of reserved sectors */
+ sz_dir = (DWORD)n_rootdir * SZDIRE / ss; /* Rootdir size [sector] */
+ }
+ b_fat = b_vol + sz_rsv; /* FAT base */
+ b_data = b_fat + sz_fat * n_fats + sz_dir; /* Data base */
+
+ /* Align data base to erase block boundary (for flash memory media) */
+ n = ((b_data + sz_blk - 1) & ~(sz_blk - 1)) - b_data; /* Next nearest erase block from current data base */
+ if (fmt == FS_FAT32) { /* FAT32: Move FAT base */
+ sz_rsv += n; b_fat += n;
+ } else { /* FAT12/16: Expand FAT size */
+ sz_fat += n / n_fats;
+ }
+
+ /* Determine number of clusters and final check of validity of the FAT sub-type */
+ if (sz_vol < b_data + pau * 16 - b_vol) return FR_MKFS_ABORTED; /* Too small volume */
+ n_clst = (sz_vol - sz_rsv - sz_fat * n_fats - sz_dir) / pau;
+ if (fmt == FS_FAT32) {
+ if (n_clst <= MAX_FAT16) { /* Too few clusters for FAT32 */
+ if (!au && (au = pau / 2) != 0) continue; /* Adjust cluster size and retry */
+ return FR_MKFS_ABORTED;
+ }
+ }
+ if (fmt == FS_FAT16) {
+ if (n_clst > MAX_FAT16) { /* Too many clusters for FAT16 */
+ if (!au && (pau * 2) <= 64) {
+ au = pau * 2; continue; /* Adjust cluster size and retry */
+ }
+ if ((opt & FM_FAT32)) {
+ fmt = FS_FAT32; continue; /* Switch type to FAT32 and retry */
+ }
+ if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
+ return FR_MKFS_ABORTED;
+ }
+ if (n_clst <= MAX_FAT12) { /* Too few clusters for FAT16 */
+ if (!au && (au = pau * 2) <= 128) continue; /* Adjust cluster size and retry */
+ return FR_MKFS_ABORTED;
+ }
+ }
+ if (fmt == FS_FAT12 && n_clst > MAX_FAT12) return FR_MKFS_ABORTED; /* Too many clusters for FAT12 */
+
+ /* Ok, it is the valid cluster configuration */
+ break;
+ } while (1);
+
+#if _USE_TRIM
+ tbl[0] = b_vol; tbl[1] = b_vol + sz_vol - 1; /* Inform the device the volume area can be erased */
+ disk_ioctl(pdrv, CTRL_TRIM, tbl);
+#endif
+ /* Create FAT VBR */
+ mem_set(buf, 0, ss);
+ mem_cpy(buf + BS_JmpBoot, "\xEB\xFE\x90" "MSDOS5.0", 11);/* Boot jump code (x86), OEM name */
+ st_word(buf + BPB_BytsPerSec, ss); /* Sector size [byte] */
+ buf[BPB_SecPerClus] = (BYTE)pau; /* Cluster size [sector] */
+ st_word(buf + BPB_RsvdSecCnt, (WORD)sz_rsv); /* Size of reserved area */
+ buf[BPB_NumFATs] = n_fats; /* Number of FATs */
+ st_word(buf + BPB_RootEntCnt, (WORD)((fmt == FS_FAT32) ? 0 : n_rootdir)); /* Number of root directory entries */
+ if (sz_vol < 0x10000) {
+ st_word(buf + BPB_TotSec16, (WORD)sz_vol); /* Volume size in 16-bit LBA */
+ } else {
+ st_dword(buf + BPB_TotSec32, sz_vol); /* Volume size in 12-bit LBA */
+ }
+ buf[BPB_Media] = 0xF8; /* Media descriptor */
+ st_word(buf + BPB_SecPerTrk, 63); /* Number of sectors per track (for int13) */
+ st_word(buf + BPB_NumHeads, 255); /* Number of heads (for int13) */
+ st_dword(buf + BPB_HiddSec, b_vol); /* Volume offset in the physical drive [sector] */
+ if (fmt == FS_FAT32) {
+ st_dword(buf + BS_VolID32, GET_FATTIME()); /* VSN */
+ st_dword(buf + BPB_FATSz32, sz_fat); /* FAT size [sector] */
+ st_dword(buf + BPB_RootClus32, 2); /* Root directory cluster # (2) */
+ st_word(buf + BPB_FSInfo32, 1); /* Offset of FSINFO sector (VBR + 1) */
+ st_word(buf + BPB_BkBootSec32, 6); /* Offset of backup VBR (VBR + 6) */
+ buf[BS_DrvNum32] = 0x80; /* Drive number (for int13) */
+ buf[BS_BootSig32] = 0x29; /* Extended boot signature */
+ mem_cpy(buf + BS_VolLab32, "NO NAME " "FAT32 ", 19); /* Volume label, FAT signature */
+ } else {
+ st_dword(buf + BS_VolID, GET_FATTIME()); /* VSN */
+ st_word(buf + BPB_FATSz16, (WORD)sz_fat); /* FAT size [sector] */
+ buf[BS_DrvNum] = 0x80; /* Drive number (for int13) */
+ buf[BS_BootSig] = 0x29; /* Extended boot signature */
+ mem_cpy(buf + BS_VolLab, "NO NAME " "FAT ", 19); /* Volume label, FAT signature */
+ }
+ st_word(buf + BS_55AA, 0xAA55); /* Signature (offset is fixed here regardless of sector size) */
+ if (disk_write(pdrv, buf, b_vol, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the VBR sector */
+
+ /* Create FSINFO record if needed */
+ if (fmt == FS_FAT32) {
+ disk_write(pdrv, buf, b_vol + 6, 1); /* Write backup VBR (VBR + 6) */
+ mem_set(buf, 0, ss);
+ st_dword(buf + FSI_LeadSig, 0x41615252);
+ st_dword(buf + FSI_StrucSig, 0x61417272);
+ st_dword(buf + FSI_Free_Count, n_clst - 1); /* Number of free clusters */
+ st_dword(buf + FSI_Nxt_Free, 2); /* Last allocated cluster# */
+ st_word(buf + BS_55AA, 0xAA55);
+ disk_write(pdrv, buf, b_vol + 7, 1); /* Write backup FSINFO (VBR + 7) */
+ disk_write(pdrv, buf, b_vol + 1, 1); /* Write original FSINFO (VBR + 1) */
+ }
+
+ /* Initialize FAT area */
+ mem_set(buf, 0, szb_buf);
+ sect = b_fat; /* Start sector */
+ for (i = 0; i < n_fats; i++) { /* Initialize FATs each */
+ if (fmt == FS_FAT32) {
+ st_dword(buf + 0, 0xFFFFFFF8); /* Entry 0 */
+ st_dword(buf + 4, 0xFFFFFFFF); /* Entry 1 */
+ st_dword(buf + 8, 0x0FFFFFFF); /* Entry 2 (root directory) */
+ } else {
+ st_dword(buf + 0, (fmt == FS_FAT12) ? 0xFFFFF8 : 0xFFFFFFF8); /* Entry 0 and 1 */
+ }
+ n = sz_fat; /* Sector count of a FAT */
+ do { /* Fill FAT sectors */
+ ns = (n > sz_buf) ? sz_buf : n;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns;
+ mem_set(buf, 0, ss);
+ } while (n -= ns);
+ }
+
+ /* Initialize root directory (fill with zero) */
+ n = (fmt == FS_FAT32) ? pau : sz_dir; /* Sector count of root directory */
+ do {
+ ns = (n > sz_buf) ? sz_buf : n;
+ if (disk_write(pdrv, buf, sect, ns) != RES_OK) return FR_DISK_ERR;
+ sect += ns;
+ } while (n -= ns);
}
/* Determine system ID in the partition table */
- if (fmt == FS_FAT32) {
- sys = 0x0C; /* FAT32X */
+ if (_FS_EXFAT && fmt == FS_EXFAT) {
+ sys = 0x07; /* HPFS/NTFS/exFAT */
} else {
- if (fmt == FS_FAT12 && n_vol < 0x10000) {
- sys = 0x01; /* FAT12(<65536) */
+ if (fmt == FS_FAT32) {
+ sys = 0x0C; /* FAT32X */
} else {
- sys = (n_vol < 0x10000) ? 0x04 : 0x06; /* FAT16(<65536) : FAT12/16(>=65536) */
+ if (sz_vol >= 0x10000) {
+ sys = 0x06; /* FAT12/16 (>=64KS) */
+ } else {
+ sys = (fmt == FS_FAT16) ? 0x04 : 0x01; /* FAT16 (<64KS) : FAT12 (<64KS) */
+ }
}
}
- if (_MULTI_PARTITION && part) {
+ if (_MULTI_PARTITION && part != 0) {
/* 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;
+ if (disk_read(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Read the MBR */
+ buf[MBR_Table + (part - 1) * SZ_PTE + PTE_System] = sys; /* Set system type */
+ if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it back to the MBR */
} 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;
+ if (!(opt & FM_SFD)) {
+ /* Create partition table in FDISK format */
+ mem_set(buf, 0, ss);
+ st_word(buf + BS_55AA, 0xAA55); /* MBR signature */
+ pte = buf + MBR_Table; /* Create partition table for single partition in the drive */
+ pte[PTE_Boot] = 0; /* Boot indicator */
+ pte[PTE_StHead] = 1; /* Start head */
+ pte[PTE_StSec] = 1; /* Start sector */
+ pte[PTE_StCyl] = 0; /* Start cylinder */
+ pte[PTE_System] = sys; /* System type */
+ n = (b_vol + sz_vol) / (63 * 255); /* (End CHS is incorrect) */
+ pte[PTE_EdHead] = 254; /* End head */
+ pte[PTE_EdSec] = (BYTE)(n >> 2 | 63); /* End sector */
+ pte[PTE_EdCyl] = (BYTE)n; /* End cylinder */
+ st_dword(pte + PTE_StLba, b_vol); /* Start offset in LBA */
+ st_dword(pte + PTE_SizLba, sz_vol); /* Size in sectors */
+ if (disk_write(pdrv, buf, 0, 1) != RES_OK) return FR_DISK_ERR; /* Write it to the MBR */
}
}
- /* 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, (WORD)i);
- tbl[BPB_SecPerClus] = (BYTE)au; /* Sectors per cluster */
- st_word(tbl + BPB_RsvdSecCnt, (WORD)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, (WORD)i);
- if (n_vol < 0x10000) { /* Number of total sectors */
- st_word(tbl + BPB_TotSec16, (WORD)n_vol);
- } else {
- st_dword(tbl + BPB_TotSec32, (WORD)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); /* Volume offset */
- 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_RootClus32, 2); /* Root directory start cluster (2) */
- st_word(tbl + BPB_FSInfo32, 1); /* FSINFO record offset (VBR + 1) */
- st_word(tbl + BPB_BkBootSec32, 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, (WORD)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 it to the backup VBR if needed (VBR + 6) */
- disk_write(pdrv, tbl, b_vol + 6, 1);
- }
+ if (disk_ioctl(pdrv, CTRL_SYNC, 0) != RES_OK) return FR_DISK_ERR;
- /* 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;
+ return FR_OK;
}
@@ -5417,7 +5662,7 @@ FRESULT f_mkfs (
FRESULT f_fdisk (
BYTE pdrv, /* Physical drive number */
- const DWORD szt[], /* Pointer to the size table for each partitions */
+ const DWORD* szt, /* Pointer to the size table for each partitions */
void* work /* Pointer to the working buffer */
)
{
@@ -5432,7 +5677,7 @@ FRESULT f_fdisk (
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 */
+ /* Determine the CHS without any care of the drive geometry */
for (n = 16; n < 256 && sz_disk / n / 63 > 1024; n *= 2) ;
if (n == 256) n--;
e_hd = n - 1;
@@ -5476,7 +5721,6 @@ FRESULT f_fdisk (
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 */
@@ -5568,14 +5812,14 @@ TCHAR* f_gets (
/*-----------------------------------------------------------------------*/
typedef struct {
- FIL* fp;
- int idx, nchr;
- BYTE buf[64];
+ FIL *fp; /* Ptr to the writing file */
+ int idx, nchr; /* Write index of buf[] (-1:error), number of chars written */
+ BYTE buf[64]; /* Write buffer */
} putbuff;
static
-void putc_bfd (
+void putc_bfd ( /* Buffered write with code conversion */
putbuff* pb,
TCHAR c
)
@@ -5588,7 +5832,7 @@ void putc_bfd (
putc_bfd(pb, '\r');
}
- i = pb->idx; /* Buffer write index (-1:error) */
+ i = pb->idx; /* Write index of pb->buf[] */
if (i < 0) return;
#if _LFN_UNICODE
@@ -5630,6 +5874,31 @@ void putc_bfd (
}
+static
+int putc_flush ( /* Flush left characters in the buffer */
+ putbuff* pb
+)
+{
+ UINT nw;
+
+ 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;
+}
+
+
+static
+void putc_init ( /* Initialize write buffer */
+ putbuff* pb,
+ FIL* fp
+)
+{
+ pb->fp = fp;
+ pb->nchr = pb->idx = 0;
+}
+
+
int f_putc (
TCHAR c, /* A character to be output */
@@ -5637,18 +5906,11 @@ int f_putc (
)
{
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;
+ putc_init(&pb, fp);
+ putc_bfd(&pb, c); /* Put the character */
+ return putc_flush(&pb);
}
@@ -5664,19 +5926,11 @@ int f_puts (
)
{
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;
+ putc_init(&pb, fp);
+ while (*str) putc_bfd(&pb, *str++); /* Put the string */
+ return putc_flush(&pb);
}
@@ -5693,15 +5947,14 @@ int f_printf (
)
{
va_list arp;
+ putbuff pb;
BYTE f, r;
- UINT nw, i, j, w;
+ UINT i, j, w;
DWORD v;
TCHAR c, d, str[32], *p;
- putbuff pb;
- pb.fp = fp; /* Initialize output buffer */
- pb.nchr = pb.idx = 0;
+ putc_init(&pb, fp);
va_start(arp, fmt);
@@ -5777,10 +6030,7 @@ int f_printf (
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;
+ return putc_flush(&pb);
}
#endif /* !_FS_READONLY */
diff --git a/source/fatfs/ff.h b/source/fatfs/ff.h
old mode 100644
new mode 100755
index 437093f..5984c8e
--- a/source/fatfs/ff.h
+++ b/source/fatfs/ff.h
@@ -1,11 +1,13 @@
-/*---------------------------------------------------------------------------/
-/ FatFs - FAT file system module include R0.12 (C)ChaN, 2016
-/----------------------------------------------------------------------------/
-/ FatFs module is a free software that opened under license policy of
-/ following conditions.
+/*----------------------------------------------------------------------------/
+/ FatFs - Generic FAT file system module R0.12a /
+/-----------------------------------------------------------------------------/
/
/ Copyright (C) 2016, ChaN, all right reserved.
/
+/ FatFs module is an open source software. Redistribution and use of FatFs in
+/ source and binary forms, with or without modification, are permitted provided
+/ that the following condition is met:
+
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
@@ -13,11 +15,11 @@
/ 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 88100 /* Revision ID */
+#define _FATFS 80186 /* Revision ID */
#ifdef __cplusplus
extern "C" {
@@ -25,6 +27,7 @@ extern "C" {
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
+
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
@@ -52,7 +55,7 @@ extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
/* Type of path name strings on FatFs API */
-#if _LFN_UNICODE /* Unicode string */
+#if _LFN_UNICODE /* Unicode (UTF-16) string */
#if _USE_LFN == 0
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
@@ -61,14 +64,25 @@ 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
+
+
+/* Type of file size variables */
+
+#if _FS_EXFAT
+#if _USE_LFN == 0
+#error LFN must be enabled when enable exFAT
+#endif
+typedef QWORD FSIZE_t;
+#else
+typedef DWORD FSIZE_t;
#endif
@@ -87,6 +101,9 @@ typedef struct {
#if _MAX_SS != _MIN_SS
WORD ssize; /* Sector size (512, 1024, 2048 or 4096) */
#endif
+#if _USE_LFN != 0
+ WCHAR* lfnbuf; /* LFN working buffer */
+#endif
#if _FS_EXFAT
BYTE* dirbuf; /* Directory entry block scratchpad buffer */
#endif
@@ -117,19 +134,6 @@ typedef struct {
-/* Type of file size variables and object identifier */
-
-#if _FS_EXFAT
-#if _USE_LFN == 0
-#error LFN must be enabled when enable exFAT
-#endif
-typedef QWORD FSIZE_t;
-#else
-typedef DWORD FSIZE_t;
-#endif
-
-
-
/* Object ID and allocation information (_FDID) */
typedef struct {
@@ -159,14 +163,14 @@ typedef struct {
BYTE flag; /* File status flags */
BYTE err; /* Abort flag (error code) */
FSIZE_t fptr; /* File read/write pointer (Zeroed on file open) */
- DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
+ DWORD clust; /* Current cluster of fpter (invalid when fprt is 0) */
DWORD sect; /* 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) */
+ DWORD* cltbl; /* Pointer to the cluster link map table (nulled on open, set by application) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
@@ -183,10 +187,9 @@ typedef struct {
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the directory item in the win[] */
- BYTE* fn; /* Pointer to the SFN (in/out) {body[8],ext[3],status[1]} */
+ BYTE fn[12]; /* SFN (in/out) {body[8],ext[3],status[1]} */
#if _USE_LFN != 0
DWORD blk_ofs; /* Offset of current entry block being processed (0xFFFFFFFF:Invalid) */
- WCHAR* lfn; /* Pointer to the LFN working buffer */
#endif
#if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
@@ -229,7 +232,7 @@ typedef enum {
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_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any problem */
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 */
@@ -244,11 +247,11 @@ typedef enum {
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_lseek (FIL* fp, FSIZE_t 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_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from the file */
+FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to the file */
+FRESULT f_lseek (FIL* fp, FSIZE_t ofs); /* Move file pointer of the file object */
+FRESULT f_truncate (FIL* fp); /* Truncate the file */
+FRESULT f_sync (FIL* fp); /* Flush cached data of the 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 */
@@ -258,8 +261,8 @@ 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 timestamp of the file/dir */
+FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of a file/dir */
+FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change timestamp of a 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 */
@@ -269,8 +272,8 @@ FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_expand (FIL* fp, FSIZE_t szf, BYTE opt); /* Allocate a contiguous block to the file */
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_mkfs (const TCHAR* path, BYTE opt, DWORD au, void* work, UINT len); /* Create a FAT volume */
+FRESULT f_fdisk (BYTE pdrv, const DWORD* szt, void* work); /* Divide a physical drive into some partitions */
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 */
@@ -323,40 +326,37 @@ int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
/* Flags and offset address */
-/* File access control and file status flags (FIL.flag) */
-
+/* File access mode and open method flags (3rd argument of f_open) */
#define FA_READ 0x01
#define FA_WRITE 0x02
#define FA_OPEN_EXISTING 0x00
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
-#define _FA_MODIFIED 0x20
-#define _FA_DIRTY 0x40
+#define FA_OPEN_APPEND 0x30
+/* Fast seek controls (2nd argument of f_lseek) */
+#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
-/* FAT sub type (FATFS.fs_type) */
+/* Format options (2nd argument of f_mkfs) */
+#define FM_FAT 0x01
+#define FM_FAT32 0x02
+#define FM_EXFAT 0x04
+#define FM_ANY 0x07
+#define FM_SFD 0x08
+/* Filesystem type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
#define FS_EXFAT 4
-
-/* File attribute bits for directory entry */
-
+/* File attribute bits for directory entry (FILINFO.fattrib) */
#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 controls */
-#define CREATE_LINKMAP ((FSIZE_t)0 - 1)
#ifdef __cplusplus
diff --git a/source/fatfs/ffconf.h b/source/fatfs/ffconf.h
old mode 100644
new mode 100755
index f40a383..ca0548d
--- a/source/fatfs/ffconf.h
+++ b/source/fatfs/ffconf.h
@@ -1,8 +1,8 @@
/*---------------------------------------------------------------------------/
-/ FatFs - FAT file system module configuration file R0.12 (C)ChaN, 2016
+/ FatFs - FAT file system module configuration file
/---------------------------------------------------------------------------*/
-#define _FFCONF 88100 /* Revision ID */
+#define _FFCONF 80186 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -62,8 +62,7 @@
#define _USE_FORWARD 0
-/* This option switches f_forward() function. (0:Disable or 1:Enable)
-/ To enable it, also _FS_TINY need to be 1. */
+/* This option switches f_forward() function. (0:Disable or 1:Enable) */
/*---------------------------------------------------------------------------/
@@ -118,13 +117,13 @@
#define _LFN_UNICODE 0
-/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
+/* This option switches character encoding on the API. (0:ANSI/OEM or 1:UTF-16)
/ To use Unicode string for the path name, enable LFN and set _LFN_UNICODE = 1.
/ This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 3
-/* When _LFN_UNICODE == 1, this option selects the character encoding on the file to
+/* When _LFN_UNICODE == 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
@@ -153,7 +152,7 @@
#define _STR_VOLUME_ID 0
-#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
+#define _VOLUME_STRS "RAM","NAND","CF","SD","SD2","USB","USB2","USB3"
/* _STR_VOLUME_ID switches string support of volume ID.
/ 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
@@ -217,7 +216,7 @@
#define _FS_NORTC 1
-#define _NORTC_MON 3
+#define _NORTC_MON 1
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2016
/* The option _FS_NORTC switches timestamp functiton. If the system does not have
diff --git a/source/fatfs/integer.h b/source/fatfs/integer.h
old mode 100644
new mode 100755
diff --git a/source/fatfs/option/ccsbcs.c b/source/fatfs/option/ccsbcs.c
old mode 100644
new mode 100755
diff --git a/source/firm.c b/source/firm.c
index 8ebd097..c8f8744 100755
--- a/source/firm.c
+++ b/source/firm.c
@@ -33,6 +33,8 @@
#include "draw.h"
#include "screen.h"
#include "buttons.h"
+#include "pin.h"
+#include "i2c.h"
#include "../build/injector.h"
static firmHeader *const firm = (firmHeader *)0x24000000;
@@ -45,10 +47,12 @@ bool isN3DS;
FirmwareSource firmSource;
+PINData pin;
+
void main(void)
{
bool isFirmlaunch,
- updatedSys;
+ isA9lh;
u32 newConfig,
emuHeader,
@@ -57,7 +61,6 @@ void main(void)
FirmwareType firmType;
FirmwareSource nandType;
ConfigurationStatus needConfig;
- A9LHMode a9lhMode;
//Detect the console being used
isN3DS = PDN_MPCORE_CFG == 7;
@@ -88,82 +91,44 @@ void main(void)
nandType = (FirmwareSource)BOOTCONFIG(0, 3);
firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
- a9lhMode = (A9LHMode)BOOTCONFIG(3, 1);
- updatedSys = a9lhMode != NO_A9LH && CONFIG(1);
+ isA9lh = BOOTCONFIG(3, 1) != 0;
}
else
{
//Get pressed buttons
u32 pressed = HID_PAD;
- //If no configuration file exists or SELECT is held, load configuration menu
- if(needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1)))
- {
- configureCFW(configPath);
-
- //Zero the last booted FIRM flag
- CFG_BOOTENV = 0;
-
- nbChronoStarted = 1;
- chrono(0);
- chrono(2);
-
- //Update pressed buttons
- pressed = HID_PAD;
- }
-
isFirmlaunch = false;
firmType = NATIVE_FIRM;
//Determine if booting with A9LH
- bool a9lhBoot = !PDN_SPI_CNT;
+ isA9lh = !PDN_SPI_CNT;
- //Determine if A9LH is installed and the user has an updated sysNAND
- if(a9lhBoot || CONFIG(2))
- {
- a9lhMode = A9LH_WITH_NFIRM_FIRMPROT;
- updatedSys = CONFIG(1);
- }
- else
- {
- a9lhMode = NO_A9LH;
- updatedSys = false;
- }
+ //Determine if the user chose to use the SysNAND FIRM as default for a R boot
+ bool useSysAsDefault = isA9lh ? CONFIG(1) : false;
- newConfig = (u32)a9lhMode << 3;
+ newConfig = (u32)isA9lh << 3;
- if(a9lhBoot)
+ //If it's a MCU reboot, try to force boot options
+ if(isA9lh && CFG_BOOTENV)
{
- //If it's a MCU reboot, try to force boot options
- if(CFG_BOOTENV)
+ //Always force a sysNAND boot when quitting AGB_FIRM
+ if(CFG_BOOTENV == 7)
{
- //Always force a sysNAND boot when quitting AGB_FIRM
- if(CFG_BOOTENV == 7)
- {
- nandType = FIRMWARE_SYSNAND;
- firmSource = updatedSys ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
- needConfig = DONT_CONFIGURE;
+ nandType = FIRMWARE_SYSNAND;
+ firmSource = useSysAsDefault ? FIRMWARE_SYSNAND : (FirmwareSource)BOOTCONFIG(2, 1);
+ needConfig = DONT_CONFIGURE;
- //Flag to prevent multiple boot options-forcing
- newConfig |= 1 << 4;
- }
-
- /* Else, force the last used boot options unless a button is pressed
- or the no-forcing flag is set */
- else if(!pressed && !BOOTCONFIG(4, 1))
- {
- nandType = (FirmwareSource)BOOTCONFIG(0, 3);
- firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
- needConfig = DONT_CONFIGURE;
- }
+ //Flag to prevent multiple boot options-forcing
+ newConfig |= 1 << 4;
}
- //If the SAFE MODE combo is held, force a sysNAND boot
- else if(pressed == SAFE_MODE)
+ /* Else, force the last used boot options unless a button is pressed
+ or the no-forcing flag is set */
+ else if(!pressed && !BOOTCONFIG(4, 1))
{
- a9lhMode = A9LH_WITH_SFIRM_FIRMPROT;
- nandType = FIRMWARE_SYSNAND;
- firmSource = FIRMWARE_SYSNAND;
+ nandType = (FirmwareSource)BOOTCONFIG(0, 3);
+ firmSource = (FirmwareSource)BOOTCONFIG(2, 1);
needConfig = DONT_CONFIGURE;
}
}
@@ -171,36 +136,83 @@ void main(void)
//Boot options aren't being forced
if(needConfig != DONT_CONFIGURE)
{
- /* If L and R/A/Select or one of the single payload buttons are pressed,
- chainload an external payload */
- if(DEVMODE || (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
- loadPayload(pressed);
+ //If no configuration file exists or SELECT is held, load configuration menu
+ bool shouldLoadConfigurationMenu = needConfig == CREATE_CONFIGURATION || ((pressed & BUTTON_SELECT) && !(pressed & BUTTON_L1));
+ bool pinExists = CONFIG(7) && readPin(&pin);
- //If screens are inited or the corresponding option is set, load splash screen
- if((PDN_GPU_CNT != 1 || CONFIG(7)) && loadSplash())
+ if(pinExists || shouldLoadConfigurationMenu)
{
- nbChronoStarted = 2;
- chrono(0);
+ bool needToDeinit = initScreens();
+
+ //If we get here we should check the PIN (if it exists) in all cases
+ if(pinExists) verifyPin(&pin, true);
+
+ if(shouldLoadConfigurationMenu)
+ {
+ configureCFW(configPath);
+
+ if(!pinExists && CONFIG(7)) pin = newPin();
+
+ //Zero the last booted FIRM flag
+ CFG_BOOTENV = 0;
+
+ nbChronoStarted = 1;
+ chrono(0);
+ chrono(2);
+
+ //Update pressed buttons
+ pressed = HID_PAD;
+ }
+
+ if(needToDeinit)
+ {
+ //Turn off backlight
+ i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x16);
+ deinitScreens();
+ PDN_GPU_CNT = 1;
+ }
}
- //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
- if(pressed & BUTTON_R1)
+ if(isA9lh && !CFG_BOOTENV && pressed == SAFE_MODE)
{
- nandType = (updatedSys) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
- firmSource = (updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
+ nandType = FIRMWARE_SYSNAND;
+ firmSource = FIRMWARE_SYSNAND;
}
-
- /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
- with their own FIRM */
else
- {
- nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
- firmSource = nandType;
- }
+ {
+ /* If L and R/A/Select or one of the single payload buttons are pressed,
+ chainload an external payload (verify the PIN if needed)*/
+ bool shouldLoadPayload = (pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS));
- /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
- or vice-versa, boot the second emuNAND */
- if(nandType != FIRMWARE_SYSNAND && (CONFIG(3) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
+ if(shouldLoadPayload)
+ loadPayload(pressed);
+
+ //If screens are inited or the corresponding option is set, load splash screen
+ if((PDN_GPU_CNT != 1 || CONFIG(6)) && loadSplash())
+ {
+ nbChronoStarted = 2;
+ chrono(0);
+ }
+
+ //If R is pressed, boot the non-updated NAND with the FIRM of the opposite one
+ if(pressed & BUTTON_R1)
+ {
+ nandType = (useSysAsDefault) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
+ firmSource = (useSysAsDefault) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND;
+ }
+
+ /* Else, boot the NAND the user set to autoboot or the opposite one, depending on L,
+ with their own FIRM */
+ else
+ {
+ nandType = (CONFIG(0) != !(pressed & BUTTON_L1)) ? FIRMWARE_EMUNAND : FIRMWARE_SYSNAND;
+ firmSource = nandType;
+ }
+
+ /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
+ or vice-versa, boot the second emuNAND */
+ if(nandType != FIRMWARE_SYSNAND && (CONFIG(2) == !(pressed & BUTTON_B))) nandType = FIRMWARE_EMUNAND2;
+ }
}
}
@@ -226,22 +238,24 @@ void main(void)
//Preserve user settings (last 26 bits)
newConfig |= config & 0xFFFFFFC0;
- fileWrite(&newConfig, configPath, 4);
+ if(!fileWrite(&newConfig, configPath, 4))
+ error("Error writing the configuration file");
}
}
- loadFirm(firmType, firmType == NATIVE_FIRM && firmSource == ((updatedSys) ? FIRMWARE_SYSNAND : FIRMWARE_EMUNAND));
+ u32 firmVersion = loadFirm(firmType);
switch(firmType)
{
case NATIVE_FIRM:
- patchNativeFirm(nandType, emuHeader, a9lhMode);
+ patchNativeFirm(firmVersion, nandType, emuHeader, isA9lh);
break;
case SAFE_FIRM:
patchSafeFirm();
break;
default:
- patchLegacyFirm(firmType);
+ //Skip patching on unsupported O3DS AGB/TWL FIRMs
+ if(isN3DS || firmVersion >= (firmType == TWL_FIRM ? 0x16 : 0xB)) patchLegacyFirm(firmType);
break;
}
@@ -254,69 +268,41 @@ void main(void)
launchFirm(firmType, isFirmlaunch);
}
-static inline void loadFirm(FirmwareType firmType, bool externalFirm)
+static inline u32 loadFirm(FirmwareType firmType)
{
section = firm->section;
- bool externalFirmLoaded = externalFirm &&
- fileRead(firm, "/luma/firmware.bin") &&
- (((u32)section[2].address >> 8) & 0xFF) == (isN3DS ? 0x60 : 0x68);
+ //Load FIRM from CTRNAND, unless it's an O3DS and we're loading a pre-5.0 NATIVE FIRM
+ u32 firmVersion = firmRead(firm, (u32)firmType);
- /* If the conditions to load the external FIRM aren't met, or reading fails, or the FIRM
- doesn't match the console, load FIRM from CTRNAND */
- if(!externalFirmLoaded)
+ if(!isN3DS && firmType == NATIVE_FIRM && firmVersion < 0x25)
{
- const char *firmFolders[4][2] = {{ "00000002", "20000002" },
- { "00000102", "20000102" },
- { "00000202", "20000202" },
- { "00000003", "20000003" }};
+ if(!fileRead(firm, "/luma/firmware.bin") || (((u32)section[2].address >> 8) & 0xFF) != 0x68)
+ error("An old unsupported FIRM has been detected.\nCopy firmware.bin in /luma to boot");
- firmRead(firm, firmFolders[(u32)firmType][isN3DS ? 1 : 0]);
- decryptExeFs((u8 *)firm);
+ //9.6 O3DS FIRM
+ firmVersion = 0x49;
}
+ else decryptExeFs((u8 *)firm);
+
+ return firmVersion;
}
-static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHMode a9lhMode)
+static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh)
{
u8 *arm9Section = (u8 *)firm + section[2].offset,
*arm11Section1 = (u8 *)firm + section[1].offset;
- bool is90Firm;
-
if(isN3DS)
{
- u32 a9lVersion;
-
- //Determine the NATIVE_FIRM/arm9loader version
- switch(arm9Section[0x53])
- {
- case 0xFF:
- a9lVersion = 0;
- break;
- case '1':
- a9lVersion = 1;
- break;
- default:
- a9lVersion = 2;
- break;
- }
-
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
- arm9Loader(arm9Section, a9lVersion);
+ arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
- is90Firm = a9lVersion == 0;
- }
- else
- {
- //Determine if we're booting the 9.0 FIRM
- u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
- is90Firm = memcmp(section[2].hash, firm90Hash, 0x10) == 0;
}
- //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY
- if(a9lhMode == NO_A9LH)
- setRSAMod0DerivedKeys();
-
+ //Sets the 7.x NCCH KeyX and the 6.x gamecard save data KeyY on >= 6.0 O3DS FIRMs, if not using A9LH
+ else if(!isA9lh && firmVersion >= 0x29) setRSAMod0DerivedKeys();
+
//Find the Process9 .code location, size and memory address
u32 process9Size,
process9MemAddr;
@@ -333,17 +319,18 @@ static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHM
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
- else if(a9lhMode != NO_A9LH) patchFirmWrites(process9Offset, process9Size);
+ else if(isA9lh) patchFirmWrites(process9Offset, process9Size);
- //Apply firmlaunch patches, not on 9.0 FIRM as it breaks firmlaunchhax
- if(!is90Firm || a9lhMode == A9LH_WITH_SFIRM_FIRMPROT) patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
+ //Apply firmlaunch patches
+ patchFirmlaunches(process9Offset, process9Size, process9MemAddr);
- if(!is90Firm)
+ //11.0 FIRM patches
+ if(firmVersion >= (isN3DS ? 0x21 : 0x52))
{
- //Apply anti-anti-DG patches for >= 11.0 firmwares
+ //Apply anti-anti-DG patches
patchTitleInstallMinVersionCheck(process9Offset, process9Size);
- //Does nothing if svcBackdoor is still there
+ //Restore svcBackdoor
reimplementSvcBackdoor(arm11Section1, section[1].size);
}
@@ -376,7 +363,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(isN3DS)
{
- arm9Loader(arm9Section, 0);
+ arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801301C;
}
@@ -387,7 +374,7 @@ static inline void patchLegacyFirm(FirmwareType firmType)
patchSvcBreak9(arm9Section, section[3].size, (u32)(section[3].address));
}
- applyLegacyFirmPatches((u8 *)firm, firmType, isN3DS);
+ applyLegacyFirmPatches((u8 *)firm, firmType);
}
static inline void patchSafeFirm(void)
@@ -397,7 +384,7 @@ static inline void patchSafeFirm(void)
if(isN3DS)
{
//Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
- arm9Loader(arm9Section, 0);
+ arm9Loader(arm9Section);
firm->arm9Entry = (u8 *)0x801B01C;
patchFirmWrites(arm9Section, section[2].size);
@@ -500,12 +487,12 @@ static inline void launchFirm(FirmwareType firmType, bool isFirmlaunch)
arm11 = (u32 *)0x1FFFFFF8;
}
- flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
- flushEntireICache();
-
//Set ARM11 kernel entrypoint
*arm11 = (u32)firm->arm11Entry;
+ flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
+ flushEntireICache();
+
//Final jump to ARM9 kernel
((void (*)())firm->arm9Entry)();
}
\ No newline at end of file
diff --git a/source/firm.h b/source/firm.h
index 1610cd7..72a3615 100644
--- a/source/firm.h
+++ b/source/firm.h
@@ -53,15 +53,8 @@ typedef enum ConfigurationStatus
CREATE_CONFIGURATION = 2
} ConfigurationStatus;
-typedef enum A9LHMode
-{
- NO_A9LH = 0,
- A9LH_WITH_NFIRM_FIRMPROT = 1,
- A9LH_WITH_SFIRM_FIRMPROT = 2
-} A9LHMode;
-
-static inline void loadFirm(FirmwareType firmType, bool externalFirm);
-static inline void patchNativeFirm(FirmwareSource nandType, u32 emuHeader, A9LHMode a9lhMode);
+static inline u32 loadFirm(FirmwareType firmType);
+static inline void patchNativeFirm(u32 firmVersion, FirmwareSource nandType, u32 emuHeader, bool isA9lh);
static inline void patchLegacyFirm(FirmwareType firmType);
static inline void patchSafeFirm(void);
static inline void copySection0AndInjectSystemModules(void);
diff --git a/source/fs.c b/source/fs.c
index a6192cb..cb9f458 100644
--- a/source/fs.c
+++ b/source/fs.c
@@ -31,12 +31,10 @@
static FATFS sdFs,
nandFs;
-bool mountFs(void)
+void mountFs(void)
{
- if(f_mount(&sdFs, "0:", 1) != FR_OK) return false;
+ f_mount(&sdFs, "0:", 1);
f_mount(&nandFs, "1:", 0);
-
- return true;
}
u32 fileRead(void *dest, const char *path)
@@ -62,7 +60,7 @@ u32 getFileSize(const char *path)
return fileRead(NULL, path);
}
-void fileWrite(const void *buffer, const char *path, u32 size)
+bool fileWrite(const void *buffer, const char *path, u32 size)
{
FIL file;
@@ -71,7 +69,16 @@ void fileWrite(const void *buffer, const char *path, u32 size)
unsigned int written;
f_write(&file, buffer, size, &written);
f_close(&file);
+
+ return true;
}
+
+ return false;
+}
+
+void createDirectory(const char *path)
+{
+ f_mkdir(path);
}
void loadPayload(u32 pressed)
@@ -115,6 +122,7 @@ void loadPayload(u32 pressed)
flushDCacheRange(loaderAddress, loader_size);
flushICacheRange(loaderAddress, loader_size);
+
((void (*)())loaderAddress)();
}
}
@@ -140,17 +148,22 @@ void findDumpFile(const char *path, char *fileName)
f_closedir(&dir);
}
-void firmRead(void *dest, const char *firmFolder)
+u32 firmRead(void *dest, u32 firmType)
{
+ const char *firmFolders[4][2] = {{ "00000002", "20000002" },
+ { "00000102", "20000102" },
+ { "00000202", "20000202" },
+ { "00000003", "20000003" }};
+
char path[48] = "1:/title/00040138/00000000/content";
- memcpy(&path[18], firmFolder, 8);
+ memcpy(&path[18], firmFolders[firmType][isN3DS ? 1 : 0], 8);
DIR dir;
FILINFO info;
f_opendir(&dir, path);
- u32 id = 0xFFFFFFFF;
+ u32 firmVersion = 0xFFFFFFFF;
//Parse the target directory
while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
@@ -159,15 +172,15 @@ void firmRead(void *dest, const char *firmFolder)
if(info.altname[9] != 'A') continue;
//Convert the .app name to an integer
- u32 tempId = 0;
+ u32 tempVersion = 0;
for(char *tmp = info.altname; *tmp != '.'; tmp++)
{
- tempId <<= 4;
- tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
+ tempVersion <<= 4;
+ tempVersion += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
}
//Found an older cxi
- if(tempId < id) id = tempId;
+ if(tempVersion < firmVersion) firmVersion = tempVersion;
}
f_closedir(&dir);
@@ -179,12 +192,15 @@ void firmRead(void *dest, const char *firmFolder)
u32 i = 42;
//Convert back the .app name from integer to array
- while(id)
+ u32 tempVersion = firmVersion;
+ while(tempVersion)
{
static const char hexDigits[] = "0123456789ABCDEF";
- path[i--] = hexDigits[id & 0xF];
- id >>= 4;
+ path[i--] = hexDigits[tempVersion & 0xF];
+ tempVersion >>= 4;
}
fileRead(dest, path);
+
+ return firmVersion;
}
\ No newline at end of file
diff --git a/source/fs.h b/source/fs.h
index 5305bc0..165dce9 100644
--- a/source/fs.h
+++ b/source/fs.h
@@ -26,10 +26,13 @@
#define PATTERN(a) a "_*.bin"
-bool mountFs(void);
+extern bool isN3DS;
+
+void mountFs(void);
u32 getFileSize(const char *path);
u32 fileRead(void *dest, const char *path);
-void fileWrite(const void *buffer, const char *path, u32 size);
+bool fileWrite(const void *buffer, const char *path, u32 size);
+void createDirectory(const char *path);
void findDumpFile(const char *path, char *fileName);
void loadPayload(u32 pressed);
-void firmRead(void *dest, const char *firmFolder);
\ No newline at end of file
+u32 firmRead(void *dest, u32 firmType);
\ No newline at end of file
diff --git a/source/patches.c b/source/patches.c
index ff558f5..b5e999e 100644
--- a/source/patches.c
+++ b/source/patches.c
@@ -240,10 +240,10 @@ void patchTitleInstallMinVersionCheck(u8 *pos, u32 size)
u8 *off = memsearch(pos, pattern, size, 4);
- if(off != NULL) off[4] = 0xE0;
+ off[4] = 0xE0;
}
-void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS)
+void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType)
{
const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
@@ -264,7 +264,7 @@ void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS)
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == TWL_FIRM ? (sizeof(twlPatches) / sizeof(patchData)) :
- (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(6));
+ (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(5));
const patchData *patches = firmType == TWL_FIRM ? twlPatches : agbPatches;
//Patch
diff --git a/source/patches.h b/source/patches.h
index 492ab05..5aa5d91 100644
--- a/source/patches.h
+++ b/source/patches.h
@@ -33,6 +33,8 @@ typedef struct patchData {
u32 type;
} patchData;
+extern bool isN3DS;
+
u8 *getProcess9(u8 *pos, u32 size, u32 *process9Size, u32 *process9MemAddr);
u32* getInfoForArm11ExceptionHandlers(u8 *pos, u32 size, u32 *stackAddr, u32 *codeSetOffset);
void patchSignatureChecks(u8 *pos, u32 size);
@@ -46,5 +48,5 @@ void patchSvcBreak11(u8 *pos, u32 size);
void patchUnitInfoValueSet(u8 *pos, u32 size);
void patchKernelFCRAMAndVRAMMappingPermissions(u8 *pos, u32 size);
void reimplementSvcBackdoor(u8 *pos, u32 size);
-void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType, bool isN3DS);
+void applyLegacyFirmPatches(u8 *pos, FirmwareType firmType);
u8 *getUnitInfoValueSet(u8 *pos, u32 size);
diff --git a/source/pin.c b/source/pin.c
new file mode 100644
index 0000000..7920708
--- /dev/null
+++ b/source/pin.c
@@ -0,0 +1,180 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2016 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program 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 .
+*
+* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
+* reasonable legal notices or author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+*/
+
+/*
+* pin.c
+* Code to manage pin locking for 3ds. By reworks.
+*/
+
+#include "draw.h"
+#include "screen.h"
+#include "utils.h"
+#include "memory.h"
+#include "buttons.h"
+#include "fs.h"
+#include "i2c.h"
+#include "pin.h"
+#include "crypto.h"
+
+bool readPin(PINData *out)
+{
+ u8 __attribute__((aligned(4))) zeroes[16] = {0};
+ u8 __attribute__((aligned(4))) tmp[32] = {0};
+ if(fileRead(out, "/luma/pin.bin") != sizeof(PINData)) return false;
+ else if(memcmp(out->magic, "PINF", 4) != 0) return false;
+
+ computePINHash(tmp, zeroes, 1);
+ return memcmp(out->testHash, tmp, 32) == 0; //test vector verification (SD card has (or hasn't) been used on another console)
+}
+
+static inline char PINKeyToLetter(u32 pressed)
+{
+ const char keys[] = "AB--------XY";
+
+ u32 i;
+ __asm__ volatile("clz %[i], %[pressed]" : [i] "=r" (i) : [pressed] "r" (pressed));
+
+ return keys[31 - i];
+}
+
+PINData newPin(void)
+{
+ clearScreens();
+
+ drawString("Enter your NEW PIN: ", 10, 10, COLOR_WHITE);
+
+ u32 pressed = 0;
+
+ // Set the default value as 0x00 so we can check if there are any unentered characters.
+ u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0}; // pad to AES block length
+
+ int charDrawPos = 20 * SPACING_X;
+ int cnt = 0;
+
+ while(true)
+ {
+ do
+ {
+ pressed = waitInput();
+ }
+ while(!(pressed & PIN_BUTTONS & ~BUTTON_START));
+
+ pressed &= PIN_BUTTONS & ~BUTTON_START;
+
+ if(!pressed) continue;
+ char key = PINKeyToLetter(pressed);
+ enteredPassword[cnt++] = (u8)key; // add character to password.
+
+ // visualize character on screen.
+ drawCharacter(key, 10 + charDrawPos, 10, COLOR_WHITE);
+ charDrawPos += 2 * SPACING_X;
+
+ // we leave the rest of the array zeroed out.
+ if (cnt >= PIN_LENGTH)
+ {
+
+ PINData pin = {0};
+ u8 __attribute__((aligned(4))) tmp[32] = {0};
+ u8 __attribute__((aligned(4))) zeroes[16] = {0};
+
+ memcpy(pin.magic, "PINF", 4);
+ pin.formatVersionMajor = 1;
+ pin.formatVersionMinor = 0;
+
+ computePINHash(tmp, zeroes, 1);
+ memcpy(pin.testHash, tmp, 32);
+
+ computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
+ memcpy(pin.hash, tmp, 32);
+
+ fileWrite(&pin, "/luma/pin.bin", sizeof(PINData));
+ return pin;
+ }
+ }
+}
+
+void verifyPin(PINData *in, bool allowQuit)
+{
+ clearScreens();
+
+ drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
+ drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
+
+ u32 pressed = 0;
+
+ // Set the default characters as 0x00 so we can check if there are any unentered characters.
+ u8 __attribute__((aligned(4))) enteredPassword[16 * ((PIN_LENGTH + 15) / 16)] = {0};
+
+ bool unlock;
+ int charDrawPos = 5 * SPACING_X, cnt = 0;
+
+ while(true)
+ {
+ do
+ {
+ pressed = waitInput();
+ }
+ while(!(pressed & PIN_BUTTONS));
+
+ pressed &= PIN_BUTTONS;// & ~BUTTON_START;
+ if(!allowQuit) pressed &= ~BUTTON_START;
+ if(!pressed) continue;
+
+ if(pressed & BUTTON_START)
+ {
+ clearScreens();
+ mcuPowerOff();
+ }
+
+ char key = PINKeyToLetter(pressed);
+ enteredPassword[cnt++] = (u8)key; // add character to password.
+
+ // visualize character on screen.
+ drawCharacter(key, 10 + charDrawPos, 10 + 2 * SPACING_Y, COLOR_WHITE);
+ charDrawPos += 2 * SPACING_X;
+
+ if(cnt >= PIN_LENGTH)
+ {
+ u8 __attribute__((aligned(4))) tmp[32] = {0};
+
+ computePINHash(tmp, enteredPassword, (PIN_LENGTH + 15) / 16);
+ unlock = memcmp(in->hash, tmp, 32) == 0;
+
+ if (!unlock)
+ {
+ // re zero out all 16 just in case.
+ memset32(enteredPassword, 0, 16);
+
+ pressed = 0;
+ charDrawPos = 5 * SPACING_X;
+ cnt = 0;
+
+ clearScreens();
+
+ drawString("Press START to shutdown or enter pin to proceed.", 10, 10, COLOR_WHITE);
+ drawString("Pin: ", 10, 10 + 2 * SPACING_Y, COLOR_WHITE);
+ drawString("Wrong pin! Try again!", 10, 10 + 3 * SPACING_Y, COLOR_RED);
+ }
+ else return;
+ }
+ }
+}
\ No newline at end of file
diff --git a/source/pin.h b/source/pin.h
new file mode 100644
index 0000000..462d73f
--- /dev/null
+++ b/source/pin.h
@@ -0,0 +1,49 @@
+/*
+* This file is part of Luma3DS
+* Copyright (C) 2016 Aurora Wright, TuxSH
+*
+* This program is free software: you can redistribute it and/or modify
+* it under the terms of the GNU General Public License as published by
+* the Free Software Foundation, either version 3 of the License, or
+* (at your option) any later version.
+*
+* This program 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 .
+*
+* Additional Terms 7.b of GPLv3 applies to this file: Requiring preservation of specified
+* reasonable legal notices or author attributions in that material or in the Appropriate Legal
+* Notices displayed by works containing it.
+*/
+
+/*
+* pin.h
+*
+* Code to manage pin locking for 3ds. By reworks.
+*/
+
+#pragma once
+
+#include "types.h"
+
+#ifndef PIN_LENGTH
+ #define PIN_LENGTH 4
+#endif
+
+typedef struct __attribute__((packed))
+{
+ char magic[4];
+ u16 formatVersionMajor, formatVersionMinor;
+
+ u8 testHash[32];
+ u8 hash[32];
+} PINData;
+
+bool readPin(PINData* out);
+
+PINData newPin(void);
+void verifyPin(PINData *in, bool allowQuit);
\ No newline at end of file
diff --git a/source/screen.c b/source/screen.c
index 523500c..b56a1e5 100644
--- a/source/screen.c
+++ b/source/screen.c
@@ -32,39 +32,36 @@
#include "draw.h"
#include "i2c.h"
-#define ARM11_STUB_ADDRESS (0x25000000 - 0x40) //It's currently only 0x28 bytes large. We're putting 0x40 just to be sure here
-#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
-vu32 *arm11Entry = (vu32 *)0x1FFFFFF8;
+vu32 *const arm11Entry = (vu32 *)0x1FFFFFF8;
+static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
void __attribute__((naked)) arm11Stub(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
-
+
//Wait for the entry to be set
while(*arm11Entry == ARM11_STUB_ADDRESS);
-
+
//Jump to it
((void (*)())*arm11Entry)();
}
-static inline void invokeArm11Function(void (*func)())
+static void invokeArm11Function(void (*func)())
{
static bool hasCopiedStub = false;
if(!hasCopiedStub)
{
- memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x40);
- flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x40);
+ memcpy((void *)ARM11_STUB_ADDRESS, arm11Stub, 0x30);
+ flushDCacheRange((void *)ARM11_STUB_ADDRESS, 0x30);
hasCopiedStub = true;
}
-
+
*arm11Entry = (u32)func;
while(*arm11Entry);
*arm11Entry = ARM11_STUB_ADDRESS;
}
-static const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
-
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
@@ -83,25 +80,24 @@ void deinitScreens(void)
if(PDN_GPU_CNT != 1) invokeArm11Function(ARM11);
}
-void updateBrightness(u32 brightnessLevel)
+void updateBrightness(u32 brightnessIndex)
{
- static int brightnessValue;
-
- brightnessValue = brightness[brightnessLevel];
-
+ static u32 brightnessLevel;
+ brightnessLevel = brightness[brightnessIndex];
+
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
- __asm(".word 0xF10C01C0");
-
+ __asm(".word 0xF10C01C0");
+
//Change brightness
- *(vu32 *)0x10202240 = brightnessValue;
- *(vu32 *)0x10202A40 = brightnessValue;
+ *(vu32 *)0x10202240 = brightnessLevel;
+ *(vu32 *)0x10202A40 = brightnessLevel;
WAIT_FOR_ARM9();
}
-
- flushDCacheRange(&brightnessValue, 4);
+
+ flushDCacheRange(&brightnessLevel, 4);
invokeArm11Function(ARM11);
}
@@ -111,9 +107,8 @@ void clearScreens(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
-
+
//Setting up two simultaneous memory fills using the GPU
-
vu32 *REGs_PSC0 = (vu32 *)0x10400010;
REGs_PSC0[0] = (u32)fb->top_left >> 3; //Start address
REGs_PSC0[1] = (u32)(fb->top_left + 0x46500) >> 3; //End address
@@ -125,7 +120,7 @@ void clearScreens(void)
REGs_PSC1[1] = (u32)(fb->bottom + 0x38400) >> 3; //End address
REGs_PSC1[2] = 0; //Fill value
REGs_PSC1[3] = (2 << 8) | 1; //32-bit pattern; start
-
+
while(!((REGs_PSC0[3] & 2) && (REGs_PSC1[3] & 2)));
if(fb->top_right != fb->top_left)
@@ -134,33 +129,33 @@ void clearScreens(void)
REGs_PSC0[1] = (u32)(fb->top_right + 0x46500) >> 3; //End address
REGs_PSC0[2] = 0; //Fill value
REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
-
+
while(!(REGs_PSC0[3] & 2));
}
-
+
WAIT_FOR_ARM9();
}
-
+
flushDCacheRange((void *)fb, sizeof(struct fb));
invokeArm11Function(ARM11);
}
-u32 initScreens(void)
+bool initScreens(void)
{
- u32 needToInit = PDN_GPU_CNT == 1;
+ bool needToInit = PDN_GPU_CNT == 1;
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts
__asm(".word 0xF10C01C0");
- u32 brightnessLevel = MULTICONFIG(0);
+ u32 brightnessLevel = brightness[MULTICONFIG(0)];
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
- *(vu32 *)0x10202240 = brightness[brightnessLevel];
- *(vu32 *)0x10202A40 = brightness[brightnessLevel];
+ *(vu32 *)0x10202240 = brightnessLevel;
+ *(vu32 *)0x10202A40 = brightnessLevel;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
@@ -246,7 +241,7 @@ u32 initScreens(void)
WAIT_FOR_ARM9();
}
-
+
if(needToInit)
{
flushDCacheRange(&config, 4);
@@ -256,9 +251,8 @@ u32 initScreens(void)
//Turn on backlight
i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
}
- else
- updateBrightness(MULTICONFIG(0));
-
+ else updateBrightness(MULTICONFIG(0));
+
clearScreens();
return needToInit;
diff --git a/source/screen.h b/source/screen.h
index 09b120e..e387825 100644
--- a/source/screen.h
+++ b/source/screen.h
@@ -30,14 +30,16 @@
#include "types.h"
#define PDN_GPU_CNT (*(vu8 *)0x10141200)
+#define ARM11_STUB_ADDRESS (0x25000000 - 0x30) //It's currently only 0x28 bytes large. We're putting 0x30 just to be sure here
+#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
static volatile struct fb {
- u8 *top_left;
- u8 *top_right;
- u8 *bottom;
+ u8 *top_left;
+ u8 *top_right;
+ u8 *bottom;
} *const fb = (volatile struct fb *)0x23FFFE00;
void deinitScreens(void);
-void updateBrightness(u32 brightnessLevel);
+void updateBrightness(u32 brightnessIndex);
void clearScreens(void);
-u32 initScreens(void);
\ No newline at end of file
+bool initScreens(void);
\ No newline at end of file
diff --git a/source/utils.c b/source/utils.c
index 52196ef..de7761c 100644
--- a/source/utils.c
+++ b/source/utils.c
@@ -23,7 +23,8 @@
#include "utils.h"
#include "i2c.h"
#include "buttons.h"
-#include "memory.h"
+#include "screen.h"
+#include "draw.h"
#include "cache.h"
u32 waitInput(void)
@@ -58,7 +59,15 @@ void mcuReboot(void)
flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
- while(1);
+ while(true);
+}
+
+void mcuPowerOff(void)
+{
+ flushEntireDCache(); //Ensure that all memory transfers have completed and that the data cache has been flushed
+
+ i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
+ while(true);
}
void mcuPowerOff(void)
@@ -104,4 +113,17 @@ void chrono(u32 seconds)
void stopChrono(void)
{
for(u32 i = 0; i < 4; i++) REG_TIMER_CNT(i) &= ~0x80;
+}
+
+void error(const char *message)
+{
+ initScreens();
+ clearScreens();
+
+ drawString("An error has occurred:", 10, 10, COLOR_RED);
+ int posY = drawString(message, 10, 30, COLOR_WHITE);
+ drawString("Press any button to shutdown", 10, posY + 2 * SPACING_Y, COLOR_WHITE);
+
+ waitInput();
+ mcuPowerOff();
}
\ No newline at end of file
diff --git a/source/utils.h b/source/utils.h
index 85485bc..80deb90 100644
--- a/source/utils.h
+++ b/source/utils.h
@@ -24,13 +24,14 @@
#include "types.h"
-u32 waitInput(void);
-void mcuReboot(void);
-void mcuPowerOff(void);
-
#define TICKS_PER_SEC 67027964ULL
#define REG_TIMER_CNT(i) *(vu16 *)(0x10003002 + 4 * i)
#define REG_TIMER_VAL(i) *(vu16 *)(0x10003000 + 4 * i)
+u32 waitInput(void);
+void mcuReboot(void);
+void mcuPowerOff(void);
+
void chrono(u32 seconds);
-void stopChrono(void);
\ No newline at end of file
+void stopChrono(void);
+void error(const char *message);
\ No newline at end of file