diff --git a/CakeBrah b/CakeBrah
index 42ebe0d..9f7cea7 160000
--- a/CakeBrah
+++ b/CakeBrah
@@ -1 +1 @@
-Subproject commit 42ebe0d0bc075ba98fa631441590de9bd2733d2b
+Subproject commit 9f7cea77d4db4d743e45b2e5193df76ffed0a571
diff --git a/CakeHax b/CakeHax
index 6b8fca0..5245c7b 160000
--- a/CakeHax
+++ b/CakeHax
@@ -1 +1 @@
-Subproject commit 6b8fca0b37a370a605f76b34b133da91a0b40f5e
+Subproject commit 5245c7b9dc232956a8578a36468f9024d8cf7001
diff --git a/Makefile b/Makefile
index 2d2402e..4460010 100644
--- a/Makefile
+++ b/Makefile
@@ -82,7 +82,7 @@ $(dir_build)/main.bin: $(dir_build)/main.elf
$(dir_build)/main.elf: $(objects)
$(LINK.o) -T linker.ld $(OUTPUT_OPTION) $^
-$(dir_build)/memory.o: CFLAGS += -O3
+$(dir_build)/memory.o $(dir_build)/strings.o: CFLAGS += -O3
$(dir_build)/installer.o: CFLAGS += -DTITLE="\"$(name) $(revision)\""
$(dir_build)/%.o: $(dir_source)/%.c
diff --git a/source/cache.h b/source/cache.h
new file mode 100644
index 0000000..6a064d5
--- /dev/null
+++ b/source/cache.h
@@ -0,0 +1,29 @@
+/*
+* 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.
+*/
+
+#pragma once
+
+#include "types.h"
+
+void flushEntireDCache(void); //actually: "clean and flush"
+void flushDCacheRange(void *startAddress, u32 size);
+void flushEntireICache(void);
\ No newline at end of file
diff --git a/source/cache.s b/source/cache.s
new file mode 100644
index 0000000..d1857ac
--- /dev/null
+++ b/source/cache.s
@@ -0,0 +1,74 @@
+@ 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.
+
+.text
+.arm
+.align 4
+
+.global flushEntireDCache
+.type flushEntireDCache, %function
+flushEntireDCache:
+ @ Adapted from http://infocenter.arm.com/help/index.jsp?topic=/com.arm.doc.ddi0155a/ch03s03s05.html,
+ @ and https://github.com/gemarcano/libctr9_io/blob/master/src/ctr_system_ARM.c#L39 as well
+ @ Note: ARM's example is actually for a 8KB DCache (which is what the 3DS has)
+
+ @ Implemented in bootROM at address 0xffff0830
+ mov r1, #0 @ segment counter
+ outer_loop:
+ mov r0, #0 @ line counter
+
+ inner_loop:
+ orr r2, r1, r0 @ generate segment and line address
+ mcr p15, 0, r2, c7, c14, 2 @ clean and flush the line
+ add r0, #0x20 @ increment to next line
+ cmp r0, #0x400
+ bne inner_loop
+
+ add r1, #0x40000000
+ cmp r1, #0
+ bne outer_loop
+
+ mcr p15, 0, r1, c7, c10, 4 @ drain write buffer
+ bx lr
+
+.global flushDCacheRange
+.type flushDCacheRange, %function
+flushDCacheRange:
+ @ Implemented in bootROM at address 0xffff08a0
+ add r1, r0, r1 @ end address
+ bic r0, #0x1f @ align source address to cache line size (32 bytes)
+
+ flush_dcache_range_loop:
+ mcr p15, 0, r0, c7, c14, 1 @ clean and flush the line corresponding to the address r0 is holding
+ add r0, #0x20
+ cmp r0, r1
+ blo flush_dcache_range_loop
+
+ mov r0, #0
+ mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
+ bx lr
+
+.global flushEntireICache
+.type flushEntireICache, %function
+flushEntireICache:
+ @ Implemented in bootROM at address 0xffff0ab4
+ mov r0, #0
+ mcr p15, 0, r0, c7, c5, 0
+ bx lr
diff --git a/source/crypto.c b/source/crypto.c
index b42730f..434eec5 100755
--- a/source/crypto.c
+++ b/source/crypto.c
@@ -9,301 +9,297 @@
#include "fatfs/sdmmc/sdmmc.h"
/****************************************************************
-* Crypto Libs
+* Crypto libs
****************************************************************/
/* original version by megazig */
#ifndef __thumb__
#define BSWAP32(x) {\
- __asm__\
- (\
- "eor r1, %1, %1, ror #16\n\t"\
- "bic r1, r1, #0xFF0000\n\t"\
- "mov %0, %1, ror #8\n\t"\
- "eor %0, %0, r1, lsr #8\n\t"\
- :"=r"(x)\
- :"0"(x)\
- :"r1"\
- );\
+ __asm__\
+ (\
+ "eor r1, %1, %1, ror #16\n\t"\
+ "bic r1, r1, #0xFF0000\n\t"\
+ "mov %0, %1, ror #8\n\t"\
+ "eor %0, %0, r1, lsr #8\n\t"\
+ :"=r"(x)\
+ :"0"(x)\
+ :"r1"\
+ );\
};
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\
- (\
- "adds %0, %4\n\t"\
- "addcss %1, %1, #1\n\t"\
- "addcss %2, %2, #1\n\t"\
- "addcs %3, %3, #1\n\t"\
- : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
- : "r"(u32_0)\
- : "cc"\
- );\
+ (\
+ "adds %0, %4\n\t"\
+ "addcss %1, %1, #1\n\t"\
+ "addcss %2, %2, #1\n\t"\
+ "addcs %3, %3, #1\n\t"\
+ : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
+ : "r"(u32_0)\
+ : "cc"\
+ );\
}
#else
#define BSWAP32(x) {x = __builtin_bswap32(x);}
#define ADD_u128_u32(u128_0, u128_1, u128_2, u128_3, u32_0) {\
__asm__\
- (\
- "mov r4, #0\n\t"\
- "add %0, %0, %4\n\t"\
- "adc %1, %1, r4\n\t"\
- "adc %2, %2, r4\n\t"\
- "adc %3, %3, r4\n\t"\
- : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
- : "r"(u32_0)\
- : "cc", "r4"\
- );\
+ (\
+ "mov r4, #0\n\t"\
+ "add %0, %0, %4\n\t"\
+ "adc %1, %1, r4\n\t"\
+ "adc %2, %2, r4\n\t"\
+ "adc %3, %3, r4\n\t"\
+ : "+r"(u128_0), "+r"(u128_1), "+r"(u128_2), "+r"(u128_3)\
+ : "r"(u32_0)\
+ : "cc", "r4"\
+ );\
}
#endif /*__thumb__*/
static void aes_setkey(u8 keyslot, const void *key, u32 keyType, u32 mode)
{
- if(keyslot <= 0x03) return; // Ignore TWL keys for now
- u32 *key32 = (u32 *)key;
- *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
- *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
+ if(keyslot <= 0x03) return; // Ignore TWL keys for now
+ u32 *key32 = (u32 *)key;
+ *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
+ *REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | AES_KEYCNT_WRITE;
- REG_AESKEYFIFO[keyType] = key32[0];
- REG_AESKEYFIFO[keyType] = key32[1];
- REG_AESKEYFIFO[keyType] = key32[2];
- REG_AESKEYFIFO[keyType] = key32[3];
+ REG_AESKEYFIFO[keyType] = key32[0];
+ REG_AESKEYFIFO[keyType] = key32[1];
+ REG_AESKEYFIFO[keyType] = key32[2];
+ REG_AESKEYFIFO[keyType] = key32[3];
}
static void aes_use_keyslot(u8 keyslot)
{
- if(keyslot > 0x3F)
- return;
+ if(keyslot > 0x3F)
+ return;
- *REG_AESKEYSEL = keyslot;
- *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
+ *REG_AESKEYSEL = keyslot;
+ *REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
}
static void aes_setiv(const void *iv, u32 mode)
{
- const u32 *iv32 = (const u32 *)iv;
- *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
+ const u32 *iv32 = (const u32 *)iv;
+ *REG_AESCNT = (*REG_AESCNT & ~(AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER)) | mode;
- // Word order for IV can't be changed in REG_AESCNT and always default to reversed
- if(mode & AES_INPUT_NORMAL)
- {
- REG_AESCTR[0] = iv32[3];
- REG_AESCTR[1] = iv32[2];
- REG_AESCTR[2] = iv32[1];
- REG_AESCTR[3] = iv32[0];
- }
- else
- {
- REG_AESCTR[0] = iv32[0];
- REG_AESCTR[1] = iv32[1];
- REG_AESCTR[2] = iv32[2];
- REG_AESCTR[3] = iv32[3];
- }
+ // Word order for IV can't be changed in REG_AESCNT and always default to reversed
+ if(mode & AES_INPUT_NORMAL)
+ {
+ REG_AESCTR[0] = iv32[3];
+ REG_AESCTR[1] = iv32[2];
+ REG_AESCTR[2] = iv32[1];
+ REG_AESCTR[3] = iv32[0];
+ }
+ else
+ {
+ REG_AESCTR[0] = iv32[0];
+ REG_AESCTR[1] = iv32[1];
+ REG_AESCTR[2] = iv32[2];
+ REG_AESCTR[3] = iv32[3];
+ }
}
static void aes_advctr(void *ctr, u32 val, u32 mode)
{
- u32 *ctr32 = (u32 *)ctr;
-
- int i;
- if(mode & AES_INPUT_BE)
- {
- for(i = 0; i < 4; ++i) // Endian swap
- BSWAP32(ctr32[i]);
- }
-
- if(mode & AES_INPUT_NORMAL)
- {
- ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
- }
- else
- {
- ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
- }
-
- if(mode & AES_INPUT_BE)
- {
- for(i = 0; i < 4; ++i) // Endian swap
- BSWAP32(ctr32[i]);
- }
+ u32 *ctr32 = (u32 *)ctr;
+
+ int i;
+ if(mode & AES_INPUT_BE)
+ {
+ for(i = 0; i < 4; ++i) // Endian swap
+ BSWAP32(ctr32[i]);
+ }
+
+ if(mode & AES_INPUT_NORMAL)
+ {
+ ADD_u128_u32(ctr32[3], ctr32[2], ctr32[1], ctr32[0], val);
+ }
+ else
+ {
+ ADD_u128_u32(ctr32[0], ctr32[1], ctr32[2], ctr32[3], val);
+ }
+
+ if(mode & AES_INPUT_BE)
+ {
+ for(i = 0; i < 4; ++i) // Endian swap
+ BSWAP32(ctr32[i]);
+ }
}
static void aes_change_ctrmode(void *ctr, u32 fromMode, u32 toMode)
{
- u32 *ctr32 = (u32 *)ctr;
- int i;
- if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
- {
- for(i = 0; i < 4; ++i)
- BSWAP32(ctr32[i]);
- }
+ u32 *ctr32 = (u32 *)ctr;
+ int i;
+ if((fromMode ^ toMode) & AES_CNT_INPUT_ENDIAN)
+ {
+ for(i = 0; i < 4; ++i)
+ BSWAP32(ctr32[i]);
+ }
- if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
- {
- u32 temp = ctr32[0];
- ctr32[0] = ctr32[3];
- ctr32[3] = temp;
+ if((fromMode ^ toMode) & AES_CNT_INPUT_ORDER)
+ {
+ u32 temp = ctr32[0];
+ ctr32[0] = ctr32[3];
+ ctr32[3] = temp;
- temp = ctr32[1];
- ctr32[1] = ctr32[2];
- ctr32[2] = temp;
- }
+ temp = ctr32[1];
+ ctr32[1] = ctr32[2];
+ ctr32[2] = temp;
+ }
}
static void aes_batch(void *dst, const void *src, u32 blockCount)
{
- *REG_AESBLKCNT = blockCount << 16;
- *REG_AESCNT |= AES_CNT_START;
-
- const u32 *src32 = (const u32 *)src;
- u32 *dst32 = (u32 *)dst;
-
- u32 wbc = blockCount;
- u32 rbc = blockCount;
-
- while(rbc)
- {
- if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
- {
- *REG_AESWRFIFO = *src32++;
- *REG_AESWRFIFO = *src32++;
- *REG_AESWRFIFO = *src32++;
- *REG_AESWRFIFO = *src32++;
- wbc--;
- }
-
- if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
- {
- *dst32++ = *REG_AESRDFIFO;
- *dst32++ = *REG_AESRDFIFO;
- *dst32++ = *REG_AESRDFIFO;
- *dst32++ = *REG_AESRDFIFO;
- rbc--;
- }
- }
+ *REG_AESBLKCNT = blockCount << 16;
+ *REG_AESCNT |= AES_CNT_START;
+
+ const u32 *src32 = (const u32 *)src;
+ u32 *dst32 = (u32 *)dst;
+
+ u32 wbc = blockCount;
+ u32 rbc = blockCount;
+
+ while(rbc)
+ {
+ if(wbc && ((*REG_AESCNT & 0x1F) <= 0xC)) // There's space for at least 4 ints
+ {
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ *REG_AESWRFIFO = *src32++;
+ wbc--;
+ }
+
+ if(rbc && ((*REG_AESCNT & (0x1F << 0x5)) >= (0x4 << 0x5))) // At least 4 ints available for read
+ {
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ *dst32++ = *REG_AESRDFIFO;
+ rbc--;
+ }
+ }
}
static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode, u32 ivMode)
{
- *REG_AESCNT = mode |
- AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
- AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
- AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
+ *REG_AESCNT = mode |
+ AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER |
+ AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN |
+ AES_CNT_FLUSH_READ | AES_CNT_FLUSH_WRITE;
- u32 blocks;
- while(blockCount != 0)
- {
- if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
- && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
- aes_setiv(iv, ivMode);
+ u32 blocks;
+ while(blockCount != 0)
+ {
+ if((mode & AES_ALL_MODES) != AES_ECB_ENCRYPT_MODE
+ && (mode & AES_ALL_MODES) != AES_ECB_DECRYPT_MODE)
+ aes_setiv(iv, ivMode);
- blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
+ blocks = (blockCount >= 0xFFFF) ? 0xFFFF : blockCount;
- // Save the last block for the next decryption CBC batch's iv
- if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
- {
- memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
- aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
- }
+ // Save the last block for the next decryption CBC batch's iv
+ if((mode & AES_ALL_MODES) == AES_CBC_DECRYPT_MODE)
+ {
+ memcpy(iv, src + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
+ }
- // Process the current batch
- aes_batch(dst, src, blocks);
+ // Process the current batch
+ aes_batch(dst, src, blocks);
- // Save the last block for the next encryption CBC batch's iv
- if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
- {
- memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
- aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
- }
-
- // Advance counter for CTR mode
- else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
- aes_advctr(iv, blocks, ivMode);
+ // Save the last block for the next encryption CBC batch's iv
+ if((mode & AES_ALL_MODES) == AES_CBC_ENCRYPT_MODE)
+ {
+ memcpy(iv, dst + (blocks - 1) * AES_BLOCK_SIZE, AES_BLOCK_SIZE);
+ aes_change_ctrmode(iv, AES_INPUT_BE | AES_INPUT_NORMAL, ivMode);
+ }
- src += blocks * AES_BLOCK_SIZE;
- dst += blocks * AES_BLOCK_SIZE;
- blockCount -= blocks;
- }
+ // Advance counter for CTR mode
+ else if((mode & AES_ALL_MODES) == AES_CTR_MODE)
+ aes_advctr(iv, blocks, ivMode);
+
+ src += blocks * AES_BLOCK_SIZE;
+ dst += blocks * AES_BLOCK_SIZE;
+ blockCount -= blocks;
+ }
}
-void sha_wait_idle()
+static void sha_wait_idle()
{
- while(*REG_SHA_CNT & 1);
+ while(*REG_SHA_CNT & 1);
}
-void sha(void *res, const void *src, u32 size, u32 mode)
+static void sha(void *res, const void *src, u32 size, u32 mode)
{
- sha_wait_idle();
- *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
-
- const u32 *src32 = (const u32 *)src;
- int i;
- while(size >= 0x40)
- {
- sha_wait_idle();
- for(i = 0; i < 4; ++i)
- {
- *REG_SHA_INFIFO = *src32++;
- *REG_SHA_INFIFO = *src32++;
- *REG_SHA_INFIFO = *src32++;
- *REG_SHA_INFIFO = *src32++;
- }
+ sha_wait_idle();
+ *REG_SHA_CNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
- size -= 0x40;
- }
-
- sha_wait_idle();
- memcpy((void *)REG_SHA_INFIFO, src32, size);
-
- *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
-
- while(*REG_SHA_CNT & SHA_FINAL_ROUND);
- sha_wait_idle();
-
- u32 hashSize = SHA_256_HASH_SIZE;
- if(mode == SHA_224_MODE)
- hashSize = SHA_224_HASH_SIZE;
- else if(mode == SHA_1_MODE)
- hashSize = SHA_1_HASH_SIZE;
+ const u32 *src32 = (const u32 *)src;
+ int i;
+ while(size >= 0x40)
+ {
+ sha_wait_idle();
+ for(i = 0; i < 4; ++i)
+ {
+ *REG_SHA_INFIFO = *src32++;
+ *REG_SHA_INFIFO = *src32++;
+ *REG_SHA_INFIFO = *src32++;
+ *REG_SHA_INFIFO = *src32++;
+ }
- memcpy(res, (void *)REG_SHA_HASH, hashSize);
+ size -= 0x40;
+ }
+
+ sha_wait_idle();
+ memcpy((void *)REG_SHA_INFIFO, src32, size);
+
+ *REG_SHA_CNT = (*REG_SHA_CNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
+
+ while(*REG_SHA_CNT & SHA_FINAL_ROUND);
+ sha_wait_idle();
+
+ u32 hashSize = SHA_256_HASH_SIZE;
+ if(mode == SHA_224_MODE)
+ hashSize = SHA_224_HASH_SIZE;
+ else if(mode == SHA_1_MODE)
+ hashSize = SHA_1_HASH_SIZE;
+
+ memcpy(res, (void *)REG_SHA_HASH, hashSize);
}
-/****************************************************************
-* Nand/FIRM Crypto stuff
-****************************************************************/
-
-static u8 nandSlot, nandCTR[0x10];
+/*****************************************************************/
+static u8 __attribute__((aligned(4))) nandCtr[AES_BLOCK_SIZE];
+static u8 nandSlot;
static u32 fatStart;
-
-const u8 key2s[3][0x10] = {
+const u8 __attribute__((aligned(4))) key2s[3][AES_BLOCK_SIZE] = {
{0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0},
{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3B, 0xF5, 0xF6},
{0x65, 0x29, 0x3E, 0x12, 0x56, 0x0C, 0x0B, 0xD1, 0xDD, 0xB5, 0x63, 0x1C, 0xB6, 0xD9, 0x52, 0x75}
};
-//Get Nand CTR key
void getNandCTR(void)
{
- u8 cid[0x10];
- u8 shaSum[0x20];
+ u8 __attribute__((aligned(4))) cid[AES_BLOCK_SIZE];
+ u8 __attribute__((aligned(4))) shaSum[SHA_256_HASH_SIZE];
sdmmc_get_cid(1, (u32 *)cid);
- sha(shaSum, cid, 0x10, SHA_256_MODE);
- memcpy(nandCTR, shaSum, 0x10);
+ sha(shaSum, cid, sizeof(cid), SHA_256_MODE);
+ memcpy(nandCtr, shaSum, sizeof(nandCtr));
}
-//Initialize the CTRNAND crypto
void ctrNandInit(void)
{
getNandCTR();
- if(console)
+ 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[AES_BLOCK_SIZE] = {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;
}
@@ -314,86 +310,81 @@ void ctrNandInit(void)
}
}
-//Read and decrypt from CTRNAND
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
{
- u8 tmpCTR[0x10];
- memcpy(tmpCTR, nandCTR, 0x10);
- aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ u8 __attribute__((aligned(4))) tmpCtr[sizeof(nandCtr)];
+ memcpy(tmpCtr, nandCtr, sizeof(nandCtr));
+ aes_advctr(tmpCtr, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Read
u32 result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
//Decrypt
aes_use_keyslot(nandSlot);
- aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(outbuf, outbuf, sectorCount * 0x200 / AES_BLOCK_SIZE, tmpCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
return result;
}
-//Read and decrypt from the FIRM0 partition on NAND
void readFirm0(u8 *outbuf, u32 size)
{
- u8 CTRtmp[0x10];
- memcpy(CTRtmp, nandCTR, 0x10);
+ u8 __attribute__((aligned(4))) ctrTmp[sizeof(nandCtr)];
+ memcpy(ctrTmp, nandCtr, sizeof(nandCtr));
//Read FIRM0 data
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf);
//Decrypt
- aes_advctr(CTRtmp, 0x0B130000 / 0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes_advctr(ctrTmp, 0x0B130000 / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x06);
- aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTRtmp, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(outbuf, outbuf, size / AES_BLOCK_SIZE, ctrTmp, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
-//Encrypt and write a FIRM partition to NAND
-void writeFirm(u8 *inbuf, u32 firm, u32 size)
+void writeFirm(u8 *inbuf, bool isFirm1, u32 size)
{
- u32 offset = firm ? 0x0B530000 : 0x0B130000;
- u8 CTRtmp[0x10];
- memcpy(CTRtmp, nandCTR, 0x10);
+ u32 offset = isFirm1 ? 0x0B530000 : 0x0B130000;
+ u8 __attribute__((aligned(4))) ctrTmp[sizeof(nandCtr)];
+ memcpy(ctrTmp, nandCtr, sizeof(nandCtr));
//Encrypt FIRM data
- aes_advctr(CTRtmp, offset / 0x10, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes_advctr(ctrTmp, offset / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x06);
- aes(inbuf, inbuf, size / AES_BLOCK_SIZE, CTRtmp, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(inbuf, inbuf, size / AES_BLOCK_SIZE, ctrTmp, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
//Write to NAND
sdmmc_nand_writesectors(offset / 0x200, size / 0x200, inbuf);
}
-//Setup keyslot 0x11 for key sector de/encryption
-void setupKeyslot0x11(u32 a9lhBoot, const void *otp)
+void setupKeyslot0x11(bool isA9lh, const void *otp)
{
- u8 shasum[0x20];
- u8 keyX[0x10];
- u8 keyY[0x10];
+ u8 __attribute__((aligned(4))) shasum[SHA_256_HASH_SIZE];
+ u8 __attribute__((aligned(4))) keyX[AES_BLOCK_SIZE];
+ u8 __attribute__((aligned(4))) keyY[AES_BLOCK_SIZE];
//If booting via A9LH, use the leftover contents of the SHA register
- if(a9lhBoot) memcpy((void *)shasum, (void *)REG_SHA_HASH, 0x20);
+ if(isA9lh) memcpy(shasum, (void *)REG_SHA_HASH, sizeof(shasum));
+
//Else calculate the otp.bin hash
else sha(shasum, otp, 0x90, SHA_256_MODE);
//Set keyX and keyY
- memcpy(keyX, shasum, 0x10);
- memcpy(keyY, shasum + 0x10, 0x10);
+ memcpy(keyX, shasum, sizeof(keyX));
+ memcpy(keyY, shasum + sizeof(keyX), sizeof(keyY));
aes_setkey(0x11, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setkey(0x11, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
}
-//Generate and encrypt an A9LH key sector
void generateSector(u8 *keySector, u32 mode)
{
//Inject key2
- memcpy(keySector + 0x10, mode ? key2s[0] : key2s[2], 0x10);
+ memcpy(keySector + AES_BLOCK_SIZE, mode ? key2s[0] : key2s[2], AES_BLOCK_SIZE);
//Encrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
- aes(keySector + (0x10 * i), keySector + (0x10 * i), 1, NULL, AES_ECB_ENCRYPT_MODE, 0);
+ aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_ENCRYPT_MODE, 0);
}
-//Read and decrypt the NAND key sector
void getSector(u8 *keySector)
{
//Read keysector from NAND
@@ -402,33 +393,30 @@ void getSector(u8 *keySector)
//Decrypt key sector
aes_use_keyslot(0x11);
for(u32 i = 0; i < 32; i++)
- aes(keySector + (0x10 * i), keySector + (0x10 * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
+ aes(keySector + (AES_BLOCK_SIZE * i), keySector + (AES_BLOCK_SIZE * i), 1, NULL, AES_ECB_DECRYPT_MODE, 0);
}
-//Check SHA256 hash
u32 verifyHash(const void *data, u32 size, const u8 *hash)
{
- u8 shasum[0x20];
+ u8 __attribute__((aligned(4))) shasum[SHA_256_HASH_SIZE];
sha(shasum, data, size, SHA_256_MODE);
- return memcmp(shasum, hash, 0x20) == 0;
+ return memcmp(shasum, hash, sizeof(shasum)) == 0;
}
-//Decrypt a FIRM ExeFS
u32 decryptExeFs(u8 *inbuf)
{
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
- u8 ncchCTR[0x10] = {0};
+ u8 __attribute__((aligned(4))) ncchCtr[AES_BLOCK_SIZE] = {0};
for(u32 i = 0; i < 8; i++)
- ncchCTR[7 - i] = *(inbuf + 0x108 + i);
- ncchCTR[8] = 2;
+ ncchCtr[7 - i] = *(inbuf + 0x108 + i);
+ ncchCtr[8] = 2;
aes_setkey(0x2C, inbuf, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
- aes_setiv(ncchCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x2C);
- aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
+ aes(inbuf - 0x200, exeFsOffset, exeFsSize / AES_BLOCK_SIZE, ncchCtr, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
return exeFsSize - 0x200;
}
\ No newline at end of file
diff --git a/source/crypto.h b/source/crypto.h
index 8602734..c0a8b9b 100755
--- a/source/crypto.h
+++ b/source/crypto.h
@@ -79,16 +79,15 @@
#define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8)
-//NAND/FIRM stuff
-extern u32 console;
+extern bool isN3DS;
const u8 key2s[3][0x10];
void getNandCTR(void);
void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void readFirm0(u8 *outbuf, u32 size);
-void writeFirm(u8 *inbuf, u32 offset, u32 size);
-void setupKeyslot0x11(u32 a9lhBoot, const void *otp);
+void writeFirm(u8 *inbuf, bool isFirm1, u32 size);
+void setupKeyslot0x11(bool isA9lh, const void *otp);
void generateSector(u8 *keySector, u32 mode);
void getSector(u8 *keySector);
u32 verifyHash(const void *data, u32 size, const u8 *hash);
diff --git a/source/draw.c b/source/draw.c
index 8092c46..1ab2027 100644
--- a/source/draw.c
+++ b/source/draw.c
@@ -1,47 +1,47 @@
/*
-* draw.c
+* 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.
+*/
+
+/*
* Code to print to the screen by mid-kid @CakesFW
+* https://github.com/mid-kid/CakesForeveryWan
*/
#include "draw.h"
-#include "memory.h"
+#include "screen.h"
+#include "strings.h"
#include "font.h"
-static const struct fb {
- u8 *top_left;
- u8 *top_right;
- u8 *bottom;
-} *const fb = (struct fb *)0x23FFFE00;
-
-static inline int strlen(const char *string)
+static void drawCharacter(char character, u32 posX, u32 posY, u32 color)
{
- char *stringEnd = (char *)string;
+ u8 *select = fb->top_left;
- while(*stringEnd) stringEnd++;
-
- return stringEnd - string;
-}
-
-void clearScreens(void)
-{
- memset32(fb->top_left, 0, 0x46500);
- memset32(fb->top_right, 0, 0x46500);
- memset32(fb->bottom, 0, 0x38400);
-}
-
-void drawCharacter(char character, int posX, int posY, u32 color)
-{
- u8 *const select = fb->top_left;
-
- for(int y = 0; y < 8; y++)
+ for(u32 y = 0; y < 8; y++)
{
char charPos = font[character * 8 + y];
- for(int x = 7; x >= 0; x--)
- if ((charPos >> x) & 1)
+ for(u32 x = 0; x < 8; x++)
+ if(((charPos >> (7 - x)) & 1) == 1)
{
- int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
+ u32 screenPos = (posX * SCREEN_HEIGHT * 3 + (SCREEN_HEIGHT - y - posY - 1) * 3) + x * 3 * SCREEN_HEIGHT;
select[screenPos] = color >> 16;
select[screenPos + 1] = color >> 8;
@@ -50,26 +50,34 @@ void drawCharacter(char character, int posX, int posY, u32 color)
}
}
-int drawString(const char *string, int posX, int posY, u32 color)
+u32 drawString(const char *string, u32 posX, u32 posY, u32 color)
{
- for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
- {
- if(string[i] == '\n')
+ for(u32 i = 0, line_i = 0; i < strlen(string); i++)
+ switch(string[i])
{
- posY += SPACING_Y;
- line_i = 0;
- i++;
- }
- else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
- {
- // Make sure we never get out of the screen.
- posY += SPACING_Y;
- line_i = 2; //Little offset so we know the same string continues.
- if(string[i] == ' ') i++; //Spaces at the start look weird
- }
+ case '\n':
+ posY += SPACING_Y;
+ line_i = 0;
+ break;
- drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
- }
+ case '\t':
+ line_i += 2;
+ break;
+
+ default:
+ //Make sure we never get out of the screen
+ if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
+ {
+ posY += SPACING_Y;
+ line_i = 1; //Little offset so we know the same string continues
+ if(string[i] == ' ') break; //Spaces at the start look weird
+ }
+
+ drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);
+
+ line_i++;
+ break;
+ }
return posY + SPACING_Y;
}
\ No newline at end of file
diff --git a/source/draw.h b/source/draw.h
index 892e422..b235600 100644
--- a/source/draw.h
+++ b/source/draw.h
@@ -1,19 +1,35 @@
/*
-* draw.h
+* 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.
+*/
+
+/*
* Code to print to the screen by mid-kid @CakesFW
+* https://github.com/mid-kid/CakesForeveryWan
*/
#pragma once
#include "types.h"
-#define SCREEN_TOP_WIDTH 400
-#define SCREEN_TOP_HEIGHT 240
-
#define SPACING_Y 10
#define SPACING_X 8
-void clearScreens(void);
-void drawCharacter(char character, int pos_x, int pos_y, u32 color);
-int drawString(const char *string, int pos_x, int pos_y, u32 color);
\ No newline at end of file
+u32 drawString(const char *string, u32 posX, u32 posY, u32 color);
\ No newline at end of file
diff --git a/source/fatfs/00history.txt b/source/fatfs/00history.txt
old mode 100644
new mode 100755
index 4d76198..49aac28
--- 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,34 @@ 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. (appeared at R0.12)
+ Fixed wrong memory read in create_name(). (appeared at R0.12)
+ Fixed compilation fails at some configurations, _USE_FASTSEEK and _USE_FORWARD.
+
+
+
+R0.12b (September 04, 2016)
+
+ Improved f_rename() to be able to rename objects with the same name but case.
+ Fixed an error in the case conversion teble of code page 866. (ff.c)
+ Fixed writing data is truncated at the file offset 4GiB on the exFAT volume. (appeared at R0.12)
+ Fixed creating a file in the root directory of exFAT volume can fail. (appeared at R0.12)
+ Fixed f_mkfs() creating exFAT volume with too small cluster size can collapse unallocated memory. (appeared at R0.12)
+ Fixed wrong object name can be returned when read directory at Unicode cfg. (appeared at R0.12)
+ Fixed large file allocation/removing on the exFAT volume collapses allocation bitmap. (appeared at R0.12)
+ Fixed some internal errors in f_expand() and f_lseek(). (appeared at R0.12)
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/diskio.c b/source/fatfs/diskio.c
index 0bae01c..e6f366e 100644
--- a/source/fatfs/diskio.c
+++ b/source/fatfs/diskio.c
@@ -33,6 +33,7 @@ DSTATUS disk_status (
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
+
DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
diff --git a/source/fatfs/ff.c b/source/fatfs/ff.c
old mode 100644
new mode 100755
index 9656965..901697b
--- 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.12b /
/-----------------------------------------------------------------------------/
-/ 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 != 68020 /* 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) */
@@ -377,7 +396,7 @@ typedef struct {
#define BPB_NumFATs 16 /* Number of FATs (BYTE) */
#define BPB_RootEntCnt 17 /* Size of root directory area for FAT12/16 [entry] (WORD) */
#define BPB_TotSec16 19 /* Volume size (16-bit) [sector] (WORD) */
-#define BPB_Media 21 /* Media descriptor (BYTE) */
+#define BPB_Media 21 /* Media descriptor byte (BYTE) */
#define BPB_FATSz16 22 /* FAT size (16-bit) [sector] (WORD) */
#define BPB_SecPerTrk 24 /* Track size for int13h [sector] (WORD) */
#define BPB_NumHeads 26 /* Number of heads for int13h (WORD) */
@@ -389,9 +408,11 @@ 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 BS_55AA 510 /* Signature word (WORD) */
+#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 +423,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 +442,41 @@ 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 +485,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 +534,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 +547,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 +719,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 +742,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 +855,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 +920,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 +955,8 @@ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
return res;
}
-#endif
+#endif
@@ -993,17 +1006,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 +1036,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 +1053,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 +1076,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 +1089,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 +1100,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 +1123,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 */
@@ -1125,8 +1140,8 @@ DWORD find_bitmap ( /* 0:No free cluster, 2..:Free cluster found, 0xFFFFFFFF:Dis
if (clst >= fs->n_fatent - 2) clst = 0;
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);
+ if (move_window(fs, fs->database + val / 8 / SS(fs)) != FR_OK) return 0xFFFFFFFF; /* (assuming bitmap is located top of the cluster heap) */
+ i = val / 8 % SS(fs); bm = 1 << (val % 8);
do {
do {
bv = fs->win[i] & bm; bm <<= 1; /* Get bit value */
@@ -1145,9 +1160,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 */
@@ -1162,8 +1179,8 @@ 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 */
+ sect = fs->database + clst / 8 / SS(fs); /* Sector address (assuming bitmap is located top of the cluster heap) */
+ 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 +1193,7 @@ FRESULT change_bitmap (
} while (bm <<= 1); /* Next bit */
bm = 1;
} while (++i < SS(fs)); /* Next byte */
+ i = 0;
}
}
@@ -1183,6 +1201,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 +1210,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 +1220,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 +1263,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 +1301,6 @@ FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
#endif
return FR_OK;
}
-#endif
@@ -1290,7 +1308,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 */
@@ -1303,7 +1320,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err
if (clst == 0) { /* Create a new chain */
- scl = fs->last_clst; /* Get suggested cluster to start at */
+ scl = fs->last_clst; /* Get suggested cluster to start from */
if (scl == 0 || scl >= fs->n_fatent) scl = 1;
}
else { /* Stretch current chain */
@@ -1315,7 +1332,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err
}
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
ncl = find_bitmap(fs, scl, 1); /* Find a free cluster */
if (ncl == 0 || ncl == 0xFFFFFFFF) return ncl; /* No free cluster or hard error? */
res = change_bitmap(fs, ncl, 1, 1); /* Mark the cluster 'in use' */
@@ -1331,7 +1348,7 @@ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk err
}
} else
#endif
- { /* At the FAT12/16/32 */
+ { /* On the FAT12/16/32 volume */
ncl = scl; /* Start cluster */
for (;;) {
ncl++; /* Next cluster */
@@ -1365,16 +1382,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 +1413,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 +1529,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 +1537,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 +1560,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 +1575,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 +1619,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 +1662,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 +1699,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 +1732,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 */
@@ -1752,7 +1774,7 @@ void gen_numname (
/* itoa (hexdecimal) */
i = 7;
do {
- c = (seq % 16) + '0';
+ c = (BYTE)((seq % 16) + '0');
if (c > '9') c += 7;
ns[i--] = c;
seq /= 16;
@@ -1770,14 +1792,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 +1812,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 +1862,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 +1926,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 +1947,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 +2018,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 +2039,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 +2053,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 +2074,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 */
@@ -2057,12 +2104,12 @@ FRESULT dir_read (
c = dp->dir[DIR_Name]; /* Test for the entry type */
if (c == 0) { res = FR_NO_FILE; break; } /* Reached to end of the directory */
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
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 */
@@ -2072,7 +2119,7 @@ FRESULT dir_read (
}
} else
#endif
- { /* At the FAT12/16/32 */
+ { /* On the FAT12/16/32 volume */
dp->obj.attr = a = dp->dir[DIR_Attr] & AM_MASK; /* Get attribute */
#if _USE_LFN != 0 /* LFN configuration */
if (c == DDEM || c == '.' || (int)((a & ~AM_ARC) == AM_VOL) != vol) { /* An entry without valid data */
@@ -2081,11 +2128,11 @@ FRESULT dir_read (
if (a == AM_LFN) { /* An LFN entry is found */
if (c & LLEF) { /* Is it start of an LFN sequence? */
sum = dp->dir[LDIR_Chksum];
- c &= ~LLEF; ord = c;
+ c &= (BYTE)~LLEF; ord = c;
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 +2153,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 */
@@ -2129,23 +2177,23 @@ FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
res = dir_sdi(dp, 0); /* Rewind directory object */
if (res != FR_OK) return res;
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
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;
}
#endif
- /* At the FAT12/16/32 */
+ /* On the FAT12/16/32 volume */
#if _USE_LFN != 0
ord = sum = 0xFF; dp->blk_ofs = 0xFFFFFFFF; /* Reset LFN sequence */
#endif
@@ -2160,14 +2208,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 */
+ c &= (BYTE)~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 +2236,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,16 +2250,14 @@ 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 */
+ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
DIR dj;
nent = (nlen + 14) / 15 + 2; /* Number of entries to allocate (85+C0+C1s) */
@@ -2218,7 +2265,7 @@ FRESULT dir_register ( /* FR_OK:succeeded, FR_DENIED:no free entry or too many S
if (res != FR_OK) return res;
dp->blk_ofs = dp->dptr - SZDIRE * (nent - 1); /* Set block position */
- if (dp->obj.stat & 4) { /* Has the sub-directory been stretched? */
+ if (dp->obj.sclust != 0 && (dp->obj.stat & 4)) { /* Has the sub-directory been stretched? */
dp->obj.stat &= 3;
dp->obj.objsize += (DWORD)fs->csize * SS(fs); /* Increase object size by cluster size */
res = fill_fat_chain(&dp->obj); /* Complement FAT chain if needed */
@@ -2232,22 +2279,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);
+ /* On the FAT12/16/32 volume */
+ 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 +2307,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 +2334,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,15 +2354,15 @@ 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);
if (res != FR_OK) break;
/* Mark an entry 'deleted' */
- if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ if (_FS_EXFAT && fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
dp->dir[XDIR_Type] &= 0x7F;
- } else { /* At the FAT12/16/32 */
+ } else { /* On the FAT12/16/32 volume */
dp->dir[DIR_Name] = DDEM;
}
fs->wflag = 1;
@@ -2334,15 +2382,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 +2400,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 +2412,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) { /* On the exFAT volume */
+ get_xdir_info(fs->dirbuf, fno);
return;
} else
#endif
- { /* At the FAT12/16/32 */
+ { /* On the FAT12/16/32 volume */
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 */
@@ -2379,7 +2429,7 @@ void get_fileinfo ( /* No return code */
}
#endif
if (i >= _MAX_LFN) { i = 0; break; } /* No LFN if buffer overflow */
- fno->fname[i++] = (char)w;
+ fno->fname[i++] = (TCHAR)w;
}
fno->fname[i] = 0; /* Terminate the LFN */
}
@@ -2431,18 +2481,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 +2544,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 +2557,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 +2579,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 +2602,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? */
@@ -2575,7 +2627,7 @@ FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
if (si) cf |= NS_LOSS | NS_LFN;
while (di && lfn[di - 1] != '.') di--; /* Find extension (di<=si: no extension) */
- b = i = 0; ni = 8;
+ i = b = 0; ni = 8;
for (;;) {
w = lfn[si++]; /* Get an LFN character */
if (!w) break; /* Break on end of the LFN */
@@ -2638,15 +2690,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 +2707,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 +2740,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 +2834,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 +2913,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;
}
@@ -2912,7 +2954,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
UINT i;
- /* Get logical drive number from the path name */
+ /* Get logical drive number */
*rfs = 0;
vol = get_ldnumber(path);
if (vol < 0) return FR_INVALID_DRIVE;
@@ -2924,7 +2966,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
ENTER_FF(fs); /* Lock the volume */
*rfs = fs; /* Return pointer to the file system object */
- mode &= ~FA_READ; /* Desired access mode, write access or not */
+ mode &= (BYTE)~FA_READ; /* Desired access mode, write access or not */
if (fs->fs_type) { /* If the volume has been mounted */
stat = disk_status(fs->drv);
if (!(stat & STA_NOINIT)) { /* and the physical drive is kept initialized */
@@ -2948,16 +2990,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 +3017,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,26 +3025,26 @@ 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;
fs->database = bsect + ld_dword(fs->win + BPB_DataOfsEx);
fs->fatbase = bsect + ld_dword(fs->win + BPB_FatOfsEx);
- if (maxlba < fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
+ if (maxlba < (QWORD)fs->database + nclst * fs->csize) return FR_NO_FILESYSTEM; /* (Volume size must not be smaller than the size requiered) */
fs->dirbase = ld_dword(fs->win + BPB_RootClusEx);
/* Check if bitmap location is in assumption (at the first cluster) */
@@ -3013,13 +3055,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 +3087,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 +3110,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 +3131,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
@@ -3118,15 +3161,14 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
static
FRESULT validate ( /* Returns FR_OK or FR_INVALID_OBJECT */
- void* dfp, /* Pointer to the FIL/DIR object to check validity */
+ _FDID* obj, /* Pointer to the _OBJ, the 1st member in the FIL/DIR object, to check validity */
FATFS** fs /* Pointer to pointer to the owner file system object to return */
)
{
- _FDID *obj = (_FDID*)dfp; /* Assuming .obj in the FIL/DIR is the first member */
FRESULT res;
- if (!dfp || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) {
+ if (!obj || !obj->fs || !obj->fs->fs_type || obj->fs->id != obj->id || (disk_status(obj->fs->drv) & STA_NOINIT)) {
*fs = 0; /* The object is invalid */
res = FR_INVALID_OBJECT;
} else {
@@ -3164,6 +3206,7 @@ FRESULT f_mount (
const TCHAR *rp = path;
+ /* Get logical drive number */
vol = get_ldnumber(&rp);
if (vol < 0) return FR_INVALID_DRIVE;
cfs = FatFs[vol]; /* Pointer to fs object */
@@ -3209,20 +3252,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;
+ /* Get logical drive */
+ 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 +3325,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 +3356,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 +3392,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);
}
@@ -3388,7 +3459,7 @@ FRESULT f_read (
*br = 0; /* Clear read byte counter */
- res = validate(fp, &fs);
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
remain = fp->obj.objsize - fp->fptr;
@@ -3396,7 +3467,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? */
@@ -3423,16 +3494,14 @@ FRESULT f_read (
if (csect + cc > fs->csize) { /* Clip at cluster boundary */
cc = fs->csize - csect;
}
- if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
+ if (disk_read(fs->drv, rbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
#if !_FS_READONLY && _FS_MINIMIZE <= 2 /* Replace one of the read sectors with cached data if it contains a dirty sector */
#if _FS_TINY
if (fs->wflag && fs->winsect - sect < cc) {
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,29 +3512,23 @@ 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 &= (BYTE)~FA_DIRTY;
}
#endif
- if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) { /* Fill sector cache */
- ABORT(fs, FR_DISK_ERR);
- }
+ if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */
}
#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
}
@@ -3495,19 +3558,18 @@ FRESULT f_write (
*bw = 0; /* Clear write byte counter */
- res = validate(fp, &fs);
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
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 +3594,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 &= (BYTE)~FA_DIRTY;
}
#endif
sect = clust2sect(fs, fp->clust); /* Get current sector */
@@ -3551,9 +3609,7 @@ FRESULT f_write (
if (csect + cc > fs->csize) { /* Clip at cluster boundary */
cc = fs->csize - csect;
}
- if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
+ if (disk_write(fs->drv, wbuff, sect, cc) != RES_OK) ABORT(fs, FR_DISK_ERR);
#if _FS_MINIMIZE <= 2
#if _FS_TINY
if (fs->winsect - sect < cc) { /* Refill sector cache if it gets invalidated by the direct write */
@@ -3563,7 +3619,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 &= (BYTE)~FA_DIRTY;
}
#endif
#endif
@@ -3571,35 +3627,32 @@ FRESULT f_write (
continue;
}
#if _FS_TINY
- if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling at growing edge */
+ if (fp->fptr >= fp->obj.objsize) { /* Avoid silly cache filling on the growing edge */
if (sync_window(fs) != FR_OK) ABORT(fs, FR_DISK_ERR);
fs->winsect = sect;
}
#else
- if (fp->sect != sect) { /* Fill sector cache with file data */
- if (fp->fptr < fp->obj.objsize &&
- disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) {
- ABORT(fs, FR_DISK_ERR);
- }
+ if (fp->sect != sect && /* Fill sector cache with file data */
+ fp->fptr < fp->obj.objsize &&
+ disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) {
+ ABORT(fs, FR_DISK_ERR);
}
#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 +3672,18 @@ FRESULT f_sync (
FATFS *fs;
DWORD tm;
BYTE *dir;
- DEF_DIRBUF;
+#if _FS_EXFAT
+ DEF_NAMBUF
+#endif
- res = validate(fp, &fs); /* Check validity of the object */
+ res = validate(&fp->obj, &fs); /* Check validity of the file 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 &= (BYTE)~FA_DIRTY;
}
#endif
/* Update the directory entry */
@@ -3641,24 +3694,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 &= (BYTE)~FA_MODIFIED;
}
}
- FREE_DIRBUF();
+ FREE_NAMBUF();
}
} else
#endif
@@ -3669,11 +3722,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 &= (BYTE)~FA_MODIFIED;
}
}
}
@@ -3703,7 +3756,7 @@ FRESULT f_close (
if (res == FR_OK)
#endif
{
- res = validate(fp, &fs); /* Lock volume */
+ res = validate(&fp->obj, &fs); /* Lock volume */
if (res == FR_OK) {
#if _FS_LOCK != 0
res = dec_lock(fp->obj.lockid); /* Decrement file open counter */
@@ -3723,11 +3776,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 */
@@ -3736,10 +3789,11 @@ FRESULT f_chdrive (
int vol;
+ /* Get logical drive number */
vol = get_ldnumber(&path);
if (vol < 0) return FR_INVALID_DRIVE;
- CurrVol = (BYTE)vol;
+ CurrVol = (BYTE)vol; /* Set it as current volume */
return FR_OK;
}
@@ -3753,13 +3807,13 @@ FRESULT f_chdir (
FRESULT res;
DIR dj;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
- /* Get logical drive number */
+ /* Get logical drive */
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,15 +3864,15 @@ FRESULT f_getcwd (
DWORD ccl;
TCHAR *tp;
FILINFO fno;
- DEF_NAMBUF;
+ DEF_NAMBUF
*buff = 0;
- /* Get logical drive number */
+ /* Get logical drive */
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 +3921,7 @@ FRESULT f_getcwd (
LEAVE_FF(fs, res);
}
+
#endif /* _FS_RPATH >= 2 */
#endif /* _FS_RPATH >= 1 */
@@ -3890,14 +3945,14 @@ FRESULT f_lseek (
DWORD cl, pcl, ncl, tcl, dsc, tlen, ulen, *tbl;
#endif
- res = validate(fp, &fs); /* Check validity of the object */
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
#if _USE_FASTSEEK
if (fp->cltbl) { /* Fast seek */
if (ofs == CREATE_LINKMAP) { /* Create CLMT */
tbl = fp->cltbl;
tlen = *tbl++; ulen = 2; /* Given table size and required table size */
- cl = fp->obj.sclust; /* Top of the chain */
+ cl = fp->obj.sclust; /* Origin of the chain */
if (cl) {
do {
/* Get a fragment */
@@ -3926,20 +3981,16 @@ 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(fs, FR_DISK_ERR);
+ fp->flag &= (BYTE)~FA_DIRTY;
}
#endif
- if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) { /* Load current sector */
- ABORT(fs, FR_DISK_ERR);
- }
+ if (disk_read(fs->drv, fp->buf, dsc, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Load current sector */
#endif
fp->sect = dsc;
}
@@ -3950,19 +4001,19 @@ 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)
+#if _FS_EXFAT
+ if (fs->fs_type != FS_EXFAT && ofs >= 0x100000000) ofs = 0xFFFFFFFF; /* Clip at 4GiB-1 if at FATxx */
#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) {
bcs = (DWORD)fs->csize * SS(fs); /* Cluster size (byte) */
if (ifptr > 0 &&
(ofs - 1) / bcs >= (ifptr - 1) / bcs) { /* When seek to same or following cluster, */
- fp->fptr = (ifptr - 1) & ~(bcs - 1); /* start from the current cluster */
+ fp->fptr = (ifptr - 1) & ~(FSIZE_t)(bcs - 1); /* start from the current cluster */
ofs -= fp->fptr;
clst = fp->clust;
} else { /* When seek to back cluster, */
@@ -3979,20 +4030,25 @@ FRESULT f_lseek (
}
if (clst != 0) {
while (ofs > bcs) { /* Cluster following loop */
+ ofs -= bcs; fp->fptr += bcs;
#if !_FS_READONLY
if (fp->flag & FA_WRITE) { /* Check if in write mode or not */
- clst = create_chain(&fp->obj, clst); /* Force stretch if in write mode */
- if (clst == 0) { /* When disk gets full, clip file size */
- ofs = bcs; break;
+ if (_FS_EXFAT && fp->fptr > fp->obj.objsize) { /* No FAT chain object needs correct objsize to generate FAT value */
+ fp->obj.objsize = fp->fptr;
+ fp->flag |= FA_MODIFIED;
+ }
+ clst = create_chain(&fp->obj, clst); /* Follow chain with forceed stretch */
+ if (clst == 0) { /* Clip file size in case of disk full */
+ ofs = 0; break;
}
} else
#endif
+ {
clst = get_fat(&fp->obj, clst); /* Follow cluster chain if not in write mode */
+ }
if (clst == 0xFFFFFFFF) ABORT(fs, FR_DISK_ERR);
if (clst <= 1 || clst >= fs->n_fatent) ABORT(fs, FR_INT_ERR);
fp->clust = clst;
- fp->fptr += bcs;
- ofs -= bcs;
}
fp->fptr += ofs;
if (ofs % SS(fs)) {
@@ -4002,28 +4058,22 @@ FRESULT f_lseek (
}
}
}
+ if (!_FS_READONLY && fp->fptr > fp->obj.objsize) { /* Set file change flag if the file size is extended */
+ fp->obj.objsize = fp->fptr;
+ fp->flag |= FA_MODIFIED;
+ }
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 &= (BYTE)~FA_DIRTY;
}
#endif
- if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) { /* Fill sector cache */
- ABORT(fs, FR_DISK_ERR);
- }
+ if (disk_read(fs->drv, fp->buf, nsect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR); /* Fill sector cache */
#endif
fp->sect = nsect;
}
-#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;
- }
-#endif
}
LEAVE_FF(fs, res);
@@ -4044,17 +4094,17 @@ FRESULT f_opendir (
FRESULT res;
FATFS *fs;
_FDID *obj;
- DEF_NAMBUF;
+ DEF_NAMBUF
if (!dp) return FR_INVALID_OBJECT;
- /* Get logical drive number */
+ /* Get logical drive */
obj = &dp->obj;
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 */
@@ -4114,7 +4164,7 @@ FRESULT f_closedir (
FATFS *fs;
- res = validate(dp, &fs);
+ res = validate(&dp->obj, &fs); /* Check validity of the file object */
if (res == FR_OK) {
#if _FS_LOCK != 0
if (dp->obj.lockid) { /* Decrement sub-directory open counter */
@@ -4146,15 +4196,15 @@ FRESULT f_readdir (
{
FRESULT res;
FATFS *fs;
- DEF_NAMBUF;
+ DEF_NAMBUF
- res = validate(dp, &fs); /* Check validity of the object */
+ res = validate(&dp->obj, &fs); /* Check validity of the directory object */
if (res == FR_OK) {
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 +4284,13 @@ FRESULT f_stat (
{
FRESULT res;
DIR dj;
- DEF_NAMBUF;
+ DEF_NAMBUF
- /* Get logical drive number */
+ /* Get logical drive */
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 */
@@ -4276,7 +4326,7 @@ FRESULT f_getfree (
_FDID obj;
- /* Get logical drive number */
+ /* Get logical drive */
res = find_volume(&path, &fs, 0);
if (res == FR_OK) {
*fatfs = fs; /* Return ptr to the fs object */
@@ -4309,7 +4359,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
@@ -4358,8 +4408,8 @@ FRESULT f_truncate (
DWORD ncl;
- res = validate(fp, &fs); /* Check validity of the object */
- if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
+ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
if (!(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
if (fp->obj.objsize > fp->fptr) {
@@ -4376,13 +4426,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 &= (BYTE)~FA_DIRTY;
}
}
#endif
@@ -4410,14 +4460,14 @@ FRESULT f_unlink (
#if _FS_EXFAT
_FDID obj;
#endif
- DEF_NAMBUF;
+ DEF_NAMBUF
- /* Get logical drive number */
+ /* Get logical drive */
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 +4554,14 @@ FRESULT f_mkdir (
BYTE *dir;
UINT n;
DWORD dsc, dcl, pcl, tm;
- DEF_NAMBUF;
+ DEF_NAMBUF
- /* Get logical drive number */
+ /* Get logical drive */
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 +4584,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 +4602,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 +4647,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 */
+ res = find_volume(&path_old, &fs, FA_WRITE); /* Get logical drive 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
@@ -4619,10 +4668,12 @@ FRESULT f_rename (
mem_cpy(buf, fs->dirbuf, SZDIRE * 2); /* Save 85+C0 entry of old object */
mem_cpy(&djn, &djo, sizeof djo);
- res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */
- if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */
- if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
- res = dir_register(&djn); /* Register the new entry */
+ res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */
+ if (res == FR_OK) { /* Is new name already in use by any other object? */
+ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
+ }
+ if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
+ res = dir_register(&djn); /* Register the new entry */
if (res == FR_OK) {
nf = fs->dirbuf[XDIR_NumSec]; nn = fs->dirbuf[XDIR_NumName];
nh = ld_word(fs->dirbuf + XDIR_NameHash);
@@ -4639,7 +4690,9 @@ FRESULT f_rename (
mem_cpy(buf, djo.dir + DIR_Attr, 21); /* Save information about the object except name */
mem_cpy(&djn, &djo, sizeof (DIR)); /* Duplicate the directory object */
res = follow_path(&djn, path_new); /* Make sure if new object name is not in use */
- if (res == FR_OK) res = FR_EXIST; /* Is new name already in use? */
+ if (res == FR_OK) { /* Is new name already in use by any other object? */
+ res = (djn.obj.sclust == djo.obj.sclust && djn.dptr == djo.dptr) ? FR_NO_FILE : FR_EXIST;
+ }
if (res == FR_NO_FILE) { /* It is a valid path and no name collision */
res = dir_register(&djn); /* Register the new entry */
if (res == FR_OK) {
@@ -4678,8 +4731,6 @@ FRESULT f_rename (
LEAVE_FF(fs, res);
}
-
-
#endif /* !_FS_READONLY */
#endif /* _FS_MINIMIZE == 0 */
#endif /* _FS_MINIMIZE <= 1 */
@@ -4701,13 +4752,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 */
+ res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
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 +4773,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 +4796,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 */
+ res = find_volume(&path, &fs, FA_WRITE); /* Get logical drive */
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);
@@ -4798,7 +4847,7 @@ FRESULT f_getlabel (
WCHAR w;
#endif
- /* Get logical drive number */
+ /* Get logical drive */
res = find_volume(&path, &fs, 0);
/* Get volume label */
@@ -4859,7 +4908,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);
}
}
@@ -4886,7 +4935,7 @@ FRESULT f_setlabel (
static const char badchr[] = "\"*+,.:;<=>\?[]|\x7F";
- /* Get logical drive number */
+ /* Get logical drive */
res = find_volume(&label, &fs, FA_WRITE);
if (res != FR_OK) LEAVE_FF(fs, res);
dj.obj.fs = fs;
@@ -4895,7 +4944,7 @@ FRESULT f_setlabel (
for (slen = 0; (UINT)label[slen] >= ' '; slen++) ; /* Get name length */
#if _FS_EXFAT
- if (fs->fs_type == FS_EXFAT) { /* At the exFAT */
+ if (fs->fs_type == FS_EXFAT) { /* On the exFAT volume */
for (i = j = 0; i < slen; ) { /* Create volume label in directory form */
w = label[i++];
#if !_LFN_UNICODE
@@ -4912,7 +4961,7 @@ FRESULT f_setlabel (
slen = j;
} else
#endif
- { /* At the FAT12/16/32 */
+ { /* On the FAT12/16/32 volume */
for ( ; slen && label[slen - 1] == ' '; slen--) ; /* Remove trailing spaces */
if (slen) { /* Is there a volume label to be set? */
dirvn[0] = 0; i = j = 0; /* Create volume label in directory form */
@@ -4953,7 +5002,7 @@ FRESULT f_setlabel (
res = dir_read(&dj, 1); /* Get volume label entry */
if (res == FR_OK) {
if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {
- dj.dir[XDIR_NumLabel] = slen / 2; /* Change the volume label */
+ dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2); /* Change the volume label */
mem_cpy(dj.dir + XDIR_Label, dirvn, slen);
} else {
if (slen) {
@@ -4973,7 +5022,7 @@ FRESULT f_setlabel (
mem_set(dj.dir, 0, SZDIRE); /* Clear the entry */
if (_FS_EXFAT && fs->fs_type == FS_EXFAT) {
dj.dir[XDIR_Type] = 0x83; /* Create 83 entry */
- dj.dir[XDIR_NumLabel] = slen / 2;
+ dj.dir[XDIR_NumLabel] = (BYTE)(slen / 2);
mem_cpy(dj.dir + XDIR_Label, dirvn, slen);
} else {
dj.dir[DIR_Attr] = AM_VOL; /* Create volume label entry */
@@ -5008,32 +5057,31 @@ 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 */
- if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
+ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
if (fsz == 0 || fp->obj.objsize != 0 || !(fp->flag & FA_WRITE)) LEAVE_FF(fs, FR_DENIED);
#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 +5089,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 +5134,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,12 +5151,12 @@ FRESULT f_forward (
DWORD clst, sect;
FSIZE_t remain;
UINT rcnt, csect;
- const BYTE *dbuf;
+ BYTE *dbuf;
*bf = 0; /* Clear transfer byte counter */
- res = validate(fp, &fs); /* Check validity of the object */
- if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res); /* Check validity */
+ res = validate(&fp->obj, &fs); /* Check validity of the file object */
+ if (res != FR_OK || (res = (FRESULT)fp->err) != FR_OK) LEAVE_FF(fs, res);
if (!(fp->flag & FA_READ)) LEAVE_FF(fs, FR_DENIED); /* Check access mode */
remain = fp->obj.objsize - fp->fptr;
@@ -5129,9 +5183,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 &= (BYTE)~FA_DIRTY;
}
#endif
if (disk_read(fs->drv, fp->buf, sect, 1) != RES_OK) ABORT(fs, FR_DISK_ERR);
@@ -5153,259 +5207,456 @@ 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};
- int vol;
- BYTE fmt, md, sys, *tbl, pdrv, part;
- DWORD n_clst, vs, n, wsect;
+ 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 szb_buf, sz_buf, sz_blk, n_clst, pau, sect, nsect, n;
+ 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;
- DWORD b_vol, b_fat, b_dir, b_data; /* LBA */
- DWORD n_vol, n_rsv, n_fat, n_dir; /* Size */
- FATFS *fs;
+ int vol;
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 from 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; /* Erase block to align data area */
+#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 > 0x1000000 || (au & (au - 1))) return FR_INVALID_PARAMETER; /* Check if au is valid */
+ au /= ss; /* Cluster size in unit of sector */
+
+ /* Get working buffer */
+ buf = (BYTE*)work; /* Working buffer */
+ sz_buf = len / ss; /* Size of working buffer (sector) */
+ szb_buf = sz_buf * ss; /* Size of working buffer (byte) */
+ if (!szb_buf) return FR_MKFS_ABORTED;
+
+ /* 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 if 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 if volume size is >=128s */
+
+ /* Pre-determine the FAT type */
+ do {
+ if (_FS_EXFAT && (opt & FM_EXFAT)) { /* exFAT possible? */
+ if ((opt & FM_ANY) == FM_EXFAT || sz_vol >= 0x4000000 || au > 128) { /* exFAT only, vol >= 64Ms or au > 128s ? */
+ fmt = FS_EXFAT; break;
+ }
}
- b_vol = (sfd) ? 0 : 63; /* Volume start sector */
- n_vol -= b_vol; /* Volume size */
- }
+ if (au > 128) 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 szb_bit, szb_case, sum, nb, cl;
+ 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; /* Number 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; /* Number 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 allocation bitmap 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 */
+ n = (i + ss - 1) / ss;
+ if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
+ sect += n; i = 0;
+ }
+ } while (si);
+ tbl[1] = (szb_case + au * ss - 1) / (au * ss); /* Number of up-case table clusters */
+ tbl[2] = 1; /* Number of root dir 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 */
+ sect = b_data; nsect = (szb_bit + ss - 1) / ss; /* Start of bitmap and number of sectors */
+ nb = tbl[0] + tbl[1] + tbl[2]; /* Number of clusters in-use by system */
+ do {
+ mem_set(buf, 0, szb_buf);
+ for (i = 0; nb >= 8 && i < szb_buf; buf[i++] = 0xFF, nb -= 8) ;
+ for (b = 1; nb && i < szb_buf; buf[i] |= b, b <<= 1, nb--) ;
+ n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */
+ if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
+ sect += n; nsect -= n;
+ } while (nsect);
+
+ /* Initialize the FAT */
+ sect = b_fat; nsect = sz_fat; /* Start of FAT and number of FAT sectors */
+ j = nb = cl = 0;
+ do {
+ mem_set(buf, 0, szb_buf); i = 0; /* Clear work area and reset write index */
+ if (cl == 0) { /* Set entry 0 and 1 */
+ st_dword(buf + i, 0xFFFFFFF8); i += 4; cl++;
+ st_dword(buf + i, 0xFFFFFFFF); i += 4; cl++;
+ }
+ do { /* Create chains of bitmap, up-case and root dir */
+ while (nb && i < szb_buf) { /* Create a chain */
+ st_dword(buf + i, (nb > 1) ? cl + 1 : 0xFFFFFFFF);
+ i += 4; cl++; nb--;
+ }
+ if (!nb && j < 3) nb = tbl[j++]; /* Next chain */
+ } while (nb && i < szb_buf);
+ n = (nsect > sz_buf) ? sz_buf : nsect; /* Write the buffered data */
+ if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
+ sect += n; nsect -= n;
+ } while (nsect);
+
+ /* Initialize the root directory */
+ mem_set(buf, 0, szb_buf);
+ 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]); nsect = au; /* Start of the root directory and number of sectors */
+ do { /* Fill root directory sectors */
+ n = (nsect > sz_buf) ? sz_buf : nsect;
+ if (disk_write(pdrv, buf, sect, n) != RES_OK) return FR_DISK_ERR;
+ mem_set(buf, 0, ss);
+ sect += n; nsect -= n;
+ } while (nsect);
+
+ /* 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 /* _FS_EXFAT */
+ { /* 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] = (BYTE)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 32-bit LBA */
+ }
+ buf[BPB_Media] = 0xF8; /* Media descriptor byte */
+ 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, (UINT)szb_buf);
+ sect = b_fat; /* 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 */
+ }
+ nsect = sz_fat; /* Number of FAT sectors */
+ do { /* Fill FAT sectors */
+ n = (nsect > sz_buf) ? sz_buf : nsect;
+ if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
+ mem_set(buf, 0, ss);
+ sect += n; nsect -= n;
+ } while (nsect);
+ }
+
+ /* Initialize root directory (fill with zero) */
+ nsect = (fmt == FS_FAT32) ? pau : sz_dir; /* Number of root directory sectors */
+ do {
+ n = (nsect > sz_buf) ? sz_buf : nsect;
+ if (disk_write(pdrv, buf, sect, (UINT)n) != RES_OK) return FR_DISK_ERR;
+ sect += n; nsect -= n;
+ } while (nsect);
}
/* 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 +5668,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 +5683,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 +5727,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 +5818,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 +5838,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 +5880,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 +5912,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 +5932,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 +5953,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 +6036,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..981a886
--- 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.12b /
+/-----------------------------------------------------------------------------/
/
/ 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 68020 /* 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 {
@@ -155,18 +159,18 @@ typedef struct {
/* File object structure (FIL) */
typedef struct {
- _FDID obj; /* Object identifier */
+ _FDID obj; /* Object identifier (must be the 1st member to detect invalid object pointer) */
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 661fa57..75cfef4
--- 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 68020 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Function Configurations
@@ -15,7 +15,7 @@
/ and optional writing functions as well. */
-#define _FS_MINIMIZE 1
+#define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
@@ -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
@@ -205,19 +204,19 @@
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
-/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS bytes.
+/ At the tiny configuration, size of file object (FIL) is reduced _MAX_SS bytes.
/ Instead of private sector buffer eliminated from the file object, common sector
/ buffer in the file system object (FATFS) is used for the file data transfer. */
#define _FS_EXFAT 0
-/* This option switches support of exFAT file system in addition to the traditional
-/ FAT file system. (0:Disable or 1:Enable) To enable exFAT, also LFN must be enabled.
+/* This option switches support of exFAT file system. (0:Disable or 1:Enable)
+/ When enable exFAT, also LFN needs to be enabled. (_USE_LFN >= 1)
/ Note that enabling exFAT discards C89 compatibility. */
#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
@@ -260,7 +259,9 @@
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
-/ included somewhere in the scope of ff.c. */
+/ included somewhere in the scope of ff.h. */
+
+/* #include // O/S definitions */
/*--- End of configuration options ---*/
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/fatfs/sdmmc/common.h b/source/fatfs/sdmmc/common.h
deleted file mode 100644
index 90a327e..0000000
--- a/source/fatfs/sdmmc/common.h
+++ /dev/null
@@ -1,4 +0,0 @@
-#pragma once
-
-#include
-#include "../../types.h"
\ No newline at end of file
diff --git a/source/fatfs/sdmmc/delay.h b/source/fatfs/sdmmc/delay.h
index afad438..543794a 100644
--- a/source/fatfs/sdmmc/delay.h
+++ b/source/fatfs/sdmmc/delay.h
@@ -1,9 +1,5 @@
-// Copyright 2014 Normmatt
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
#pragma once
-#include "common.h"
+#include "../../types.h"
-void ioDelay(u32 us);
+void waitcycles(u32 us);
diff --git a/source/fatfs/sdmmc/delay.s b/source/fatfs/sdmmc/delay.s
index b3baccd..0bf19c2 100644
--- a/source/fatfs/sdmmc/delay.s
+++ b/source/fatfs/sdmmc/delay.s
@@ -1,17 +1,16 @@
-// Copyright 2014 Normmatt
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
+.text
.arm
-.global ioDelay
-.type ioDelay STT_FUNC
+.align 4
-@ioDelay ( u32 us )
-ioDelay:
- ldr r1, =0x18000000 @ VRAM
-1:
- @ Loop doing uncached reads from VRAM to make loop timing more reliable
- ldr r2, [r1]
- subs r0, #1
- bgt 1b
- bx lr
+.global waitcycles
+.type waitcycles, %function
+waitcycles:
+ push {r0-r2, lr}
+ str r0, [sp, #4]
+ waitcycles_loop:
+ ldr r3, [sp, #4]
+ subs r2, r3, #1
+ str r2, [sp, #4]
+ cmp r3, #0
+ bne waitcycles_loop
+ pop {r0-r2, pc}
diff --git a/source/fatfs/sdmmc/sdmmc.c b/source/fatfs/sdmmc/sdmmc.c
index bee13d7..150fac3 100644
--- a/source/fatfs/sdmmc/sdmmc.c
+++ b/source/fatfs/sdmmc/sdmmc.c
@@ -1,30 +1,55 @@
-// Copyright 2014 Normmatt
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/.
+ *
+ * Copyright (c) 2014-2015, Normmatt
+ *
+ * Alternatively, the contents of this file may be used under the terms
+ * of the GNU General Public License Version 2, as described below:
+ *
+ * This file is free software: you may copy, redistribute and/or modify
+ * it under the terms of the GNU General Public License as published by the
+ * Free Software Foundation, either version 2 of the License, or (at your
+ * option) any later version.
+ *
+ * This file is distributed in the hope that it will be useful, but
+ * WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
+ * Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see http://www.gnu.org/licenses/.
+ */
#include "sdmmc.h"
#include "delay.h"
-struct mmcdevice handleNAND;
-struct mmcdevice handleSD;
+static struct mmcdevice handleNAND;
+static struct mmcdevice handleSD;
-static inline u16 sdmmc_read16(u16 reg) {
- return *(vu16*)(SDMMC_BASE + reg);
+static inline u16 sdmmc_read16(u16 reg)
+{
+ return *(vu16 *)(SDMMC_BASE + reg);
}
-static inline void sdmmc_write16(u16 reg, u16 val) {
- *(vu16*)(SDMMC_BASE + reg) = val;
+static inline void sdmmc_write16(u16 reg, u16 val)
+{
+ *(vu16 *)(SDMMC_BASE + reg) = val;
}
-static inline u32 sdmmc_read32(u16 reg) {
- return *(vu32*)(SDMMC_BASE + reg);
+static inline u32 sdmmc_read32(u16 reg)
+{
+ return *(vu32 *)(SDMMC_BASE + reg);
}
-static inline void sdmmc_write32(u16 reg, u32 val) {
- *(vu32*)(SDMMC_BASE + reg) = val;
+static inline void sdmmc_write32(u16 reg, u32 val)
+{
+ *(vu32 *)(SDMMC_BASE + reg) = val;
}
-static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set) {
+static inline void sdmmc_mask16(u16 reg, const u16 clear, const u16 set)
+{
u16 val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
@@ -38,188 +63,213 @@ static inline void setckl(u32 data)
sdmmc_mask16(REG_SDCLKCTL, 0x0, 0x100);
}
-
mmcdevice *getMMCDevice(int drive)
{
- if(drive==0) return &handleNAND;
+ if(drive == 0) return &handleNAND;
return &handleSD;
}
-static u32 __attribute__((noinline)) geterror(struct mmcdevice *ctx)
+static int geterror(struct mmcdevice *ctx)
{
- return (ctx->error << 29) >> 31;
+ return (int)((ctx->error << 29) >> 31);
}
-static void __attribute__((noinline)) inittarget(struct mmcdevice *ctx)
+static void inittarget(struct mmcdevice *ctx)
{
- sdmmc_mask16(REG_SDPORTSEL,0x3,(u16)ctx->devicenumber);
+ sdmmc_mask16(REG_SDPORTSEL, 0x3, (u16)ctx->devicenumber);
setckl(ctx->clk);
- if (ctx->SDOPT == 0) {
- sdmmc_mask16(REG_SDOPT, 0, 0x8000);
- } else {
- sdmmc_mask16(REG_SDOPT, 0x8000, 0);
- }
-
+ if(ctx->SDOPT == 0) sdmmc_mask16(REG_SDOPT, 0, 0x8000);
+ else sdmmc_mask16(REG_SDOPT, 0x8000, 0);
}
static void __attribute__((noinline)) sdmmc_send_command(struct mmcdevice *ctx, u32 cmd, u32 args)
{
- bool getSDRESP = (cmd << 15) >> 31;
+ u32 getSDRESP = (cmd << 15) >> 31;
u16 flags = (cmd << 15) >> 31;
- const bool readdata = cmd & 0x20000;
- const bool writedata = cmd & 0x40000;
+ const int readdata = cmd & 0x20000;
+ const int writedata = cmd & 0x40000;
- if (readdata || writedata)
+ if(readdata || writedata)
flags |= TMIO_STAT0_DATAEND;
ctx->error = 0;
- while (sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY); //mmc working?
- sdmmc_write16(REG_SDIRMASK0,0);
- sdmmc_write16(REG_SDIRMASK1,0);
- sdmmc_write16(REG_SDSTATUS0,0);
- sdmmc_write16(REG_SDSTATUS1,0);
- sdmmc_mask16(REG_SDDATACTL32,0x1800,0);
-
- sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
- sdmmc_write16(REG_SDCMDARG1,args >> 16);
- sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
+ while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working?
+ sdmmc_write16(REG_SDIRMASK0, 0);
+ sdmmc_write16(REG_SDIRMASK1, 0);
+ sdmmc_write16(REG_SDSTATUS0, 0);
+ sdmmc_write16(REG_SDSTATUS1, 0);
+ sdmmc_mask16(REG_DATACTL32, 0x1800, 0);
+ sdmmc_write16(REG_SDCMDARG0, args & 0xFFFF);
+ sdmmc_write16(REG_SDCMDARG1, args >> 16);
+ sdmmc_write16(REG_SDCMD, cmd & 0xFFFF);
u32 size = ctx->size;
- vu8 *dataPtr = ctx->data;
+ u8 *rDataPtr = ctx->rData;
+ const u8 *tDataPtr = ctx->tData;
- bool useBuf = ( NULL != dataPtr );
+ bool rUseBuf = rDataPtr != NULL;
+ bool tUseBuf = tDataPtr != NULL;
u16 status0 = 0;
- while(true) {
- u16 status1 = sdmmc_read16(REG_SDSTATUS1);
- if (status1 & TMIO_STAT1_RXRDY) {
- if (readdata && useBuf) {
- sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
- //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
- if (size > 0x1FF) {
- for(int i = 0; i<0x200; i+=2) {
- u16 data = sdmmc_read16(REG_SDFIFO);
- *dataPtr++ = data & 0xFF;
- *dataPtr++ = data >> 8;
+ while(true)
+ {
+ vu16 status1 = sdmmc_read16(REG_SDSTATUS1);
+ vu16 ctl32 = sdmmc_read16(REG_DATACTL32);
+ if((ctl32 & 0x100))
+ {
+ if(readdata)
+ {
+ if(rUseBuf)
+ {
+ sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
+ if(size > 0x1FF)
+ {
+ //Gabriel Marcano: This implementation doesn't assume alignment.
+ //I've removed the alignment check doen with former rUseBuf32 as a result
+ for(int i = 0; i < 0x200; i += 4)
+ {
+ u32 data = sdmmc_read32(REG_SDFIFO32);
+ *rDataPtr++ = data;
+ *rDataPtr++ = data >> 8;
+ *rDataPtr++ = data >> 16;
+ *rDataPtr++ = data >> 24;
+ }
+ size -= 0x200;
}
- size -= 0x200;
}
- }
- }
- if (status1 & TMIO_STAT1_TXRQ) {
- if (writedata && useBuf) {
- sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
- //sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
- if (size > 0x1FF) {
- for (int i = 0; i<0x200; i+=2) {
- u16 data = *dataPtr++;
- data |= *dataPtr++ << 8;
- sdmmc_write16(REG_SDFIFO, data);
- }
- size -= 0x200;
- }
+ sdmmc_mask16(REG_DATACTL32, 0x800, 0);
}
}
- if (status1 & TMIO_MASK_GW) {
+ if(!(ctl32 & 0x200))
+ {
+ if(writedata)
+ {
+ if(tUseBuf)
+ {
+ sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
+ if(size > 0x1FF)
+ {
+ for(int i = 0; i < 0x200; i += 4)
+ {
+ u32 data = *tDataPtr++;
+ data |= (u32)*tDataPtr++ << 8;
+ data |= (u32)*tDataPtr++ << 16;
+ data |= (u32)*tDataPtr++ << 24;
+ sdmmc_write32(REG_SDFIFO32, data);
+ }
+ size -= 0x200;
+ }
+ }
+
+ sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
+ }
+ }
+ if(status1 & TMIO_MASK_GW)
+ {
ctx->error |= 4;
break;
}
- if (!(status1 & TMIO_STAT1_CMD_BUSY)) {
+ if(!(status1 & TMIO_STAT1_CMD_BUSY))
+ {
status0 = sdmmc_read16(REG_SDSTATUS0);
- if (sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
+ if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
+ {
ctx->error |= 0x1;
- if (status0 & TMIO_STAT0_DATAEND)
+ }
+ if(status0 & TMIO_STAT0_DATAEND)
+ {
ctx->error |= 0x2;
+ }
- if ((status0 & flags) == flags)
+ if((status0 & flags) == flags)
break;
}
}
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
- sdmmc_write16(REG_SDSTATUS0,0);
- sdmmc_write16(REG_SDSTATUS1,0);
+ sdmmc_write16(REG_SDSTATUS0, 0);
+ sdmmc_write16(REG_SDSTATUS1, 0);
- if (getSDRESP != 0) {
- ctx->ret[0] = (u32)sdmmc_read16(REG_SDRESP0) | (u32)(sdmmc_read16(REG_SDRESP1) << 16);
- ctx->ret[1] = (u32)sdmmc_read16(REG_SDRESP2) | (u32)(sdmmc_read16(REG_SDRESP3) << 16);
- ctx->ret[2] = (u32)sdmmc_read16(REG_SDRESP4) | (u32)(sdmmc_read16(REG_SDRESP5) << 16);
- ctx->ret[3] = (u32)sdmmc_read16(REG_SDRESP6) | (u32)(sdmmc_read16(REG_SDRESP7) << 16);
+ if(getSDRESP != 0)
+ {
+ ctx->ret[0] = (u32)(sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16));
+ ctx->ret[1] = (u32)(sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16));
+ ctx->ret[2] = (u32)(sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16));
+ ctx->ret[3] = (u32)(sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16));
}
}
-u32 __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in)
+int __attribute__((noinline)) sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in)
{
- if (handleSD.isSDHC == 0)
- sector_no <<= 9;
+ if(handleSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handleSD);
- sdmmc_write16(REG_SDSTOP,0x100);
-
- sdmmc_write16(REG_SDBLKCOUNT,numsectors);
- handleSD.data = in;
+ sdmmc_write16(REG_SDSTOP, 0x100);
+ sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
+ sdmmc_write16(REG_SDBLKLEN32, 0x200);
+ sdmmc_write16(REG_SDBLKCOUNT, numsectors);
+ handleSD.tData = in;
handleSD.size = numsectors << 9;
- sdmmc_send_command(&handleSD,0x52C19,sector_no);
+ sdmmc_send_command(&handleSD, 0x52C19, sector_no);
return geterror(&handleSD);
}
-u32 __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
+int __attribute__((noinline)) sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out)
{
- if (handleSD.isSDHC == 0)
- sector_no <<= 9;
+ if(handleSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handleSD);
- sdmmc_write16(REG_SDSTOP,0x100);
-
- sdmmc_write16(REG_SDBLKCOUNT,numsectors);
- handleSD.data = out;
+ sdmmc_write16(REG_SDSTOP, 0x100);
+ sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
+ sdmmc_write16(REG_SDBLKLEN32, 0x200);
+ sdmmc_write16(REG_SDBLKCOUNT, numsectors);
+ handleSD.rData = out;
handleSD.size = numsectors << 9;
- sdmmc_send_command(&handleSD,0x33C12,sector_no);
+ sdmmc_send_command(&handleSD, 0x33C12, sector_no);
return geterror(&handleSD);
}
-u32 __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out)
+int __attribute__((noinline)) sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out)
{
- if (handleNAND.isSDHC == 0)
- sector_no <<= 9;
+ if(handleNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handleNAND);
- sdmmc_write16(REG_SDSTOP,0x100);
-
- sdmmc_write16(REG_SDBLKCOUNT,numsectors);
-
- handleNAND.data = out;
+ sdmmc_write16(REG_SDSTOP, 0x100);
+ sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
+ sdmmc_write16(REG_SDBLKLEN32, 0x200);
+ sdmmc_write16(REG_SDBLKCOUNT, numsectors);
+ handleNAND.rData = out;
handleNAND.size = numsectors << 9;
- sdmmc_send_command(&handleNAND,0x33C12,sector_no);
+ sdmmc_send_command(&handleNAND, 0x33C12, sector_no);
inittarget(&handleSD);
return geterror(&handleNAND);
}
-u32 __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in) //experimental
+int __attribute__((noinline)) sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in) //experimental
{
- if (handleNAND.isSDHC == 0)
- sector_no <<= 9;
+ if(handleNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handleNAND);
- sdmmc_write16(REG_SDSTOP,0x100);
-
- sdmmc_write16(REG_SDBLKCOUNT,numsectors);
-
- handleNAND.data = in;
+ sdmmc_write16(REG_SDSTOP, 0x100);
+ sdmmc_write16(REG_SDBLKCOUNT32, numsectors);
+ sdmmc_write16(REG_SDBLKLEN32, 0x200);
+ sdmmc_write16(REG_SDBLKCOUNT, numsectors);
+ handleNAND.tData = in;
handleNAND.size = numsectors << 9;
- sdmmc_send_command(&handleNAND,0x52C19,sector_no);
+ sdmmc_send_command(&handleNAND, 0x52C19, sector_no);
inittarget(&handleSD);
return geterror(&handleNAND);
}
-static u32 calcSDSize(u8* csd, int type)
+static u32 calcSDSize(u8 *csd, int type)
{
u32 result = 0;
- if (type == -1) type = csd[14] >> 6;
- switch (type) {
+ if(type == -1) type = csd[14] >> 6;
+ switch(type)
+ {
case 0:
{
- u32 block_len = csd[9] & 0xf;
+ u32 block_len = csd[9] & 0xF;
block_len = 1u << block_len;
- u32 mult = (u32)(csd[4] >> 7) | (u32)((csd[5] & 3) << 1);
+ u32 mult = (u32)((csd[4] >> 7) | ((csd[5] & 3) << 1));
mult = 1u << (mult + 2);
result = csd[8] & 3;
result = (result << 8) | csd[7];
@@ -228,18 +278,42 @@ static u32 calcSDSize(u8* csd, int type)
}
break;
case 1:
- result = csd[7] & 0x3f;
+ result = csd[7] & 0x3F;
result = (result << 8) | csd[6];
result = (result << 8) | csd[5];
result = (result + 1) * 1024;
break;
- default:
- break; //Do nothing otherwise
+ default:
+ break; //Do nothing otherwise FIXME perhaps return some error?
}
return result;
}
static void InitSD()
+{
+ *(vu16 *)0x10006100 &= 0xF7FFu; //SDDATACTL32
+ *(vu16 *)0x10006100 &= 0xEFFFu; //SDDATACTL32
+ *(vu16 *)0x10006100 |= 0x402u; //SDDATACTL32
+ *(vu16 *)0x100060D8 = (*(vu16 *)0x100060D8 & 0xFFDD) | 2;
+ *(vu16 *)0x10006100 &= 0xFFFFu; //SDDATACTL32
+ *(vu16 *)0x100060D8 &= 0xFFDFu; //SDDATACTL
+ *(vu16 *)0x10006104 = 512; //SDBLKLEN32
+ *(vu16 *)0x10006108 = 1; //SDBLKCOUNT32
+ *(vu16 *)0x100060E0 &= 0xFFFEu; //SDRESET
+ *(vu16 *)0x100060E0 |= 1u; //SDRESET
+ *(vu16 *)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
+ *(vu16 *)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
+ *(vu16 *)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
+ *(vu16 *)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
+ *(vu16 *)0x10006002 &= 0xFFFCu; //SDPORTSEL
+ *(vu16 *)0x10006024 = 0x20;
+ *(vu16 *)0x10006028 = 0x40EE;
+ *(vu16 *)0x10006002 &= 0xFFFCu; ////SDPORTSEL
+ *(vu16 *)0x10006026 = 512; //SDBLKLEN
+ *(vu16 *)0x10006008 = 0; //SDSTOP
+}
+
+static int Nand_Init()
{
//NAND
handleNAND.isSDHC = 0;
@@ -249,80 +323,50 @@ static void InitSD()
handleNAND.clk = 0x80;
handleNAND.devicenumber = 1;
- //SD
- handleSD.isSDHC = 0;
- handleSD.SDOPT = 0;
- handleSD.res = 0;
- handleSD.initarg = 0;
- handleSD.clk = 0x80;
- handleSD.devicenumber = 0;
-
- *(vu16*)0x10006100 &= 0xF7FFu; //SDDATACTL32
- *(vu16*)0x10006100 &= 0xEFFFu; //SDDATACTL32
- *(vu16*)0x10006100 |= 0x402u; //SDDATACTL32
- *(vu16*)0x100060D8 = (*(vu16*)0x100060D8 & 0xFFDD) | 2;
- *(vu16*)0x10006100 &= 0xFFFDu; //SDDATACTL32
- *(vu16*)0x100060D8 &= 0xFFDDu; //SDDATACTL
- *(vu16*)0x10006104 = 0; //SDBLKLEN32
- *(vu16*)0x10006108 = 1; //SDBLKCOUNT32
- *(vu16*)0x100060E0 &= 0xFFFEu; //SDRESET
- *(vu16*)0x100060E0 |= 1u; //SDRESET
- *(vu16*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
- *(vu16*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
- *(vu16*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
- *(vu16*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
- *(vu16*)0x10006002 &= 0xFFFCu; //SDPORTSEL
- *(vu16*)0x10006024 = 0x40; //Nintendo sets this to 0x20
- *(vu16*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
- *(vu16*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
- *(vu16*)0x10006026 = 512; //SDBLKLEN
- *(vu16*)0x10006008 = 0; //SDSTOP
-
- inittarget(&handleSD);
-}
-
-static int Nand_Init()
-{
inittarget(&handleNAND);
- ioDelay(0xF000);
+ waitcycles(0xF000);
- sdmmc_send_command(&handleNAND,0,0);
+ sdmmc_send_command(&handleNAND, 0, 0);
- do {
- do {
- sdmmc_send_command(&handleNAND,0x10701,0x100000);
- } while ( !(handleNAND.error & 1) );
- } while((handleNAND.ret[0] & 0x80000000) == 0);
+ do
+ {
+ do
+ {
+ sdmmc_send_command(&handleNAND, 0x10701, 0x100000);
+ }
+ while(!(handleNAND.error & 1));
+ }
+ while((handleNAND.ret[0] & 0x80000000) == 0);
- sdmmc_send_command(&handleNAND,0x10602,0x0);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10602, 0x0);
+ if((handleNAND.error & 0x4)) return -1;
- sdmmc_send_command(&handleNAND,0x10403,handleNAND.initarg << 0x10);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10403, handleNAND.initarg << 0x10);
+ if((handleNAND.error & 0x4)) return -1;
- sdmmc_send_command(&handleNAND,0x10609,handleNAND.initarg << 0x10);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10609, handleNAND.initarg << 0x10);
+ if((handleNAND.error & 0x4)) return -1;
- handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0],0);
+ handleNAND.total_size = calcSDSize((u8*)&handleNAND.ret[0], 0);
handleNAND.clk = 1;
setckl(1);
- sdmmc_send_command(&handleNAND,0x10407,handleNAND.initarg << 0x10);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10407, handleNAND.initarg << 0x10);
+ if((handleNAND.error & 0x4)) return -1;
handleNAND.SDOPT = 1;
- sdmmc_send_command(&handleNAND,0x10506,0x3B70100);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10506, 0x3B70100);
+ if((handleNAND.error & 0x4)) return -1;
- sdmmc_send_command(&handleNAND,0x10506,0x3B90100);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10506, 0x3B90100);
+ if((handleNAND.error & 0x4)) return -1;
- sdmmc_send_command(&handleNAND,0x1040D,handleNAND.initarg << 0x10);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x1040D, handleNAND.initarg << 0x10);
+ if((handleNAND.error & 0x4)) return -1;
- sdmmc_send_command(&handleNAND,0x10410,0x200);
- if (handleNAND.error & 0x4) return -1;
+ sdmmc_send_command(&handleNAND, 0x10410, 0x200);
+ if((handleNAND.error & 0x4)) return -1;
handleNAND.clk |= 0x200;
@@ -333,113 +377,102 @@ static int Nand_Init()
static int SD_Init()
{
+ //SD
+ handleSD.isSDHC = 0;
+ handleSD.SDOPT = 0;
+ handleSD.res = 0;
+ handleSD.initarg = 0;
+ handleSD.clk = 0x80;
+ handleSD.devicenumber = 0;
+
inittarget(&handleSD);
- ioDelay(1u << 18); //Card needs a little bit of time to be detected, it seems
-
+ waitcycles(1u << 22); //Card needs a little bit of time to be detected, it seems FIXME test again to see what a good number is for the delay
+
//If not inserted
- if (!(*((vu16*)0x1000601c) & TMIO_STAT0_SIGSTATE)) return -1;
-
- sdmmc_send_command(&handleSD,0,0);
- sdmmc_send_command(&handleSD,0x10408,0x1AA);
- //u32 temp = (handleSD.ret[0] == 0x1AA) << 0x1E;
+ if(!(*((vu16 *)(SDMMC_BASE + REG_SDSTATUS0)) & TMIO_STAT0_SIGSTATE)) return 5;
+
+ sdmmc_send_command(&handleSD, 0, 0);
+ sdmmc_send_command(&handleSD, 0x10408, 0x1AA);
u32 temp = (handleSD.error & 0x1) << 0x1E;
- //int count = 0;
u32 temp2 = 0;
- do {
- do {
- sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
- sdmmc_send_command(&handleSD,0x10769,0x00FF8000 | temp);
+ do
+ {
+ do
+ {
+ sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10);
+ sdmmc_send_command(&handleSD, 0x10769, 0x00FF8000 | temp);
temp2 = 1;
- } while ( !(handleSD.error & 1) );
-
- } while((handleSD.ret[0] & 0x80000000) == 0);
+ }
+ while(!(handleSD.error & 1));
+ }
+ while((handleSD.ret[0] & 0x80000000) == 0);
if(!((handleSD.ret[0] >> 30) & 1) || !temp)
temp2 = 0;
handleSD.isSDHC = temp2;
- sdmmc_send_command(&handleSD,0x10602,0);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10602, 0);
+ if((handleSD.error & 0x4)) return -1;
- sdmmc_send_command(&handleSD,0x10403,0);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10403, 0);
+ if((handleSD.error & 0x4)) return -2;
handleSD.initarg = handleSD.ret[0] >> 0x10;
- sdmmc_send_command(&handleSD,0x10609,handleSD.initarg << 0x10);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10609, handleSD.initarg << 0x10);
+ if((handleSD.error & 0x4)) return -3;
- handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0],-1);
+ handleSD.total_size = calcSDSize((u8*)&handleSD.ret[0], -1);
handleSD.clk = 1;
setckl(1);
- sdmmc_send_command(&handleSD,0x10507,handleSD.initarg << 0x10);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10507, handleSD.initarg << 0x10);
+ if((handleSD.error & 0x4)) return -4;
- sdmmc_send_command(&handleSD,0x10437,handleSD.initarg << 0x10);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10437, handleSD.initarg << 0x10);
+ if((handleSD.error & 0x4)) return -5;
handleSD.SDOPT = 1;
- sdmmc_send_command(&handleSD,0x10446,0x2);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10446, 0x2);
+ if((handleSD.error & 0x4)) return -6;
- sdmmc_send_command(&handleSD,0x1040D,handleSD.initarg << 0x10);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x1040D, handleSD.initarg << 0x10);
+ if((handleSD.error & 0x4)) return -7;
- sdmmc_send_command(&handleSD,0x10410,0x200);
- if (handleSD.error & 0x4) return -1;
+ sdmmc_send_command(&handleSD, 0x10410, 0x200);
+ if((handleSD.error & 0x4)) return -8;
handleSD.clk |= 0x200;
return 0;
}
-int sdmmc_sdcard_init()
+void sdmmc_get_cid(bool isNand, u32 *info)
{
- InitSD();
- int result = Nand_Init();
- return result | SD_Init();
+ struct mmcdevice *device = isNand ? &handleNAND : &handleSD;
+
+ inittarget(device);
+
+ // use cmd7 to put sd card in standby mode
+ // CMD7
+ sdmmc_send_command(device, 0x10507, 0);
+
+ // get sd card info
+ // use cmd10 to read CID
+ sdmmc_send_command(device, 0x1060A, device->initarg << 0x10);
+
+ for(int i = 0; i < 4; ++i)
+ info[i] = device->ret[i];
+
+ // put sd card back to transfer mode
+ // CMD7
+ sdmmc_send_command(device, 0x10507, device->initarg << 0x10);
}
-int sdmmc_get_cid( int isNand, uint32_t *info)
+void sdmmc_sdcard_init()
{
- struct mmcdevice *device;
- if(isNand)
- device = &handleNAND;
- else
- device = &handleSD;
-
- inittarget(device);
- // use cmd7 to put sd card in standby mode
- // CMD7
- {
- sdmmc_send_command(device,0x10507,0);
- //if((device->error & 0x4)) return -1;
- }
-
- // get sd card info
- // use cmd10 to read CID
- {
- sdmmc_send_command(device,0x1060A,device->initarg << 0x10);
- //if((device->error & 0x4)) return -2;
-
- for( int i = 0; i < 4; ++i ) {
- info[i] = device->ret[i];
- }
- }
-
- // put sd card back to transfer mode
- // CMD7
- {
- sdmmc_send_command(device,0x10507,device->initarg << 0x10);
- //if((device->error & 0x4)) return -3;
- }
-
- if(isNand)
- {
- inittarget(&handleSD);
- }
-
- return 0;
+ InitSD();
+ Nand_Init();
+ SD_Init();
}
\ No newline at end of file
diff --git a/source/fatfs/sdmmc/sdmmc.h b/source/fatfs/sdmmc/sdmmc.h
index 9c1fdd7..fa3d960 100644
--- a/source/fatfs/sdmmc/sdmmc.h
+++ b/source/fatfs/sdmmc/sdmmc.h
@@ -1,52 +1,48 @@
-// Copyright 2014 Normmatt
-// Licensed under GPLv2 or any later version
-// Refer to the license.txt file included.
-
#pragma once
-#include "common.h"
+#include "../../types.h"
-#define SDMMC_BASE 0x10006000u
+#define SDMMC_BASE 0x10006000
-#define REG_SDCMD 0x00
-#define REG_SDPORTSEL 0x02
-#define REG_SDCMDARG 0x04
-#define REG_SDCMDARG0 0x04
-#define REG_SDCMDARG1 0x06
-#define REG_SDSTOP 0x08
-#define REG_SDBLKCOUNT 0x0a
+#define REG_SDCMD 0x00
+#define REG_SDPORTSEL 0x02
+#define REG_SDCMDARG 0x04
+#define REG_SDCMDARG0 0x04
+#define REG_SDCMDARG1 0x06
+#define REG_SDSTOP 0x08
+#define REG_SDBLKCOUNT 0x0A
-#define REG_SDRESP0 0x0c
-#define REG_SDRESP1 0x0e
-#define REG_SDRESP2 0x10
-#define REG_SDRESP3 0x12
-#define REG_SDRESP4 0x14
-#define REG_SDRESP5 0x16
-#define REG_SDRESP6 0x18
-#define REG_SDRESP7 0x1a
+#define REG_SDRESP0 0x0C
+#define REG_SDRESP1 0x0E
+#define REG_SDRESP2 0x10
+#define REG_SDRESP3 0x12
+#define REG_SDRESP4 0x14
+#define REG_SDRESP5 0x16
+#define REG_SDRESP6 0x18
+#define REG_SDRESP7 0x1A
-#define REG_SDSTATUS0 0x1c
-#define REG_SDSTATUS1 0x1e
+#define REG_SDSTATUS0 0x1C
+#define REG_SDSTATUS1 0x1E
-#define REG_SDIRMASK0 0x20
-#define REG_SDIRMASK1 0x22
-#define REG_SDCLKCTL 0x24
+#define REG_SDIRMASK0 0x20
+#define REG_SDIRMASK1 0x22
+#define REG_SDCLKCTL 0x24
-#define REG_SDBLKLEN 0x26
-#define REG_SDOPT 0x28
-#define REG_SDFIFO 0x30
+#define REG_SDBLKLEN 0x26
+#define REG_SDOPT 0x28
+#define REG_SDFIFO 0x30
-#define REG_SDDATACTL 0xd8
-#define REG_SDRESET 0xe0
-#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
+#define REG_DATACTL 0xD8
+#define REG_SDRESET 0xE0
+#define REG_SDPROTECTED 0xF6 //bit 0 determines if sd is protected or not?
-#define REG_SDDATACTL32 0x100
-#define REG_SDBLKLEN32 0x104
-#define REG_SDBLKCOUNT32 0x108
-#define REG_SDFIFO32 0x10C
+#define REG_DATACTL32 0x100
+#define REG_SDBLKLEN32 0x104
+#define REG_SDBLKCOUNT32 0x108
+#define REG_SDFIFO32 0x10C
-#define REG_CLK_AND_WAIT_CTL 0x138
-#define REG_RESET_SDIO 0x1e0
+#define REG_CLK_AND_WAIT_CTL 0x138
+#define REG_RESET_SDIO 0x1E0
#define TMIO_STAT0_CMDRESPEND 0x0001
#define TMIO_STAT0_DATAEND 0x0004
@@ -70,31 +66,7 @@
#define TMIO_STAT1_CMD_BUSY 0x4000
#define TMIO_STAT1_ILL_ACCESS 0x8000
-//Comes from TWLSDK mongoose.tef DWARF info
-#define SDMC_NORMAL 0x00000000
-#define SDMC_ERR_COMMAND 0x00000001
-#define SDMC_ERR_CRC 0x00000002
-#define SDMC_ERR_END 0x00000004
-#define SDMC_ERR_TIMEOUT 0x00000008
-#define SDMC_ERR_FIFO_OVF 0x00000010
-#define SDMC_ERR_FIFO_UDF 0x00000020
-#define SDMC_ERR_WP 0x00000040
-#define SDMC_ERR_ABORT 0x00000080
-#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
-#define SDMC_ERR_PARAM 0x00000200
-#define SDMC_ERR_R1_STATUS 0x00000800
-#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
-#define SDMC_ERR_RESET 0x00002000
-#define SDMC_ERR_ILA 0x00004000
-#define SDMC_ERR_INFO_DETECT 0x00008000
-
-#define SDMC_STAT_ERR_UNKNOWN 0x00080000
-#define SDMC_STAT_ERR_CC 0x00100000
-#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
-#define SDMC_STAT_ERR_CRC 0x00800000
-#define SDMC_STAT_ERR_OTHER 0xf9c70008
-
-#define TMIO_MASK_ALL 0x837f031d
+#define TMIO_MASK_ALL 0x837F031D
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
@@ -103,7 +75,8 @@
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
typedef struct mmcdevice {
- vu8* data;
+ u8 *rData;
+ const u8 *tData;
u32 size;
u32 error;
u16 stat0;
@@ -118,11 +91,10 @@ typedef struct mmcdevice {
u32 res;
} mmcdevice;
-int sdmmc_sdcard_init();
-u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
-u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
-mmcdevice *getMMCDevice(int drive);
-int sdmmc_get_cid( int isNand, uint32_t *info);
-
-u32 sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
-u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
\ No newline at end of file
+void sdmmc_sdcard_init();
+int sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, u8 *out);
+int sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
+int sdmmc_nand_readsectors(u32 sector_no, u32 numsectors, u8 *out);
+int sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, const u8 *in);
+void sdmmc_get_cid(bool isNand, u32 *info);
+mmcdevice *getMMCDevice(int drive);
\ No newline at end of file
diff --git a/source/fs.c b/source/fs.c
index 84893ab..c615ecb 100644
--- a/source/fs.c
+++ b/source/fs.c
@@ -1,9 +1,28 @@
/*
-* fs.c
+* 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.
*/
#include "fs.h"
#include "memory.h"
+#include "strings.h"
#include "fatfs/ff.h"
static FATFS fs;
@@ -18,71 +37,92 @@ u32 mountCTRNAND(void)
return f_mount(&fs, "1:", 1) == FR_OK;
}
-u32 fileRead(void *dest, const char *path)
+u32 fileRead(void *dest, const char *path, u32 maxSize)
{
FIL file;
- u32 size;
+ u32 ret = 0;
if(f_open(&file, path, FA_READ) == FR_OK)
{
- unsigned int read;
- size = f_size(&file);
- f_read(&file, dest, size, &read);
+ u32 size = f_size(&file);
+ if(dest == NULL) ret = size;
+ else if(!(maxSize > 0 && size > maxSize))
+ f_read(&file, dest, size, (unsigned int *)&ret);
f_close(&file);
}
- else size = 0;
- return size;
+ return ret;
}
-void fileWrite(const void *buffer, const char *path, u32 size)
+bool fileWrite(const void *buffer, const char *path, u32 size)
{
FIL file;
- if(f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS) == FR_OK)
+ FRESULT result = f_open(&file, path, FA_WRITE | FA_OPEN_ALWAYS);
+
+ if(result == FR_OK)
{
unsigned int written;
f_write(&file, buffer, size, &written);
f_close(&file);
+
+ return true;
}
+
+ if(result == FR_NO_PATH)
+ {
+ for(u32 i = 1; path[i] != 0; i++)
+ if(path[i] == '/')
+ {
+ char folder[i + 1];
+ memcpy(folder, path, i);
+ folder[i] = 0;
+ f_mkdir(folder);
+ }
+
+ return fileWrite(buffer, path, size);
+ }
+
+ return false;
}
u32 firmRead(void *dest)
{
const char *firmFolders[] = { "00000002", "20000002" };
- char path[48] = "1:/title/00040138/00000000/content";
- memcpy(&path[18], firmFolders[console], 8);
+ char path[48] = "1:/title/00040138/";
+ concatenateStrings(path, firmFolders[isN3DS ? 1 : 0]);
+ concatenateStrings(path, "/content");
DIR dir;
FILINFO info;
f_opendir(&dir, path);
- u32 id = 0xFFFFFFFF,
+ u32 firmVersion = 0xFFFFFFFF,
ret = 0;
//Parse the target directory
- while(f_readdir(&dir, &info) == FR_OK && info.fname[0])
+ while(f_readdir(&dir, &info) == FR_OK && info.fname[0] != 0)
{
//Not a cxi
- if(info.altname[9] != 'A') continue;
+ if(info.fname[9] != 'a') continue;
//Multiple cxis were found
- if(id != 0xFFFFFFFF) ret = 1;
+ if(firmVersion != 0xFFFFFFFF) ret = 1;
//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';
}
//FIRM is equal or newer than 11.0
- if(tempId >= (console ? 0x21 : 0x52)) ret = 2;
+ if(tempVersion >= (isN3DS ? 0x21 : 0x52)) ret = 2;
//Found an older cxi
- if(tempId < id) id = tempId;
+ if(tempVersion < firmVersion) firmVersion = tempVersion;
}
f_closedir(&dir);
@@ -90,20 +130,12 @@ u32 firmRead(void *dest)
if(!ret)
{
//Complete the string with the .app name
- memcpy(&path[34], "/00000000.app", 14);
-
- //Last digit of the .app
- u32 i = 42;
+ concatenateStrings(path, "/00000000.app");
//Convert back the .app name from integer to array
- while(id)
- {
- static const char hexDigits[] = "0123456789ABCDEF";
- path[i--] = hexDigits[id & 0xF];
- id >>= 4;
- }
+ hexItoa(firmVersion, &path[35], 8);
- fileRead(dest, path);
+ fileRead(dest, path, 0);
}
return ret;
diff --git a/source/fs.h b/source/fs.h
index a7b63a5..3717057 100644
--- a/source/fs.h
+++ b/source/fs.h
@@ -1,15 +1,33 @@
/*
-* fs.h
+* 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.
*/
#pragma once
#include "types.h"
-extern u32 console;
+extern bool isN3DS;
u32 mountSD(void);
u32 mountCTRNAND(void);
-u32 fileRead(void *dest, const char *path);
-void fileWrite(const void *buffer, const char *path, u32 size);
+u32 fileRead(void *dest, const char *path, u32 maxSize);
+bool fileWrite(const void *buffer, const char *path, u32 size);
u32 firmRead(void *dest);
\ No newline at end of file
diff --git a/source/i2c.c b/source/i2c.c
index 6f03579..103bd9d 100644
--- a/source/i2c.c
+++ b/source/i2c.c
@@ -10,50 +10,58 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
};
-static inline u8 i2cGetDeviceBusId(u8 device_id) {
+static inline u8 i2cGetDeviceBusId(u8 device_id)
+{
return dev_data[device_id].bus_id;
}
-static inline u8 i2cGetDeviceRegAddr(u8 device_id) {
+static inline u8 i2cGetDeviceRegAddr(u8 device_id)
+{
return dev_data[device_id].reg_addr;
}
//-----------------------------------------------------------------------------
-static vu8* reg_data_addrs[] = {
- (vu8*)(I2C1_REG_OFF + I2C_REG_DATA),
- (vu8*)(I2C2_REG_OFF + I2C_REG_DATA),
- (vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
+static vu8 *reg_data_addrs[] = {
+ (vu8 *)(I2C1_REG_OFF + I2C_REG_DATA),
+ (vu8 *)(I2C2_REG_OFF + I2C_REG_DATA),
+ (vu8 *)(I2C3_REG_OFF + I2C_REG_DATA),
};
-static inline vu8* i2cGetDataReg(u8 bus_id) {
+static inline vu8 *i2cGetDataReg(u8 bus_id)
+{
return reg_data_addrs[bus_id];
}
//-----------------------------------------------------------------------------
-static vu8* reg_cnt_addrs[] = {
- (vu8*)(I2C1_REG_OFF + I2C_REG_CNT),
- (vu8*)(I2C2_REG_OFF + I2C_REG_CNT),
- (vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
+static vu8 *reg_cnt_addrs[] = {
+ (vu8 *)(I2C1_REG_OFF + I2C_REG_CNT),
+ (vu8 *)(I2C2_REG_OFF + I2C_REG_CNT),
+ (vu8 *)(I2C3_REG_OFF + I2C_REG_CNT),
};
-static inline vu8* i2cGetCntReg(u8 bus_id) {
+static inline vu8 *i2cGetCntReg(u8 bus_id)
+{
return reg_cnt_addrs[bus_id];
}
//-----------------------------------------------------------------------------
-static inline void i2cWaitBusy(u8 bus_id) {
+static inline void i2cWaitBusy(u8 bus_id)
+{
while (*i2cGetCntReg(bus_id) & 0x80);
}
-static inline u32 i2cGetResult(u8 bus_id) {
+static inline bool i2cGetResult(u8 bus_id)
+{
i2cWaitBusy(bus_id);
+
return (*i2cGetCntReg(bus_id) >> 4) & 1;
}
-static void i2cStop(u8 bus_id, u8 arg0) {
+static void i2cStop(u8 bus_id, u8 arg0)
+{
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
@@ -61,38 +69,45 @@ static void i2cStop(u8 bus_id, u8 arg0) {
//-----------------------------------------------------------------------------
-static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) {
+static bool i2cSelectDevice(u8 bus_id, u8 dev_reg)
+{
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2;
+
return i2cGetResult(bus_id);
}
-static u32 i2cSelectRegister(u8 bus_id, u8 reg) {
+static bool i2cSelectRegister(u8 bus_id, u8 reg)
+{
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0;
+
return i2cGetResult(bus_id);
}
//-----------------------------------------------------------------------------
-u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
- u8 bus_id = i2cGetDeviceBusId(dev_id);
- u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
+bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
+{
+ u8 bus_id = i2cGetDeviceBusId(dev_id),
+ dev_addr = i2cGetDeviceRegAddr(dev_id);
- for (int i = 0; i < 8; i++) {
- if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
+ for(u32 i = 0; i < 8; i++)
+ {
+ if(i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
+ {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0);
- if (i2cGetResult(bus_id))
- return 1;
+
+ if(i2cGetResult(bus_id)) return true;
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
- return 0;
-}
+ return false;
+}
\ No newline at end of file
diff --git a/source/i2c.h b/source/i2c.h
index 00658ea..07554f7 100644
--- a/source/i2c.h
+++ b/source/i2c.h
@@ -15,4 +15,4 @@
#define I2C_DEV_GYRO 10
#define I2C_DEV_IR 13
-u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
\ No newline at end of file
+bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
\ No newline at end of file
diff --git a/source/installer.c b/source/installer.c
index d0b8c0e..6b44a4e 100755
--- a/source/installer.c
+++ b/source/installer.c
@@ -6,7 +6,7 @@
#include "memory.h"
#include "fs.h"
#include "crypto.h"
-#include "screeninit.h"
+#include "screen.h"
#include "draw.h"
#include "utils.h"
#include "fatfs/sdmmc/sdmmc.h"
@@ -31,9 +31,8 @@ static const u8 firm1Hash[0x20] = {
0x2D, 0x3D, 0x56, 0x6C, 0x6A, 0x1A, 0x8E, 0x52, 0x54, 0xE3, 0x89, 0xC2, 0x95, 0x06, 0x23, 0xE5
};
-int posY;
-
-u32 console;
+u32 posY;
+bool isN3DS;
void main(void)
{
@@ -41,54 +40,54 @@ void main(void)
sdmmc_sdcard_init();
//Determine if booting with A9LH
- u32 a9lhBoot = !PDN_SPI_CNT;
+ bool isA9lh = !PDN_SPI_CNT;
+
//Detect the console being used
- console = PDN_MPCORE_CFG == 7;
+ isN3DS = PDN_MPCORE_CFG == 7;
drawString(TITLE, 10, 10, COLOR_TITLE);
posY = drawString("Thanks to delebile, #cakey and StandardBus", 10, 40, COLOR_WHITE);
- posY = drawString(a9lhBoot ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE);
+ posY = drawString(isA9lh ? "Press SELECT to update A9LH, START to uninstall" : "Press SELECT for a full install", 10, posY + SPACING_Y, COLOR_WHITE);
posY = drawString("Press any other button to shutdown", 10, posY, COLOR_WHITE);
u32 pressed = waitInput();
- if(pressed == BUTTON_SELECT) installer(a9lhBoot);
- if(pressed == BUTTON_START && a9lhBoot) uninstaller();
+
+ if(pressed == BUTTON_SELECT) installer(isA9lh);
+ if(pressed == BUTTON_START && isA9lh) uninstaller();
shutdown(0, NULL);
}
-static inline void installer(u32 a9lhBoot)
+static inline void installer(bool isA9lh)
{
if(!mountSD())
shutdown(1, "Error: failed to mount the SD card");
- const char *path;
- u32 updatea9lh = 0;
+ bool updateA9lh = false;
//If making a first install, we need the OTP
- if(!a9lhBoot)
+ if(!isA9lh)
{
- // Prefer OTP from memory if available
+ const char otpPath[] = "a9lh/otp.bin";
const u8 zeroes[256] = {0};
- path = "a9lh/otp.bin";
+
+ //Prefer OTP from memory if available
if(memcmp((void *)OTP_FROM_MEM, zeroes, 256) == 0)
{
// Read OTP from file
- if(fileRead((void *)OTP_OFFSET, path) != 256)
- {
- shutdown(1, "Error: otp.bin doesn't exist and can't be dumped");
- }
+ if(!fileRead((void *)OTP_OFFSET, otpPath, 256))
+ shutdown(1, "Error: otp.bin doesn't exist and can't be dumped");
}
else
{
- // Write OTP from memory to file
- fileWrite((void *)OTP_FROM_MEM, path, 256);
+ //Write OTP from memory to file
+ fileWrite((void *)OTP_FROM_MEM, otpPath, 256);
memcpy((void *)OTP_OFFSET, (void *)OTP_FROM_MEM, 256);
}
}
//Setup the key sector de/encryption with the SHA register or otp.bin
- setupKeyslot0x11(a9lhBoot, (void *)OTP_OFFSET);
+ setupKeyslot0x11(isA9lh, (void *)OTP_OFFSET);
//Calculate the CTR for the 3DS partitions
getNandCTR();
@@ -99,7 +98,7 @@ static inline void installer(u32 a9lhBoot)
shutdown(1, "Error: failed to setup FIRM encryption");
//If booting from A9LH or on N3DS, we can use the key sector from NAND
- if(a9lhBoot || console)
+ if(isA9lh || isN3DS)
{
getSector((u8 *)SECTOR_OFFSET);
@@ -107,28 +106,26 @@ static inline void installer(u32 a9lhBoot)
for(i = 0; i < 3; i++)
if(memcmp((void *)(SECTOR_OFFSET + 0x10), key2s[i], 0x10) == 0) break;
- if(i == 3) shutdown(1, a9lhBoot ? "Error: the OTP hash or the NAND key sector\nare invalid" :
+ if(i == 3) shutdown(1, isA9lh ? "Error: the OTP hash or the NAND key sector\nare invalid" :
"Error: the otp.bin or the NAND key sector\nare invalid");
- else if(i == 1) updatea9lh = 1;
+ else if(i == 1) updateA9lh = true;
}
else
{
//Read decrypted key sector
- path = "a9lh/secret_sector.bin";
- if(fileRead((void *)SECTOR_OFFSET, path) != 0x200)
+ if(!fileRead((void *)SECTOR_OFFSET, "a9lh/secret_sector.bin", 0x200))
shutdown(1, "Error: secret_sector.bin doesn't exist or has\na wrong size");
if(!verifyHash((void *)SECTOR_OFFSET, 0x200, sectorHash))
shutdown(1, "Error: secret_sector.bin is invalid or corrupted");
}
- if(!a9lhBoot || updatea9lh)
+ if(!isA9lh || updateA9lh)
{
//Generate and encrypt a per-console A9LH key sector
generateSector((u8 *)SECTOR_OFFSET, 0);
//Read FIRM0
- path = "a9lh/firm0.bin";
- if(fileRead((void *)FIRM0_OFFSET, path) != FIRM0_SIZE)
+ if(!fileRead((void *)FIRM0_OFFSET, "a9lh/firm0.bin", FIRM0_SIZE))
shutdown(1, "Error: firm0.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM0_OFFSET, FIRM0_SIZE, firm0Hash))
@@ -137,11 +134,10 @@ static inline void installer(u32 a9lhBoot)
else if(!verifyHash((void *)FIRM0_OFFSET, SECTION2_POSITION, firm0A9lhHash))
shutdown(1, "Error: NAND FIRM0 is invalid");
- if(!a9lhBoot)
+ if(!isA9lh)
{
//Read FIRM1
- path = "a9lh/firm1.bin";
- if(fileRead((void *)FIRM1_OFFSET, path) != FIRM1_SIZE)
+ if(!fileRead((void *)FIRM1_OFFSET, "a9lh/firm1.bin", FIRM1_SIZE))
shutdown(1, "Error: firm1.bin doesn't exist or has a wrong size");
if(!verifyHash((void *)FIRM1_OFFSET, FIRM1_SIZE, firm1Hash))
@@ -150,9 +146,7 @@ static inline void installer(u32 a9lhBoot)
//Inject stage1
memset32((void *)STAGE1_OFFSET, 0, MAX_STAGE1_SIZE);
- path = "a9lh/payload_stage1.bin";
- u32 size = fileRead((void *)STAGE1_OFFSET, path);
- if(!size || size > MAX_STAGE1_SIZE)
+ if(!fileRead((void *)STAGE1_OFFSET, "a9lh/payload_stage1.bin", MAX_STAGE1_SIZE))
shutdown(1, "Error: payload_stage1.bin doesn't exist or\nexceeds max size");
const u8 zeroes[688] = {0};
@@ -161,20 +155,18 @@ static inline void installer(u32 a9lhBoot)
//Read stage2
memset32((void *)STAGE2_OFFSET, 0, MAX_STAGE2_SIZE);
- path = "a9lh/payload_stage2.bin";
- size = fileRead((void *)STAGE2_OFFSET, path);
- if(!size || size > MAX_STAGE2_SIZE)
+ if(!fileRead((void *)STAGE2_OFFSET, "a9lh/payload_stage2.bin", MAX_STAGE2_SIZE))
shutdown(1, "Error: payload_stage2.bin doesn't exist or\nexceeds max size");
posY = drawString("All checks passed, installing...", 10, posY + SPACING_Y, COLOR_WHITE);
//Point of no return, install stuff in the safest order
- sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (vu8 *)STAGE2_OFFSET);
- if(!a9lhBoot) writeFirm((u8 *)FIRM1_OFFSET, 1, FIRM1_SIZE);
- if(!a9lhBoot || updatea9lh) sdmmc_nand_writesectors(0x96, 1, (vu8 *)SECTOR_OFFSET);
- writeFirm((u8 *)FIRM0_OFFSET, 0, FIRM0_SIZE);
+ sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (u8 *)STAGE2_OFFSET);
+ if(!isA9lh) writeFirm((u8 *)FIRM1_OFFSET, true, FIRM1_SIZE);
+ if(!isA9lh || updateA9lh) sdmmc_nand_writesectors(0x96, 1, (u8 *)SECTOR_OFFSET);
+ writeFirm((u8 *)FIRM0_OFFSET, false, FIRM0_SIZE);
- shutdown(2, a9lhBoot ? "Update: success!" : "Full install: success!");
+ shutdown(2, isA9lh ? "Update: success!" : "Full install: success!");
}
static inline void uninstaller(void)
@@ -194,7 +186,7 @@ static inline void uninstaller(void)
}
//New 3DSes need a key sector with a proper key2, Old 3DSes have a blank key sector
- if(console)
+ if(isN3DS)
{
setupKeyslot0x11(1, NULL);
getSector((u8 *)SECTOR_OFFSET);
@@ -232,10 +224,10 @@ static inline void uninstaller(void)
posY = drawString("All checks passed, uninstalling...", 10, posY + SPACING_Y, COLOR_WHITE);
//Point of no return, install stuff in the safest order
- sdmmc_nand_writesectors(0x96, 1, (vu8 *)SECTOR_OFFSET);
- writeFirm((u8 *)FIRM0_OFFSET, 0, firmSize);
- writeFirm((u8 *)FIRM1_OFFSET, 1, firmSize);
- sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (vu8 *)STAGE2_OFFSET);
+ sdmmc_nand_writesectors(0x96, 1, (u8 *)SECTOR_OFFSET);
+ writeFirm((u8 *)FIRM0_OFFSET, false, firmSize);
+ writeFirm((u8 *)FIRM1_OFFSET, true, firmSize);
+ sdmmc_nand_writesectors(0x5C000, MAX_STAGE2_SIZE / 0x200, (u8 *)STAGE2_OFFSET);
shutdown(2, "Uninstall: success!");
-}
+}
\ No newline at end of file
diff --git a/source/installer.h b/source/installer.h
index d603633..b5d73d3 100644
--- a/source/installer.h
+++ b/source/installer.h
@@ -6,8 +6,8 @@
#include "types.h"
-#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC)
-#define PDN_SPI_CNT (*(vu8 *)0x101401C0)
+#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC)
+#define PDN_SPI_CNT (*(vu8 *)0x101401C0)
#define OTP_FROM_MEM 0x10012000
#define OTP_OFFSET 0x24000000
@@ -23,5 +23,5 @@
#define MAX_STAGE1_SIZE 0x1E70
#define MAX_STAGE2_SIZE 0x89A00
-static inline void installer(u32 a9lhBoot);
+static inline void installer(bool isA9lh);
static inline void uninstaller(void);
\ No newline at end of file
diff --git a/source/memory.c b/source/memory.c
index 4b6efd3..9f37af7 100644
--- a/source/memory.c
+++ b/source/memory.c
@@ -1,5 +1,7 @@
/*
* memory.c
+*
+* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#include "memory.h"
@@ -17,19 +19,19 @@ void memset32(void *dest, u32 filler, u32 size)
{
u32 *dest32 = (u32 *)dest;
- for (u32 i = 0; i < size / 4; i++)
+ for(u32 i = 0; i < size / 4; i++)
dest32[i] = filler;
}
int memcmp(const void *buf1, const void *buf2, u32 size)
{
- const u8 *buf1c = (const u8 *)buf1;
- const u8 *buf2c = (const u8 *)buf2;
+ const u8 *buf1c = (const u8 *)buf1,
+ *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i];
- if(cmp) return cmp;
+ if(cmp != 0) return cmp;
}
return 0;
diff --git a/source/memory.h b/source/memory.h
index 3dbef14..bc0004c 100644
--- a/source/memory.h
+++ b/source/memory.h
@@ -1,5 +1,7 @@
/*
* memory.h
+*
+* memcpy, memset32 and memcmp adapted from https://github.com/mid-kid/CakesForeveryWan/blob/557a8e8605ab3ee173af6497486e8f22c261d0e2/source/memfuncs.c
*/
#pragma once
diff --git a/source/screen.c b/source/screen.c
new file mode 100644
index 0000000..bcf3384
--- /dev/null
+++ b/source/screen.c
@@ -0,0 +1,209 @@
+/*
+* 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.
+*/
+
+/*
+* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
+*/
+
+/*
+* About cache coherency:
+*
+* Flushing the data cache for all memory regions read from/written to by both processors is mandatory on the ARM9 processor.
+* Thus, we make sure there'll be a cache miss on the ARM9 next time it's read.
+* Otherwise the ARM9 won't see the changes made and things will break.
+*
+* On the ARM11, in the environment we're in, the MMU isn't enabled and nothing is cached.
+*/
+
+#include "screen.h"
+#include "draw.h"
+#include "cache.h"
+#include "i2c.h"
+
+vu32 *const arm11Entry = (vu32 *)BRAHMA_ARM11_ENTRY;
+
+static void invokeArm11Function(void (*func)())
+{
+ *arm11Entry = (u32)func;
+ while(*arm11Entry);
+}
+
+void clearScreens(void)
+{
+ void __attribute__((naked)) ARM11(void)
+ {
+ //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 + SCREEN_TOP_FBSIZE) >> 3; //End address
+ REGs_PSC0[2] = 0; //Fill value
+ REGs_PSC0[3] = (2 << 8) | 1; //32-bit pattern; start
+
+ vu32 *REGs_PSC1 = (vu32 *)0x10400020;
+ REGs_PSC1[0] = (u32)fb->bottom >> 3; //Start address
+ REGs_PSC1[1] = (u32)(fb->bottom + SCREEN_BOTTOM_FBSIZE) >> 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)
+ {
+ REGs_PSC0[0] = (u32)fb->top_right >> 3; //Start address
+ REGs_PSC0[1] = (u32)(fb->top_right + SCREEN_TOP_FBSIZE) >> 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();
+ }
+
+ invokeArm11Function(ARM11);
+}
+
+void initScreens(void)
+{
+ void __attribute__((naked)) initSequence(void)
+ {
+ //Disable interrupts
+ __asm(".word 0xF10C01C0");
+
+ *(vu32 *)0x10141200 = 0x1007F;
+ *(vu32 *)0x10202014 = 0x00000001;
+ *(vu32 *)0x1020200C &= 0xFFFEFFFE;
+ *(vu32 *)0x10202240 = 0x45;
+ *(vu32 *)0x10202A40 = 0x45;
+ *(vu32 *)0x10202244 = 0x1023E;
+ *(vu32 *)0x10202A44 = 0x1023E;
+
+ //Top screen
+ *(vu32 *)0x10400400 = 0x000001c2;
+ *(vu32 *)0x10400404 = 0x000000d1;
+ *(vu32 *)0x10400408 = 0x000001c1;
+ *(vu32 *)0x1040040c = 0x000001c1;
+ *(vu32 *)0x10400410 = 0x00000000;
+ *(vu32 *)0x10400414 = 0x000000cf;
+ *(vu32 *)0x10400418 = 0x000000d1;
+ *(vu32 *)0x1040041c = 0x01c501c1;
+ *(vu32 *)0x10400420 = 0x00010000;
+ *(vu32 *)0x10400424 = 0x0000019d;
+ *(vu32 *)0x10400428 = 0x00000002;
+ *(vu32 *)0x1040042c = 0x00000192;
+ *(vu32 *)0x10400430 = 0x00000192;
+ *(vu32 *)0x10400434 = 0x00000192;
+ *(vu32 *)0x10400438 = 0x00000001;
+ *(vu32 *)0x1040043c = 0x00000002;
+ *(vu32 *)0x10400440 = 0x01960192;
+ *(vu32 *)0x10400444 = 0x00000000;
+ *(vu32 *)0x10400448 = 0x00000000;
+ *(vu32 *)0x1040045C = 0x00f00190;
+ *(vu32 *)0x10400460 = 0x01c100d1;
+ *(vu32 *)0x10400464 = 0x01920002;
+ *(vu32 *)0x10400468 = 0x18300000;
+ *(vu32 *)0x10400470 = 0x80341;
+ *(vu32 *)0x10400474 = 0x00010501;
+ *(vu32 *)0x10400478 = 0;
+ *(vu32 *)0x10400490 = 0x000002D0;
+ *(vu32 *)0x1040049C = 0x00000000;
+
+ //Disco register
+ for(u32 i = 0; i < 256; i++)
+ *(vu32 *)0x10400484 = 0x10101 * i;
+
+ //Bottom screen
+ *(vu32 *)0x10400500 = 0x000001c2;
+ *(vu32 *)0x10400504 = 0x000000d1;
+ *(vu32 *)0x10400508 = 0x000001c1;
+ *(vu32 *)0x1040050c = 0x000001c1;
+ *(vu32 *)0x10400510 = 0x000000cd;
+ *(vu32 *)0x10400514 = 0x000000cf;
+ *(vu32 *)0x10400518 = 0x000000d1;
+ *(vu32 *)0x1040051c = 0x01c501c1;
+ *(vu32 *)0x10400520 = 0x00010000;
+ *(vu32 *)0x10400524 = 0x0000019d;
+ *(vu32 *)0x10400528 = 0x00000052;
+ *(vu32 *)0x1040052c = 0x00000192;
+ *(vu32 *)0x10400530 = 0x00000192;
+ *(vu32 *)0x10400534 = 0x0000004f;
+ *(vu32 *)0x10400538 = 0x00000050;
+ *(vu32 *)0x1040053c = 0x00000052;
+ *(vu32 *)0x10400540 = 0x01980194;
+ *(vu32 *)0x10400544 = 0x00000000;
+ *(vu32 *)0x10400548 = 0x00000011;
+ *(vu32 *)0x1040055C = 0x00f00140;
+ *(vu32 *)0x10400560 = 0x01c100d1;
+ *(vu32 *)0x10400564 = 0x01920052;
+ *(vu32 *)0x10400568 = 0x18300000 + 0x46500;
+ *(vu32 *)0x10400570 = 0x80301;
+ *(vu32 *)0x10400574 = 0x00010501;
+ *(vu32 *)0x10400578 = 0;
+ *(vu32 *)0x10400590 = 0x000002D0;
+ *(vu32 *)0x1040059C = 0x00000000;
+
+ //Disco register
+ for(u32 i = 0; i < 256; i++)
+ *(vu32 *)0x10400584 = 0x10101 * i;
+
+ WAIT_FOR_ARM9();
+ }
+
+ //Set CakeBrah framebuffers
+ void __attribute__((naked)) setupFramebuffers(void)
+ {
+ //Disable interrupts
+ __asm(".word 0xF10C01C0");
+
+ fb->top_left = (u8 *)0x18300000;
+ fb->top_right = (u8 *)0x18300000;
+ fb->bottom = (u8 *)0x18346500;
+
+ *(vu32 *)0x10400468 = (u32)fb->top_left;
+ *(vu32 *)0x1040046c = (u32)fb->top_left;
+ *(vu32 *)0x10400494 = (u32)fb->top_right;
+ *(vu32 *)0x10400498 = (u32)fb->top_right;
+ *(vu32 *)0x10400568 = (u32)fb->bottom;
+ *(vu32 *)0x1040056c = (u32)fb->bottom;
+
+ WAIT_FOR_ARM9();
+ }
+
+ static bool needToSetup = true;
+
+ if(needToSetup)
+ {
+ if(PDN_GPU_CNT == 1)
+ {
+ invokeArm11Function(initSequence);
+
+ //Turn on backlight
+ i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
+ }
+
+ flushDCacheRange((void *)fb, sizeof(struct fb));
+ invokeArm11Function(setupFramebuffers);
+ needToSetup = false;
+ }
+
+ clearScreens();
+}
\ No newline at end of file
diff --git a/source/screen.h b/source/screen.h
new file mode 100644
index 0000000..ce8da5f
--- /dev/null
+++ b/source/screen.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.
+*/
+
+/*
+* Screen init code by dark_samus, bil1s, Normmatt, delebile and others
+*/
+
+#pragma once
+
+#include "types.h"
+
+#define PDN_GPU_CNT (*(vu8 *)0x10141200)
+
+#define BRAHMA_ARM11_ENTRY 0x1FFFFFF8
+#define WAIT_FOR_ARM9() *arm11Entry = 0; while(!*arm11Entry); ((void (*)())*arm11Entry)();
+
+#define SCREEN_TOP_WIDTH 400
+#define SCREEN_BOTTOM_WIDTH 320
+#define SCREEN_HEIGHT 240
+#define SCREEN_TOP_FBSIZE (3 * SCREEN_TOP_WIDTH * SCREEN_HEIGHT)
+#define SCREEN_BOTTOM_FBSIZE (3 * SCREEN_BOTTOM_WIDTH * SCREEN_HEIGHT)
+
+static struct fb {
+ u8 *top_left;
+ u8 *top_right;
+ u8 *bottom;
+} *const fb = (struct fb *)0x23FFFE00;
+
+void clearScreens(void);
+void initScreens(void);
\ No newline at end of file
diff --git a/source/screeninit.c b/source/screeninit.c
deleted file mode 100644
index e1f247a..0000000
--- a/source/screeninit.c
+++ /dev/null
@@ -1,122 +0,0 @@
-/*
-* screeninit.c
-*
-* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
-*/
-
-#include "screeninit.h"
-#include "draw.h"
-#include "i2c.h"
-
-void initScreens(void)
-{
- vu32 *const arm11 = (u32 *)0x1FFFFFF8;
-
- void __attribute__((naked)) ARM11(void)
- {
- __asm(".word 0xF10C01C0");
- *(vu32 *)0x10141200 = 0x1007F;
- *(vu32 *)0x10202014 = 0x00000001;
- *(vu32 *)0x1020200C &= 0xFFFEFFFE;
- *(vu32 *)0x10202240 = 0x45;
- *(vu32 *)0x10202A40 = 0x45;
- *(vu32 *)0x10202244 = 0x1023E;
- *(vu32 *)0x10202A44 = 0x1023E;
-
- // Top screen
- *(vu32 *)0x10400400 = 0x000001c2;
- *(vu32 *)0x10400404 = 0x000000d1;
- *(vu32 *)0x10400408 = 0x000001c1;
- *(vu32 *)0x1040040c = 0x000001c1;
- *(vu32 *)0x10400410 = 0x00000000;
- *(vu32 *)0x10400414 = 0x000000cf;
- *(vu32 *)0x10400418 = 0x000000d1;
- *(vu32 *)0x1040041c = 0x01c501c1;
- *(vu32 *)0x10400420 = 0x00010000;
- *(vu32 *)0x10400424 = 0x0000019d;
- *(vu32 *)0x10400428 = 0x00000002;
- *(vu32 *)0x1040042c = 0x00000192;
- *(vu32 *)0x10400430 = 0x00000192;
- *(vu32 *)0x10400434 = 0x00000192;
- *(vu32 *)0x10400438 = 0x00000001;
- *(vu32 *)0x1040043c = 0x00000002;
- *(vu32 *)0x10400440 = 0x01960192;
- *(vu32 *)0x10400444 = 0x00000000;
- *(vu32 *)0x10400448 = 0x00000000;
- *(vu32 *)0x1040045C = 0x00f00190;
- *(vu32 *)0x10400460 = 0x01c100d1;
- *(vu32 *)0x10400464 = 0x01920002;
- *(vu32 *)0x10400468 = 0x18300000;
- *(vu32 *)0x10400470 = 0x80341;
- *(vu32 *)0x10400474 = 0x00010501;
- *(vu32 *)0x10400478 = 0;
- *(vu32 *)0x10400490 = 0x000002D0;
- *(vu32 *)0x1040049C = 0x00000000;
-
- // Disco register
- for(vu32 i = 0; i < 256; i++)
- *(vu32 *)0x10400484 = 0x10101 * i;
-
- // Bottom screen
- *(vu32 *)0x10400500 = 0x000001c2;
- *(vu32 *)0x10400504 = 0x000000d1;
- *(vu32 *)0x10400508 = 0x000001c1;
- *(vu32 *)0x1040050c = 0x000001c1;
- *(vu32 *)0x10400510 = 0x000000cd;
- *(vu32 *)0x10400514 = 0x000000cf;
- *(vu32 *)0x10400518 = 0x000000d1;
- *(vu32 *)0x1040051c = 0x01c501c1;
- *(vu32 *)0x10400520 = 0x00010000;
- *(vu32 *)0x10400524 = 0x0000019d;
- *(vu32 *)0x10400528 = 0x00000052;
- *(vu32 *)0x1040052c = 0x00000192;
- *(vu32 *)0x10400530 = 0x00000192;
- *(vu32 *)0x10400534 = 0x0000004f;
- *(vu32 *)0x10400538 = 0x00000050;
- *(vu32 *)0x1040053c = 0x00000052;
- *(vu32 *)0x10400540 = 0x01980194;
- *(vu32 *)0x10400544 = 0x00000000;
- *(vu32 *)0x10400548 = 0x00000011;
- *(vu32 *)0x1040055C = 0x00f00140;
- *(vu32 *)0x10400560 = 0x01c100d1;
- *(vu32 *)0x10400564 = 0x01920052;
- *(vu32 *)0x10400568 = 0x18300000 + 0x46500;
- *(vu32 *)0x10400570 = 0x80301;
- *(vu32 *)0x10400574 = 0x00010501;
- *(vu32 *)0x10400578 = 0;
- *(vu32 *)0x10400590 = 0x000002D0;
- *(vu32 *)0x1040059C = 0x00000000;
-
- // Disco register
- for(vu32 i = 0; i < 256; i++)
- *(vu32 *)0x10400584 = 0x10101 * i;
-
- // Enable backlight
- i2cWriteRegister(I2C_DEV_MCU, 0x22, 0x2A);
-
- *(vu32 *)0x10400468 = 0x18300000;
- *(vu32 *)0x1040046c = 0x18300000;
- *(vu32 *)0x10400494 = 0x18300000;
- *(vu32 *)0x10400498 = 0x18300000;
- *(vu32 *)0x10400568 = 0x18346500;
- *(vu32 *)0x1040056c = 0x18346500;
-
- //Set CakeBrah framebuffers
- *((vu32 *)0x23FFFE00) = 0x18300000;
- *((vu32 *)0x23FFFE04) = 0x18300000;
- *((vu32 *)0x23FFFE08) = 0x18346500;
-
- //Clear ARM11 entry offset
- *arm11 = 0;
-
- while(1);
- }
-
- if(PDN_GPU_CNT == 1)
- {
- *arm11 = (u32)ARM11;
- while(*arm11);
- }
-
- clearScreens();
-}
\ No newline at end of file
diff --git a/source/screeninit.h b/source/screeninit.h
deleted file mode 100644
index 9c60ef3..0000000
--- a/source/screeninit.h
+++ /dev/null
@@ -1,13 +0,0 @@
-/*
-* screeninit.h
-*
-* Screen init code by dark_samus, bil1s, Normmatt, delebile and others.
-*/
-
-#pragma once
-
-#include "types.h"
-
-#define PDN_GPU_CNT (*(vu8 *)0x10141200)
-
-void initScreens(void);
\ No newline at end of file
diff --git a/source/start.s b/source/start.s
index 4c91264..13e747d 100644
--- a/source/start.s
+++ b/source/start.s
@@ -1,3 +1,25 @@
+@ 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.
+
+@ Thanks to the numerous people who took part in writing this file
+
.section .text.start
.align 4
.global _start
@@ -5,6 +27,11 @@ _start:
@ Change the stack pointer
mov sp, #0x27000000
+ @ Disable interrupts
+ mrs r0, cpsr
+ orr r0, #0x1C0
+ msr cpsr_cx, r0
+
@ Disable caches / MPU
mrc p15, 0, r0, c1, c0, 0 @ read control register
bic r0, #(1<<12) @ - instruction cache disable
@@ -12,21 +39,25 @@ _start:
bic r0, #(1<<0) @ - mpu disable
mcr p15, 0, r0, c1, c0, 0 @ write control register
+ @ Flush caches
+ bl flushEntireDCache
+ bl flushEntireICache
+
@ Give read/write access to all the memory regions
- ldr r0, =0x33333333
+ ldr r0, =0x3333333
mcr p15, 0, r0, c5, c0, 2 @ write data access
mcr p15, 0, r0, c5, c0, 3 @ write instruction access
@ Set MPU permissions and cache settings
- ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
- ldr r1, =0x3000801B @ fff00000 16k | dtcm
- ldr r2, =0x01FF801D @ 01ff8000 32k | itcm
- ldr r3, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
- ldr r4, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
- ldr r5, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
- ldr r6, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
- ldr r7, =0x1800002D @ 18000000 8M | vram (+ 2MB)
- mov r8, #0x29
+ ldr r0, =0xFFFF001D @ ffff0000 32k | bootrom (unprotected part)
+ ldr r1, =0x01FF801D @ 01ff8000 32k | itcm
+ ldr r2, =0x08000029 @ 08000000 2M | arm9 mem (O3DS / N3DS)
+ ldr r3, =0x10000029 @ 10000000 2M | io mem (ARM9 / first 2MB)
+ ldr r4, =0x20000037 @ 20000000 256M | fcram (O3DS / N3DS)
+ ldr r5, =0x1FF00027 @ 1FF00000 1M | dsp / axi wram
+ ldr r6, =0x1800002D @ 18000000 8M | vram (+ 2MB)
+ mov r7, #0
+ mov r8, #0x15
mcr p15, 0, r0, c6, c0, 0
mcr p15, 0, r1, c6, c1, 0
mcr p15, 0, r2, c6, c2, 0
@@ -35,23 +66,19 @@ _start:
mcr p15, 0, r5, c6, c5, 0
mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0
- mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 3, 5
- mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 3, 5
- mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 3, 5
+ mcr p15, 0, r8, c3, c0, 0 @ Write bufferable 0, 2, 4
+ mcr p15, 0, r8, c2, c0, 0 @ Data cacheable 0, 2, 4
+ mcr p15, 0, r8, c2, c0, 1 @ Inst cacheable 0, 2, 4
- @ Enable caches / MPU
+ @ Enable caches / MPU / ITCM
mrc p15, 0, r0, c1, c0, 0 @ read control register
+ orr r0, r0, #(1<<18) @ - ITCM enable
+ orr r0, r0, #(1<<13) @ - alternate exception vectors enable
orr r0, r0, #(1<<12) @ - instruction cache enable
orr r0, r0, #(1<<2) @ - data cache enable
orr r0, r0, #(1<<0) @ - mpu enable
mcr p15, 0, r0, c1, c0, 0 @ write control register
- @ Flush caches
- mov r0, #0
- mcr p15, 0, r0, c7, c5, 0 @ flush I-cache
- mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
- mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
-
@ Fix mounting of SDMC
ldr r0, =0x10000020
mov r1, #0x340
diff --git a/source/strings.c b/source/strings.c
new file mode 100644
index 0000000..55fee26
--- /dev/null
+++ b/source/strings.c
@@ -0,0 +1,55 @@
+/*
+* 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.
+*/
+
+#include "strings.h"
+#include "memory.h"
+
+u32 strlen(const char *string)
+{
+ char *stringEnd = (char *)string;
+
+ while(*stringEnd) stringEnd++;
+
+ return stringEnd - string;
+}
+
+void concatenateStrings(char *destination, const char *source)
+{
+ u32 i = strlen(source),
+ j = strlen(destination);
+
+ memcpy(&destination[j], source, i + 1);
+}
+
+void hexItoa(u32 number, char *out, u32 digits)
+{
+ const char hexDigits[] = "0123456789ABCDEF";
+ u32 i = 0;
+
+ while(number > 0)
+ {
+ out[digits - 1 - i++] = hexDigits[number & 0xF];
+ number >>= 4;
+ }
+
+ while(i < digits) out[digits - 1 - i++] = '0';
+}
\ No newline at end of file
diff --git a/source/strings.h b/source/strings.h
new file mode 100644
index 0000000..fc40e19
--- /dev/null
+++ b/source/strings.h
@@ -0,0 +1,29 @@
+/*
+* 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.
+*/
+
+#pragma once
+
+#include "types.h"
+
+u32 strlen(const char *string);
+void concatenateStrings(char *destination, const char *source);
+void hexItoa(u32 number, char *out, u32 digits);
\ No newline at end of file
diff --git a/source/types.h b/source/types.h
index 7caf623..bce6f07 100644
--- a/source/types.h
+++ b/source/types.h
@@ -6,6 +6,7 @@
#include
#include
+#include
//Common data types
typedef uint8_t u8;
diff --git a/source/utils.c b/source/utils.c
index 84cbb45..4e1891d 100755
--- a/source/utils.c
+++ b/source/utils.c
@@ -4,12 +4,14 @@
#include "utils.h"
#include "draw.h"
+#include "screen.h"
+#include "cache.h"
#include "i2c.h"
u32 waitInput(void)
{
- u32 pressedKey = 0,
- key;
+ bool pressedKey = false;
+ u32 key;
//Wait for no keys to be pressed
while(HID_PAD);
@@ -22,10 +24,10 @@ u32 waitInput(void)
key = HID_PAD;
//Make sure it's pressed
- for(u32 i = 0x13000; i; i--)
+ for(u32 i = 0x13000; i > 0; i--)
{
if(key != HID_PAD) break;
- if(i == 1) pressedKey = 1;
+ if(i == 1) pressedKey = true;
}
}
while(!pressedKey);
@@ -41,6 +43,9 @@ void shutdown(u32 mode, const char *message)
drawString("Press any button to shutdown", 10, posY, COLOR_WHITE);
waitInput();
}
- i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
- while(1);
+
+ if(PDN_GPU_CNT != 1) clearScreens();
+ flushEntireDCache();
+ i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
+ while(true);
}
\ No newline at end of file
diff --git a/source/utils.h b/source/utils.h
index fcee33a..e519de3 100644
--- a/source/utils.h
+++ b/source/utils.h
@@ -21,7 +21,7 @@
#define COLOR_RED 0x0000FF
#define COLOR_GREEN 0x00FF00
-extern int posY;
+extern u32 posY;
u32 waitInput(void);
void shutdown(u32 mode, const char *message);
\ No newline at end of file