Compare commits

...

70 Commits
v4.0 ... v5.1.1

Author SHA1 Message Date
Aurora
a11124a3d6 Remove LFN support from the loader FatFs as it is not used. Slims down the binary by ~4 KBs 2016-04-18 04:47:53 +02:00
Aurora
d2d6e786c7 Fixed L+SELECT payload being broken (annoying LFN to 8.3 conversion rules). Now the payload is sel_NAME.bin 2016-04-18 02:55:54 +02:00
Aurora
a76c943c01 Reinstated the L+SELECT payload 2016-04-17 19:35:29 +02:00
Aurora
3c64a3a234 Updated ReadME 2016-04-17 19:11:38 +02:00
Aurora
06060c67b5 Changed the chainloader to load payloads named "BUTTON_NAME.bin", to remember which payload is which. Original idea and code by @habbbe (many thanks!) 2016-04-17 18:57:25 +02:00
Aurora
0f64fd73ec Fix bug when quitting AGB_FIRM
The wrong config.bin section was used to remember the last-used FIRM
2016-04-16 20:27:52 +02:00
Aurora
2323528975 Merge pull request #29 from habbbe/master
Made define for payload paths (removes repeated parts of file paths t…
2016-04-16 18:39:22 +02:00
habbbe
22b38a0f88 Made define for payload paths (removes repeated parts of file paths to payloads) 2016-04-16 18:21:42 +02:00
Aurora
034c0f8d7c Updated ReadME 2016-04-15 19:46:25 +02:00
Aurora
b4cd67cb8c Merge pull request #24 from ericchu94/master
Fix buffer overflow due to null character
2016-04-15 19:32:10 +02:00
Eric Chu
be83d77187 Fix buffer overflow due to null character 2016-04-15 12:54:30 -04:00
Aurora
615cf81a9f Further compatibility fix for language/region emulation, now works with games like Kirby Triple Deluxe 2016-04-15 17:54:45 +02:00
Aurora
c60ef7fe82 Better to reboot here 2016-04-15 16:10:32 +02:00
Aurora
fea5a111a9 Misc fixes, renamed "Updated SysNAND" to reflect what the option actually does now 2016-04-15 16:01:44 +02:00
Aurora
7eebfd4f6a Added improved language emulation from @TuxSH (improves compatibility), fixed language emulation only working for the first launched game/app and not being applied on demos 2016-04-15 03:34:08 +02:00
Aurora
939965b5a0 Cleanup 2016-04-14 17:10:55 +02:00
Aurora
a0334120a6 Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:59:14 +02:00
Aurora
308417a48e Added region/language emulation feature, thanks to the hard work of @TuxSH
Create a "locales" folder inside aurei, and one .txt for each game, with the title id of the game. The txt must be exactly 6 bytes long: 3 characters for the region ("JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"), a space, and two for the language ("JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"). You can enable the feature globally in the config menu. This should also make DLCs for foreign games work.
2016-04-14 00:56:34 +02:00
Aurora
85533411c9 Config menu cleanup 2016-04-13 15:29:44 +02:00
Aurora
6d4a84a325 Remove unneeded stuff from the loader injection 2016-04-13 14:37:40 +02:00
Aurora
89350b1edd Fixed config.bin getting recreated on each boot 2016-04-13 04:18:59 +02:00
Aurora
9e58e4ed7a Screwed up the order of the CPU settings 2016-04-13 00:36:35 +02:00
Aurora
f8f4ecea27 Add better code to the FIRM finding function to convert from integer to its hex representation array 2016-04-13 00:20:28 +02:00
Aurora
e9449f86bf Rewrote config menu to allow for multiple choice settings, made the N3DS CPU patch configurable in the NTR way, changed the config.bin format to be more future-proof (settings are on the leftmost part), added more macros to read settings 2016-04-12 23:28:35 +02:00
Aurora
4fabe1f704 Added new and working N3DS CPU patch from @TuxSH 2016-04-12 15:25:36 +02:00
Aurora
ef3ba896d5 Cleanup, removed the non-working clock speed patch 2016-04-12 14:32:38 +02:00
Aurora
649b160292 Use better makefiles for loader and the screen init stub 2016-04-12 04:55:36 +02:00
Aurora
697bc74535 Added tentative N3DS clock speed/L2 cache patch by @TuxSH. 2016-04-12 01:22:42 +02:00
Aurora
0e9ff44746 Made N3DS >9.6 key generation version independent 2016-04-11 22:26:39 +02:00
Aurora
49d49e637a Merge pull request #20 from Steveice10/master
Add developer UNITINFO patch.
2016-04-11 21:17:22 +02:00
Steven Smith
b3f0d13aa4 Add developer UNITINFO patch. 2016-04-11 12:14:51 -07:00
Aurora
bd1547710e Derp 2016-04-11 18:43:51 +02:00
Aurora
7479bf8092 Fixed possible issue with the injector 2016-04-11 18:08:22 +02:00
Aurora
d4d281bb9c Removed debug info patch 2016-04-11 17:14:00 +02:00
Aurora
68bf134017 Merge pull request #19 from TuxSH/master
"Friends" and "ErrDisp" patches (and Makefile fix)
2016-04-11 16:46:12 +02:00
Aurora
c7b90f739f Use fLTO to reduce the binary size 2016-04-11 15:58:58 +02:00
Aurora
160bc36ae8 Update FatFs for the loader 2016-04-11 15:13:05 +02:00
Aurora
464bf1680c Small changes 2016-04-11 14:42:34 +02:00
TuxSH
c51eaba18c Revert "Update FatFs"
This reverts commit 6d06ea6975.
2016-04-11 11:46:49 +02:00
Aurora
7dbded99a2 First commit of the AuReiNand rewrite!
- Gotten rid of the patched FIRMs, AuReiNand now finds and loads all the FIRMs from CTRNAND by default. If you are booting an emuNAND, the FIRMs will be loaded from its CTRNAND. This also applies to AGB and TWL FIRM, and allows for a very fast boot with no firmware files on the SD card.
- If for some reason (like using NTR) you do not want to use the CTRNAND FIRM, you can place a firmware.bin in the aurei folder and it will be loaded just for the default NAND.
- The way AuReiNand works has changed. Now you can specify to autoboot SysNAND or not, and a NAND is no more tied to a FIRM (since 9.0 FIRM is autodetected). If you press nothing the default NAND is booted with its own FIRM, L boots the non-default NAND with its own FIRM, R boots EmuNAND with the SysNAND FIRM if you picked "Updated SysNAND", and vice-versa.
- In order for AuReiNand to handle FIRM reboots, the .bin path needs to be hardcoded in the program. The default is /arm9loaderhax.bin (the AuReiNand.dat is also supported for 9.0 people). A PC tool was written to make changing the path easier.
- Bug fixes and stuff I forgot.
- Gelex is a saint.
2016-04-11 05:58:46 +02:00
TuxSH
6351e5b8c3 Implement "friends" and "ErrDisp" patches 2016-04-08 23:28:40 +02:00
TuxSH
5a0f2e4dfc Fix Makefile (by including 3ds_rules) 2016-04-08 19:52:37 +02:00
Aurora
6d06ea6975 Update FatFs 2016-04-07 17:16:57 +02:00
Aurora
4180261f1f Small changes, added a macro for reading options 2016-04-06 14:54:58 +02:00
Aurora
e882dd7aaf Rewrote the config menu (no longer prints the whole menu on each button press), cleaned up the reboot patch, boot options will keep being forced if a GBA game was lanched from SysNAND, added option to have a splash screen with the built-in screen-init 2016-04-05 23:20:21 +02:00
Aurora
9e851d2dfd Small code reorganization 2016-04-05 05:34:57 +02:00
Aurora
21a3edb150 Get rid of double options reading 2016-04-05 03:08:38 +02:00
Aurora
3aacbd17ce Upped patch version 2016-04-05 02:29:36 +02:00
Aurora
6f8a9421ef Added basic support for configuring the brightness level for the built-in screen init 2016-04-05 02:24:21 +02:00
Aurora
bb437f6f7b Better commenting 2016-04-04 19:14:49 +02:00
Aurora
0001f301f8 Cleanup, fixed the second emuNAND patched FIRM still getting created, removed injector SOAP patch as it changes nothing without going to great lengths to change the region of a NNID, made L not needed to load payloads except for R and Select (Start is now default) 2016-04-04 18:07:13 +02:00
Aurora
f7bbc4bfec Made the AGB_FIRM splash screen optional
Apparently it causes compatibility issues
2016-04-04 01:08:42 +02:00
Aurora
a127a38438 Updated ReadME 2016-04-03 19:53:03 +02:00
Aurora
16225b97d7 Small changes 2016-04-03 18:18:44 +02:00
Aurora
0587c14162 Forgot stuff 2016-04-03 18:10:48 +02:00
Aurora
a181bba9f2 Added TWL/AGB FIRM patching/SD loading for New and Old 3DS (thanks to mid-kid of CakesFW for making it possible!) 2016-04-03 17:56:09 +02:00
Aurora
993e564fbb u32-ify 2016-04-02 22:02:16 +02:00
Aurora
956829864c This looks unused (my AUS N3DS has 2) 2016-04-02 18:57:52 +02:00
Aurora
24186a7148 Some more tidying up 2016-04-02 18:48:31 +02:00
Aurora
3475cfe1e6 Changed indentation style across the code to make it more readable, added newlines before comments, moved patches to separate functions, made memory operations slightly faster by compiling them with O3 (thanks TuxSH!) 2016-04-02 18:22:47 +02:00
Aurora
6b64a10362 Fixed ARM11 access to chainloaded payloads 2016-04-01 14:27:31 +02:00
Aurora
5e99fb3aa0 Fixed dumb mistakes 2016-03-31 18:25:50 +02:00
Aurora
060d8e9945 Comment things better 2016-03-31 16:04:12 +02:00
Aurora
1026471842 Leftover from testing 2016-03-31 15:59:40 +02:00
Aurora
645208ec82 EmuNAND is detected almost instantly when the CFW configures itself, if the user is attempting to load an EmuNAND and none is found, SysNAND and 9.6/10.x FIRM are forced. Also prevents the second EmuNAND patched FIRM from being created if no second EmuNAND exists. 2016-03-31 15:57:02 +02:00
Aurora
f4c48a64ca Fixed loading the alternate EmuNAND if 9.0 FIRM was set as default, improved comments and further cleanup of the injector 2016-03-31 01:38:28 +02:00
Aurora
c80ac985fe Further clean-up of the patcher code 2016-03-29 22:43:15 +02:00
Aurora
ac9bdc7665 Fixed exiting GBA games with updated SysNAND 2016-03-29 18:56:51 +02:00
Aurora
217d75024d These should be u32s 2016-03-29 18:47:30 +02:00
Aurora
12e5b4adb9 Updated readME 2016-03-29 18:17:22 +02:00
58 changed files with 13336 additions and 12097 deletions

1
.gitignore vendored
View File

@@ -1,6 +1,7 @@
out out
build build
loader/build loader/build
screeninit/build
injector/build injector/build
*.bin *.bin
*.3dsx *.3dsx

View File

@@ -1,5 +1,11 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2)) rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc CC := arm-none-eabi-gcc
AS := arm-none-eabi-as AS := arm-none-eabi-as
LD := arm-none-eabi-ld LD := arm-none-eabi-ld
@@ -11,6 +17,7 @@ version := $(shell git describe --abbrev=0 --tags)
dir_source := source dir_source := source
dir_patches := patches dir_patches := patches
dir_loader := loader dir_loader := loader
dir_screeninit := screeninit
dir_injector := injector dir_injector := injector
dir_mset := CakeHax dir_mset := CakeHax
dir_ninjhax := CakeBrah dir_ninjhax := CakeBrah
@@ -18,14 +25,15 @@ dir_build := build
dir_out := out dir_out := out
ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -ffast-math CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -fshort-wchar -std=c11 -Wno-main -O2 -flto -ffast-math
CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\"" LDFLAGS := -nostartfiles
FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory FLAGS := name=$(name).dat dir_out=$(abspath $(dir_out)) ICON=$(abspath icon.png) APP_DESCRIPTION="Noob-friendly 3DS CFW." APP_AUTHOR="Reisyukaku/Aurora Wright" --no-print-directory
objects_cfw = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \ objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \ $(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c))) $(call rwildcard, $(dir_source), *.s *.c)))
bundled = $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/screeninit.h
.PHONY: all .PHONY: all
all: launcher a9lh ninjhax all: launcher a9lh ninjhax
@@ -42,54 +50,67 @@ ninjhax: $(dir_out)/3ds/$(name)
.PHONY: release .PHONY: release
release: $(dir_out)/$(name).zip release: $(dir_out)/$(name).zip
.PHONY: pathchanger
pathchanger: $(dir_out)/pathchanger
.PHONY: clean .PHONY: clean
clean: clean:
@$(MAKE) $(FLAGS) -C $(dir_mset) clean @$(MAKE) $(FLAGS) -C $(dir_mset) clean
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean @$(MAKE) $(FLAGS) -C $(dir_ninjhax) clean
@rm -rf $(dir_out) $(dir_build)
@$(MAKE) -C $(dir_loader) clean @$(MAKE) -C $(dir_loader) clean
@$(MAKE) -C $(dir_screeninit) clean
@$(MAKE) -C $(dir_injector) clean @$(MAKE) -C $(dir_injector) clean
@rm -rf $(dir_out) $(dir_build)
$(dir_out): $(dir_out):
@mkdir -p "$(dir_out)/aurei/payloads" @mkdir -p "$(dir_out)/aurei/payloads"
$(dir_out)/pathchanger: $(dir_out)
@cc pathchanger/pathchanger.c -o out/pathchanger
$(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out) $(dir_out)/$(name).dat: $(dir_build)/main.bin $(dir_out)
@$(MAKE) $(FLAGS) -C $(dir_mset) launcher @$(MAKE) $(FLAGS) -C $(dir_mset) launcher
@dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144 @dd if=$(dir_build)/main.bin of=$@ bs=512 seek=144
$(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out) $(dir_out)/arm9loaderhax.bin: $(dir_build)/main.bin $(dir_out)
@cp -av $(dir_build)/main.bin $@ @cp -a $(dir_build)/main.bin $@
$(dir_out)/3ds/$(name): $(dir_out) $(dir_out)/3ds/$(name): $(dir_out)
@mkdir -p "$(dir_out)/3ds/$(name)" @mkdir -p "$@"
@$(MAKE) $(FLAGS) -C $(dir_ninjhax) @$(MAKE) $(FLAGS) -C $(dir_ninjhax)
@mv $(dir_out)/$(name).3dsx $@ @mv $(dir_out)/$(name).3dsx $(dir_out)/$(name).smdh $@
@mv $(dir_out)/$(name).smdh $@
$(dir_out)/$(name).zip: launcher a9lh ninjhax $(dir_out)/$(name).zip: launcher a9lh ninjhax
@cd $(dir_out) && zip -9 -r $(name) * @cd "$(@D)" && zip -9 -r $(name) *
$(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
@mkdir -p "$(dir_build)"
@armips $<
@armips $(word 2,$^)
@$(MAKE) -C $(dir_injector)
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(dir_build)
@bin2c -o $@ -n emunand $(dir_build)/emunand.bin -n reboot $(dir_build)/reboot.bin -n injector $(dir_build)/injector.cxi
$(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@mv $(dir_loader)/loader.bin $(dir_build)
@bin2c -o $@ -n loader $(dir_build)/loader.bin
$(dir_build)/main.bin: $(dir_build)/main.elf $(dir_build)/main.bin: $(dir_build)/main.elf
$(OC) -S -O binary $< $@ $(OC) -S -O binary $< $@
$(dir_build)/main.elf: $(objects_cfw) $(dir_build)/main.elf: $(objects)
# FatFs requires libgcc for __aeabi_uidiv $(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(CC) -nostartfiles $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c $(dir_build)/patches.h $(dir_build)/loader.h $(dir_build)/patches.h: $(dir_patches)/emunand.s $(dir_patches)/reboot.s $(dir_injector)/Makefile
@mkdir -p "$(@D)"
@armips $<
@armips $(word 2,$^)
@$(MAKE) -C $(dir_injector)
@mv emunand.bin reboot.bin $(dir_injector)/injector.cxi $(@D)
@bin2c -o $@ -n emunand $(@D)/emunand.bin -n reboot $(@D)/reboot.bin -n injector $(@D)/injector.cxi
$(dir_build)/loader.h: $(dir_loader)/Makefile
@$(MAKE) -C $(dir_loader)
@mv $(dir_loader)/loader.bin $(@D)
@bin2c -o $@ -n loader $(@D)/loader.bin
$(dir_build)/screeninit.h: $(dir_screeninit)/Makefile
@$(MAKE) -C $(dir_screeninit)
@mv $(dir_screeninit)/screeninit.bin $(@D)
@bin2c -o $@ -n screeninit $(@D)/screeninit.bin
$(dir_build)/memory.o : CFLAGS += -O3
$(dir_build)/config.o : CFLAGS += -DCONFIG_TITLE="\"$(name) $(version) configuration\""
$(dir_build)/%.o: $(dir_source)/%.c $(bundled)
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
@@ -99,9 +120,9 @@ $(dir_build)/%.o: $(dir_source)/%.s
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c $(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.c) -mthumb -mthumb-interwork -Wno-unused-function $(OUTPUT_OPTION) $< $(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s $(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
@mkdir -p "$(@D)" @mkdir -p "$(@D)"
$(COMPILE.s) -mthumb -mthumb-interwork $(OUTPUT_OPTION) $< $(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d) include $(call rwildcard, $(dir_build), *.d)

View File

@@ -3,30 +3,14 @@
**Compiling:** **Compiling:**
You'll need armips and [bin2c](https://sourceforge.net/projects/bin2c/) added to your Path. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips. You'll need armips, [bin2c](https://sourceforge.net/projects/bin2c/), and a recent build of [makerom](https://github.com/profi200/Project_CTR) added to your PATH. [HERE](http://www91.zippyshare.com/v/ePGpjk9r/file.html) is a pre-compiled version of armips for Windows.
Then, just run "make" and everything should work!
You can find the compiled files in the 'out' folder.
Lastly, just run Make and everything should work! **Setup / Usage / Features:**
Copy everything in 'out' folder to SD root and run! See https://github.com/AuroraWright/AuReiNand/wiki
**Usage / Features:**
See https://github.com/Reisyukaku/ReiNand and http://gbatemp.net/threads/reinand-mod-o3ds-n3ds-sysnand.411110
The FIRMs you need are [HERE](http://www99.zippyshare.com/v/kEIiQl0x/file.html).
**Credits:** **Credits:**
Rei as this is mostly his code. See https://github.com/AuroraWright/AuReiNand/wiki/Credits
The offset to detect the console, and to calculate the O3DS NAND CTR are from Decrypt9.
tiniVi suggested me a way to detect a A9LH environment, and figured out screen deinit.
Delebile provided me with the FIRM writes blocking patch.
A skilled reverser gave me the new reboot patch.
The screen init code is from dark_samus, bil1s, Normmatt, delebile and everyone who contributed.
The code for printing to the screen is from CakesFW.

View File

@@ -158,7 +158,7 @@ static Result load_code(u64 progid, prog_addrs_t *shared, u64 prog_handle, int i
} }
// patch // patch
patch_code(progid, (u8 *)shared->text_addr, shared->total_size << 12); patchCode(progid, (u8 *)shared->text_addr, shared->total_size << 12);
return 0; return 0;
} }

View File

@@ -5,17 +5,21 @@
#ifndef PATH_MAX #ifndef PATH_MAX
#define PATH_MAX 255 #define PATH_MAX 255
#define CONFIG(a) ((config >> (a + 16)) & 1)
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((config >> a) & b)
#endif #endif
static u32 config = 0; static u32 config = 0;
static u8 secureinfo[0x111] = {0}; static u8 secureInfo[0x111] = {0};
//Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190 //Quick Search algorithm, adapted from http://igm.univ-mlv.fr/~lecroq/string/node19.html#SECTION00190
static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -25,7 +29,8 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];
@@ -34,28 +39,31 @@ static u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSiz
return NULL; return NULL;
} }
static u32 patch_memory(u8 *start, u32 size, const void *pattern, u32 patsize, int offset, const void *replace, u32 repsize, u32 count){ static u32 patchMemory(u8 *start, u32 size, const void *pattern, u32 patSize, int offset, const void *replace, u32 repSize, u32 count)
{
u32 i; u32 i;
for(i = 0; i < count; i++){ for(i = 0; i < count; i++)
u8 *found = memsearch(start, pattern, size, patsize); {
if(found == NULL) u8 *found = memsearch(start, pattern, size, patSize);
break;
memcpy(found + offset, replace, repsize); if(found == NULL) break;
memcpy(found + offset, replace, repSize);
u32 at = (u32)(found - start); u32 at = (u32)(found - start);
if(at + patsize > size) size = 0; if(at + patSize > size) break;
else size = size - (at + patsize);
start = found + patsize; size -= at + patSize;
start = found + patSize;
} }
return i; return i;
} }
static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){ static int fileOpen(IFile *file, FS_ArchiveID id, const char *path, int flags)
{
FS_Archive archive; FS_Archive archive;
FS_Path ppath; FS_Path ppath;
@@ -66,69 +74,226 @@ static int file_open(IFile *file, FS_ArchiveID id, const char *path, int flags){
archive.lowPath.data = (u8 *)""; archive.lowPath.data = (u8 *)"";
ppath.type = PATH_ASCII; ppath.type = PATH_ASCII;
ppath.data = path; ppath.data = path;
ppath.size = len+1; ppath.size = len + 1;
return IFile_Open(file, archive, ppath, flags); return IFile_Open(file, archive, ppath, flags);
} }
static int patch_secureinfo(){ static int loadSecureInfo(void)
IFile file; {
Result ret; if(secureInfo[0] == 0xFF)
u64 total;
if(secureinfo[0] == 0xFF)
return 0; return 0;
ret = file_open(&file, ARCHIVE_SDMC, "/SecureInfo_A", FS_OPEN_READ); IFile file;
if(R_SUCCEEDED(ret)){ Result ret = fileOpen(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo)); if(R_SUCCEEDED(ret))
{
u64 total;
ret = IFile_Read(&file, &total, secureInfo, 0x111);
IFile_Close(&file); IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo)){ if(R_SUCCEEDED(ret) && total == 0x111)
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_WRITE | FS_OPEN_CREATE); secureInfo[0] = 0xFF;
if(R_SUCCEEDED(ret)){
ret = IFile_Write(&file, &total, secureinfo, sizeof(secureinfo), FS_WRITE_FLUSH);
IFile_Close(&file);
}
secureinfo[0] = 0xFF; // we repurpose this byte as status
}
}
else { // get file from NAND
ret = file_open(&file, ARCHIVE_NAND_RW, "/sys/SecureInfo_C", FS_OPEN_READ);
if(R_SUCCEEDED(ret)){
ret = IFile_Read(&file, &total, secureinfo, sizeof(secureinfo));
IFile_Close(&file);
if(R_SUCCEEDED(ret) && total == sizeof(secureinfo))
secureinfo[0] = 0xFF;
}
} }
return ret; return ret;
} }
static int open_config(){ static int loadConfig(void)
IFile file; {
Result ret;
u64 total;
if(config) if(config)
return 0; return 0;
ret = file_open(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ); IFile file;
if(R_SUCCEEDED(ret)){ Result ret = fileOpen(&file, ARCHIVE_SDMC, "/aurei/config.bin", FS_OPEN_READ);
ret = IFile_Read(&file, &total, (void *)&config, 3); if(R_SUCCEEDED(ret))
{
u64 total;
ret = IFile_Read(&file, &total, &config, 4);
IFile_Close(&file); IFile_Close(&file);
if(R_SUCCEEDED(ret)) config |= 1 << 4;
} }
return ret; return ret;
} }
u32 patch_code(u64 progid, u8 *code, u32 size){ static int loadTitleLocaleConfig(u64 progId, u8 *regionId, u8 *languageId)
if( progid == 0x0004003000008F02LL || // USA Menu {
progid == 0x0004003000008202LL || // JPN Menu /* Here we look for "/aurei/locales/[u64 titleID in hex, uppercase].txt"
progid == 0x0004003000009802LL || // EUR Menu If it exists it should contain, for example, "EUR IT" */
progid == 0x000400300000A102LL || // CHN Menu
progid == 0x000400300000A902LL || // KOR Menu char path[] = "/aurei/locales/0000000000000000.txt";
progid == 0x000400300000B102LL // TWN Menu
){ u32 i = 30;
while(progId > 0)
{
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[(u32)(progId & 0xF)];
progId >>= 4;
}
IFile file;
Result ret = fileOpen(&file, ARCHIVE_SDMC, path, FS_OPEN_READ);
if(R_SUCCEEDED(ret))
{
char buf[6];
u64 total;
ret = IFile_Read(&file, &total, buf, 6);
IFile_Close(&file);
if(!R_SUCCEEDED(ret) || total < 6) return -1;
for(u32 i = 0; i < 7; ++i)
{
static const char *regions[] = {"JPN", "USA", "EUR", "AUS", "CHN", "KOR", "TWN"};
if(memcmp(buf, regions[i], 3) == 0)
{
*regionId = (u8)i;
break;
}
}
for(u32 i = 0; i < 12; ++i)
{
static const char *languages[] = {"JP", "EN", "FR", "DE", "IT", "ES", "ZH", "KO", "NL", "PT", "RU", "TW"};
if(memcmp(buf + 4, languages[i], 2) == 0)
{
*languageId = (u8)i;
break;
}
}
}
return ret;
}
static u8 *getCfgOffsets(u8 *code, u32 size, u32 *CFGUHandleOffset)
{
/* HANS:
Look for error code which is known to be stored near cfg:u handle
this way we can find the right candidate
(handle should also be stored right after end of candidate function) */
u32 n = 0,
possible[24];
for(u8 *pos = code + 4; n < 24 && pos < code + size - 4; pos += 4)
{
if(*(u32 *)pos == 0xD8A103F9)
{
for(u32 *l = (u32 *)pos - 4; n < 24 && l < (u32 *)pos + 4; l++)
if(*l <= 0x10000000) possible[n++] = *l;
}
}
for(u8 *CFGU_GetConfigInfoBlk2_endPos = code; CFGU_GetConfigInfoBlk2_endPos < code + size - 8; CFGU_GetConfigInfoBlk2_endPos += 4)
{
static const u32 CFGU_GetConfigInfoBlk2_endPattern[] = {0xE8BD8010, 0x00010082};
//There might be multiple implementations of GetConfigInfoBlk2 but let's search for the one we want
u32 *cmp = (u32 *)CFGU_GetConfigInfoBlk2_endPos;
if(cmp[0] == CFGU_GetConfigInfoBlk2_endPattern[0] && cmp[1] == CFGU_GetConfigInfoBlk2_endPattern[1])
{
*CFGUHandleOffset = *((u32 *)CFGU_GetConfigInfoBlk2_endPos + 2);
for(u32 i = 0; i < n; i++)
if(possible[i] == *CFGUHandleOffset) return CFGU_GetConfigInfoBlk2_endPos;
CFGU_GetConfigInfoBlk2_endPos += 4;
}
}
return NULL;
}
static void patchCfgGetLanguage(u8 *code, u32 size, u8 languageId, u8 *CFGU_GetConfigInfoBlk2_endPos)
{
u8 *CFGU_GetConfigInfoBlk2_startPos; //Let's find STMFD SP (there might be a NOP before, but nevermind)
for(CFGU_GetConfigInfoBlk2_startPos = CFGU_GetConfigInfoBlk2_endPos - 4;
CFGU_GetConfigInfoBlk2_startPos >= code && *((u16 *)CFGU_GetConfigInfoBlk2_startPos + 1) != 0xE92D;
CFGU_GetConfigInfoBlk2_startPos -= 2);
for(u8 *languageBlkIdPos = code; languageBlkIdPos < code + size; languageBlkIdPos += 4)
{
if(*(u32 *)languageBlkIdPos == 0xA0002)
{
for(u8 *instr = languageBlkIdPos - 8; instr >= languageBlkIdPos - 0x1008 && instr >= code + 4; instr -= 4) //Should be enough
{
if(instr[3] == 0xEB) //We're looking for BL
{
u8 *calledFunction = instr;
u32 i = 0,
found;
do
{
u32 low24 = (*(u32 *)calledFunction & 0x00FFFFFF) << 2;
u32 signMask = (u32)(-(low24 >> 25)) & 0xFC000000; //Sign extension
s32 offset = (s32)(low24 | signMask) + 8; //Branch offset + 8 for prefetch
calledFunction += offset;
found = calledFunction >= CFGU_GetConfigInfoBlk2_startPos - 4 && calledFunction <= CFGU_GetConfigInfoBlk2_endPos;
i++;
}
while(i < 2 && !found && calledFunction[3] == 0xEA);
if(found)
{
*((u32 *)instr - 1) = 0xE3A00000 | languageId; // mov r0, sp => mov r0, =languageId
*(u32 *)instr = 0xE5CD0000; // bl CFGU_GetConfigInfoBlk2 => strb r0, [sp]
*((u32 *)instr + 1) = 0xE3B00000; // (1 or 2 instructions) => movs r0, 0 (result code)
//We're done
return;
}
}
}
}
}
}
static void patchCfgGetRegion(u8 *code, u32 size, u8 regionId, u32 CFGUHandleOffset)
{
for(u8 *cmdPos = code; cmdPos < code + size - 28; cmdPos += 4)
{
static const u32 cfgSecureInfoGetRegionCmdPattern[] = {0xEE1D4F70, 0xE3A00802, 0xE5A40080};
u32 *cmp = (u32 *)cmdPos;
if(cmp[0] == cfgSecureInfoGetRegionCmdPattern[0] && cmp[1] == cfgSecureInfoGetRegionCmdPattern[1] &&
cmp[2] == cfgSecureInfoGetRegionCmdPattern[2] && *((u16 *)cmdPos + 7) == 0xE59F &&
*(u32 *)(cmdPos + 20 + *((u16 *)cmdPos + 6)) == CFGUHandleOffset)
{
*((u32 *)cmdPos + 4) = 0xE3A00000 | regionId; // mov r0, =regionId
*((u32 *)cmdPos + 5) = 0xE5C40008; // strb r0, [r4, 8]
*((u32 *)cmdPos + 6) = 0xE3B00000; // movs r0, 0 (result code) ('s' not needed but nvm)
*((u32 *)cmdPos + 7) = 0xE5840004; // str r0, [r4, 4]
//The remaining, not patched, function code will do the rest for us
break;
}
}
}
void patchCode(u64 progId, u8 *code, u32 size)
{
switch(progId)
{
case 0x0004003000008F02LL: // USA Menu
case 0x0004003000008202LL: // EUR Menu
case 0x0004003000009802LL: // JPN Menu
case 0x000400300000A102LL: // CHN Menu
case 0x000400300000A902LL: // KOR Menu
case 0x000400300000B102LL: // TWN Menu
{
static const u8 regionFreePattern[] = { static const u8 regionFreePattern[] = {
0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3 0x00, 0x00, 0x55, 0xE3, 0x01, 0x10, 0xA0, 0xE3
}; };
@@ -136,97 +301,98 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1 0x01, 0x00, 0xA0, 0xE3, 0x1E, 0xFF, 0x2F, 0xE1
}; };
patch_memory(code, size, //Patch SMDH region checks
patchMemory(code, size,
regionFreePattern, regionFreePattern,
sizeof(regionFreePattern), -16, sizeof(regionFreePattern), -16,
regionFreePatch, regionFreePatch,
sizeof(regionFreePatch), 1 sizeof(regionFreePatch), 1
); );
break;
} }
else if(progid == 0x0004013000002C02LL){ // NIM
case 0x0004013000002C02LL: // NIM
{
static const u8 blockAutoUpdatesPattern[] = { static const u8 blockAutoUpdatesPattern[] = {
0x25, 0x79, 0x0B, 0x99 0x25, 0x79, 0x0B, 0x99
}; };
static const u8 blockAutoUpdatesPatch[] = { static const u8 blockAutoUpdatesPatch[] = {
0xE3, 0xA0 0xE3, 0xA0
}; };
static const u8 blockEShopUpdateCheckPattern[] = { static const u8 skipEshopUpdateCheckPattern[] = {
0x30, 0xB5, 0xF1, 0xB0 0x30, 0xB5, 0xF1, 0xB0
}; };
static const u8 blockEShopUpdateCheckPatch[] = { static const u8 skipEshopUpdateCheckPatch[] = {
0x00, 0x20, 0x08, 0x60, 0x70, 0x47 0x00, 0x20, 0x08, 0x60, 0x70, 0x47
}; };
static const u8 countryRespPattern[] = {
0x01, 0x20, 0x01, 0x90, 0x22, 0x46, 0x06, 0x9B
};
static const char countryRespPatchModel[] = {
0x06, 0x9A, 0x03, 0x20, 0x90, 0x47, 0x55, 0x21, 0x01, 0x70, 0x53, 0x21, 0x41, 0x70, 0x00, 0x21,
0x81, 0x70, 0x60, 0x61, 0x00, 0x20
};
const char *country;
char countryRespPatch[sizeof(countryRespPatchModel)];
patch_memory(code, size, //Block silent auto-updates
patchMemory(code, size,
blockAutoUpdatesPattern, blockAutoUpdatesPattern,
sizeof(blockAutoUpdatesPattern), 0, sizeof(blockAutoUpdatesPattern), 0,
blockAutoUpdatesPatch, blockAutoUpdatesPatch,
sizeof(blockAutoUpdatesPatch), 1 sizeof(blockAutoUpdatesPatch), 1
); );
patch_memory(code, size,
blockEShopUpdateCheckPattern, //Skip update checks to access the EShop
sizeof(blockEShopUpdateCheckPattern), 0, patchMemory(code, size,
blockEShopUpdateCheckPatch, skipEshopUpdateCheckPattern,
sizeof(blockEShopUpdateCheckPatch), 1 sizeof(skipEshopUpdateCheckPattern), 0,
skipEshopUpdateCheckPatch,
sizeof(skipEshopUpdateCheckPatch), 1
); );
if(R_SUCCEEDED(patch_secureinfo())){
switch(secureinfo[0x100]){ break;
case 1: country = "US"; break;
case 2: country = "GB"; break; // sorry rest-of-Europe, you have to change this
case 3: country = "AU"; break;
case 4: country = "CN"; break;
case 5: country = "KR"; break;
case 6: country = "TW"; break;
default: case 0: country = "JP"; break;
} }
// patch XML response Country case 0x0004013000003202LL: // FRIENDS
memcpy(countryRespPatch, {
countryRespPatchModel, static const u8 fpdVerPattern[] = {
sizeof(countryRespPatchModel) 0xE0, 0x1E, 0xFF, 0x2F, 0xE1, 0x01, 0x01, 0x01
); };
countryRespPatch[6] = country[0];
countryRespPatch[10] = country[1];
patch_memory(code, size,
countryRespPattern,
sizeof(countryRespPattern), 0,
countryRespPatch,
sizeof(countryRespPatch), 1
);
}
}
else if(
progid == 0x0004001000021000LL || // USA MSET
progid == 0x0004001000020000LL || // JPN MSET
progid == 0x0004001000022000LL || // EUR MSET
progid == 0x0004001000026000LL || // CHN MSET
progid == 0x0004001000027000LL || // KOR MSET
progid == 0x0004001000028000LL // TWN MSET
){
if(R_SUCCEEDED(open_config()) && ((config >> 5) & 0x1)){
static const u16 VerPattern[] = u"Ver.";
const u32 currentFirm = ((config >> 12) & 0x1);
const u32 currentNand = ((config >> 13) & 0x3);
patch_memory(code, size, u8 *fdpVer = memsearch(code, fpdVerPattern, size, sizeof(fpdVerPattern));
VerPattern,
sizeof(VerPattern) - sizeof(u16), 0, if(fdpVer != NULL)
currentNand ? ((currentNand == 1) ? ((currentFirm == 1) ? u" Emu" : u"Emu9") : u"Emu2") : {
((currentFirm == 1) ? u" Sys" : u"Sys9"), fdpVer += sizeof(fpdVerPattern) + 1;
sizeof(VerPattern) - sizeof(u16), 1
//Allow online access to work with old friends modules
if(*fdpVer < 5) *fdpVer = 5;
}
break;
}
case 0x0004001000021000LL: // USA MSET
case 0x0004001000020000LL: // JPN MSET
case 0x0004001000022000LL: // EUR MSET
case 0x0004001000026000LL: // CHN MSET
case 0x0004001000027000LL: // KOR MSET
case 0x0004001000028000LL: // TWN MSET
{
if(R_SUCCEEDED(loadConfig()) && CONFIG(6))
{
static const u16 verPattern[] = u"Ver.";
const u32 currentNand = BOOTCONFIG(0, 3);
const u32 matchingFirm = BOOTCONFIG(2, 1) == (currentNand != 0);
//Patch Ver. string
patchMemory(code, size,
verPattern,
sizeof(verPattern) - sizeof(u16), 0,
!currentNand ? ((matchingFirm) ? u" Sys" : u"SysE") :
((currentNand == 1) ? (matchingFirm ? u" Emu" : u"EmuS") : ((matchingFirm) ? u"Emu2" : u"Em2S")),
sizeof(verPattern) - sizeof(u16), 1
); );
} }
break;
} }
else if (progid == 0x0004013000008002LL){ // NS
case 0x0004013000008002LL: // NS
{
static const u8 stopCartUpdatesPattern[] = { static const u8 stopCartUpdatesPattern[] = {
0x0C, 0x18, 0xE1, 0xD8 0x0C, 0x18, 0xE1, 0xD8
}; };
@@ -234,33 +400,57 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
0x0B, 0x18, 0x21, 0xC8 0x0B, 0x18, 0x21, 0xC8
}; };
patch_memory(code, size, //Disable updates from foreign carts (makes carts region-free)
patchMemory(code, size,
stopCartUpdatesPattern, stopCartUpdatesPattern,
sizeof(stopCartUpdatesPattern), 0, sizeof(stopCartUpdatesPattern), 0,
stopCartUpdatesPatch, stopCartUpdatesPatch,
sizeof(stopCartUpdatesPatch), 2 sizeof(stopCartUpdatesPatch), 2
); );
if(R_SUCCEEDED(loadConfig()) && MULTICONFIG(1))
{
static const u8 cfgN3dsCpuPattern[] = {
0x40, 0xA0, 0xE1, 0x07, 0x00
};
u8 *cfgN3dsCpuLoc = memsearch(code, cfgN3dsCpuPattern, size, sizeof(cfgN3dsCpuPattern));
//Patch N3DS CPU Clock and L2 cache setting
if(cfgN3dsCpuLoc != NULL)
{
*(u32 *)(cfgN3dsCpuLoc + 3) = 0xE1A00000;
*(u32 *)(cfgN3dsCpuLoc + 0x1F) = 0xE3A00000 | MULTICONFIG(1);
} }
else if(progid == 0x0004013000001702LL){ // CFG }
break;
}
case 0x0004013000001702LL: // CFG
{
static const u8 secureinfoSigCheckPattern[] = { static const u8 secureinfoSigCheckPattern[] = {
0x06, 0x46, 0x10, 0x48, 0xFC 0x06, 0x46, 0x10, 0x48, 0xFC
}; };
static const u8 secureinfoSigCheckPatch[] = { static const u8 secureinfoSigCheckPatch[] = {
0x00, 0x26 0x00, 0x26
}; };
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
// disable SecureInfo signature check //Disable SecureInfo signature check
patch_memory(code, size, patchMemory(code, size,
secureinfoSigCheckPattern, secureinfoSigCheckPattern,
sizeof(secureinfoSigCheckPattern), 0, sizeof(secureinfoSigCheckPattern), 0,
secureinfoSigCheckPatch, secureinfoSigCheckPatch,
sizeof(secureinfoSigCheckPatch), 1 sizeof(secureinfoSigCheckPatch), 1
); );
if(R_SUCCEEDED(patch_secureinfo())){
// use SecureInfo_C if(R_SUCCEEDED(loadSecureInfo()))
patch_memory(code, size, {
static const u16 secureinfoFilenamePattern[] = u"SecureInfo_";
static const u16 secureinfoFilenamePatch[] = u"C";
//Use SecureInfo_C
patchMemory(code, size,
secureinfoFilenamePattern, secureinfoFilenamePattern,
sizeof(secureinfoFilenamePattern) - sizeof(u16), sizeof(secureinfoFilenamePattern) - sizeof(u16),
sizeof(secureinfoFilenamePattern) - sizeof(u16), sizeof(secureinfoFilenamePattern) - sizeof(u16),
@@ -268,7 +458,38 @@ u32 patch_code(u64 progid, u8 *code, u32 size){
sizeof(secureinfoFilenamePatch) - sizeof(u16), 2 sizeof(secureinfoFilenamePatch) - sizeof(u16), 2
); );
} }
break;
} }
return 0; default:
if(R_SUCCEEDED(loadConfig()) && CONFIG(4))
{
u32 tidHigh = (progId & 0xFFFFFFF000000000LL) >> 0x24;
if(tidHigh == 0x0004000)
{
//Language emulation
u8 regionId = 0xFF,
languageId = 0xFF;
int ret = loadTitleLocaleConfig(progId, &regionId, &languageId);
if(R_SUCCEEDED(ret))
{
u32 CFGUHandleOffset;
u8 *CFGU_GetConfigInfoBlk2_endPos = getCfgOffsets(code, size, &CFGUHandleOffset);
if(CFGU_GetConfigInfoBlk2_endPos != NULL)
{
if(languageId != 0xFF) patchCfgGetLanguage(code, size, languageId, CFGU_GetConfigInfoBlk2_endPos);
if(regionId != 0xFF) patchCfgGetRegion(code, size, regionId, CFGUHandleOffset);
}
}
}
break;
}
}
} }

View File

@@ -2,4 +2,4 @@
#include <3ds/types.h> #include <3ds/types.h>
u32 patch_code(u64 progid, u8 *code, u32 size); void patchCode(u64 progId, u8 *code, u32 size);

View File

@@ -1,6 +1,4 @@
#--------------------------------------------------------------------------------- rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),) ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM") $(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
@@ -8,127 +6,50 @@ endif
include $(DEVKITARM)/3ds_rules include $(DEVKITARM)/3ds_rules
#--------------------------------------------------------------------------------- CC := arm-none-eabi-gcc
# TARGET is the name of the output AS := arm-none-eabi-as
# BUILD is the directory where object files & intermediate files will be placed LD := arm-none-eabi-ld
# SOURCES is a list of directories containing source code OC := arm-none-eabi-objcopy
# DATA is a list of directories containing data files
# INCLUDES is a list of directories containing header files
# SPECS is the directory containing the important build and link files
#---------------------------------------------------------------------------------
export TARGET := $(shell basename $(CURDIR))
BUILD := build
SOURCES := source source/fatfs source/fatfs/sdmmc
DATA := data
INCLUDES := include source/fatfs source/fatfs/sdmmc
#--------------------------------------------------------------------------------- name := $(shell basename $(CURDIR))
# Setup some defines
#---------------------------------------------------------------------------------
#--------------------------------------------------------------------------------- dir_source := source
# options for code generation dir_build := build
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\ ASFLAGS := -mlittle-endian -mcpu=arm946e-s -march=armv5te
-march=armv5te -mtune=arm946e-s\ CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -mthumb -mthumb-interwork
-ffast-math -Wno-main -std=c99\ LDFLAGS := -nostartfiles
$(ARCH)
CFLAGS += $(INCLUDE) -DARM9 objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions .PHONY: all
all: $(name).bin
ASFLAGS := -g $(ARCH) .PHONY: clean
LDFLAGS = -nostartfiles -g --specs=../stub.specs $(ARCH) -Wl,-Map,$(TARGET).map
LIBS :=
#---------------------------------------------------------------------------------
# list of directories containing libraries, this must be the top level containing
# include and lib
#---------------------------------------------------------------------------------
LIBDIRS :=
#---------------------------------------------------------------------------------
# no real need to edit anything past this point unless you need to add additional
# rules for different file extensions
#---------------------------------------------------------------------------------
ifneq ($(BUILD),$(notdir $(CURDIR)))
#---------------------------------------------------------------------------------
export OUTPUT := $(CURDIR)/$(TARGET)
export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \
$(foreach dir,$(DATA),$(CURDIR)/$(dir))
export DEPSDIR := $(CURDIR)/$(BUILD)
CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c)))
CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp)))
SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s)))
BINFILES := $(foreach dir,$(DATA),$(notdir $(wildcard $(dir)/*.*)))
#---------------------------------------------------------------------------------
# use CXX for linking C++ projects, CC for standard C
#---------------------------------------------------------------------------------
ifeq ($(strip $(CPPFILES)),)
#---------------------------------------------------------------------------------
export LD := $(CC)
#---------------------------------------------------------------------------------
else
#---------------------------------------------------------------------------------
export LD := $(CXX)
#---------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------
export OFILES := $(addsuffix .o,$(BINFILES)) \
$(CPPFILES:.cpp=.o) $(CFILES:.c=.o) $(SFILES:.s=.o)
export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \
$(foreach dir,$(LIBDIRS),-I$(dir)/include) \
-I$(CURDIR)/$(BUILD)
export LIBPATHS := $(foreach dir,$(LIBDIRS),-L$(dir)/lib)
.PHONY: $(BUILD) clean all
#---------------------------------------------------------------------------------
all: $(BUILD)
$(BUILD):
@[ -d $@ ] || mkdir -p $@
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile
#---------------------------------------------------------------------------------
clean: clean:
@echo clean ... @rm -rf $(dir_build)
@rm -fr $(BUILD) $(OUTPUT).elf
$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
#--------------------------------------------------------------------------------- $(dir_build)/$(name).elf: $(objects)
else $(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
DEPENDS := $(OFILES:.o=.d) $(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
#--------------------------------------------------------------------------------- $(dir_build)/%.o: $(dir_source)/%.s
# main targets @mkdir -p "$(@D)"
#--------------------------------------------------------------------------------- $(COMPILE.s) $(OUTPUT_OPTION) $<
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
$(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
#--------------------------------------------------------------------------------- $(dir_build)/fatfs/%.o: $(dir_source)/fatfs/%.s
%.bin: %.elf @mkdir -p "$(@D)"
@$(OBJCOPY) -O binary $< $@ $(COMPILE.s) $(OUTPUT_OPTION) $<
@echo built ... $(notdir $@) include $(call rwildcard, $(dir_build), *.d)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

View File

@@ -9,4 +9,3 @@ SECTIONS
.rodata : { *(.rodata) } .rodata : { *(.rodata) }
. = ALIGN(4); . = ALIGN(4);
} }

View File

@@ -2,13 +2,12 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5) #define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6) #define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7) #define BUTTON_DOWN (1 << 7)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_R1 (1 << 8)
#define BUTTON_SELECT (1 << 2)

View File

@@ -3,73 +3,98 @@
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
R0.00 (February 26, 2006) R0.00 (February 26, 2006)
Prototype. Prototype.
R0.01 (April 29, 2006) R0.01 (April 29, 2006)
First stable version. First stable version.
R0.02 (June 01, 2006) R0.02 (June 01, 2006)
Added FAT12 support. Added FAT12 support.
Removed unbuffered mode. Removed unbuffered mode.
Fixed a problem on small (<32M) partition. Fixed a problem on small (<32M) partition.
R0.02a (June 10, 2006) R0.02a (June 10, 2006)
Added a configuration option (_FS_MINIMUM). Added a configuration option (_FS_MINIMUM).
R0.03 (September 22, 2006) R0.03 (September 22, 2006)
Added f_rename(). Added f_rename().
Changed option _FS_MINIMUM to _FS_MINIMIZE. Changed option _FS_MINIMUM to _FS_MINIMIZE.
R0.03a (December 11, 2006) R0.03a (December 11, 2006)
Improved cluster scan algorithm to write files fast. Improved cluster scan algorithm to write files fast.
Fixed f_mkdir() creates incorrect directory on FAT32. Fixed f_mkdir() creates incorrect directory on FAT32.
R0.04 (February 04, 2007) R0.04 (February 04, 2007)
Added f_mkfs(). Added f_mkfs().
Supported multiple drive system. Supported multiple drive system.
Changed some interfaces for multiple drive system. Changed some interfaces for multiple drive system.
Changed f_mountdrv() to f_mount(). Changed f_mountdrv() to f_mount().
R0.04a (April 01, 2007) R0.04a (April 01, 2007)
Supported multiple partitions on a physical drive. Supported multiple partitions on a physical drive.
Added a capability of extending file size to f_lseek(). Added a capability of extending file size to f_lseek().
Added minimization level 3. Added minimization level 3.
Fixed an endian sensitive code in f_mkfs(). Fixed an endian sensitive code in f_mkfs().
R0.04b (May 05, 2007) R0.04b (May 05, 2007)
Added a configuration option _USE_NTFLAG. Added a configuration option _USE_NTFLAG.
Added FSINFO support. Added FSINFO support.
Fixed DBCS name can result FR_INVALID_NAME. Fixed DBCS name can result FR_INVALID_NAME.
Fixed short seek (<= csize) collapses the file object. Fixed short seek (<= csize) collapses the file object.
R0.05 (August 25, 2007) R0.05 (August 25, 2007)
Changed arguments of f_read(), f_write() and f_mkfs(). Changed arguments of f_read(), f_write() and f_mkfs().
Fixed f_mkfs() on FAT32 creates incorrect FSINFO. Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
Fixed f_mkdir() on FAT32 creates incorrect directory. Fixed f_mkdir() on FAT32 creates incorrect directory.
R0.05a (February 03, 2008) R0.05a (February 03, 2008)
Added f_truncate() and f_utime(). Added f_truncate() and f_utime().
Fixed off by one error at FAT sub-type determination. Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated. Fixed btr in f_read() can be mistruncated.
Fixed cached sector is not flushed when create and close without write. Fixed cached sector is not flushed when create and close without write.
R0.06 (April 01, 2008) R0.06 (April 01, 2008)
Added fputc(), fputs(), fprintf() and fgets(). Added fputc(), fputs(), fprintf() and fgets().
Improved performance of f_lseek() on moving to the same or following cluster. Improved performance of f_lseek() on moving to the same or following cluster.
R0.07 (April 01, 2009) R0.07 (April 01, 2009)
Merged Tiny-FatFs as a configuration option. (_FS_TINY) Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Added long file name feature. (_USE_LFN) Added long file name feature. (_USE_LFN)
Added multiple code page feature. (_CODE_PAGE) Added multiple code page feature. (_CODE_PAGE)
@@ -80,12 +105,16 @@ R0.07 (April 01, 2009)
Renamed string functions to avoid name collision. Renamed string functions to avoid name collision.
R0.07a (April 14, 2009) R0.07a (April 14, 2009)
Septemberarated out OS dependent code on reentrant cfg. Septemberarated out OS dependent code on reentrant cfg.
Added multiple sector size feature. Added multiple sector size feature.
R0.07c (June 21, 2009) R0.07c (June 21, 2009)
Fixed f_unlink() can return FR_OK on error. Fixed f_unlink() can return FR_OK on error.
Fixed wrong cache control in f_lseek(). Fixed wrong cache control in f_lseek().
Added relative path feature. Added relative path feature.
@@ -93,7 +122,9 @@ R0.07c (June 21, 2009)
Added proper case conversion to extended character. Added proper case conversion to extended character.
R0.07e (November 03, 2009) R0.07e (November 03, 2009)
Septemberarated out configuration options from ff.h to ffconf.h. Septemberarated out configuration options from ff.h to ffconf.h.
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH. Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
Fixed name matching error on the 13 character boundary. Fixed name matching error on the 13 character boundary.
@@ -101,7 +132,9 @@ R0.07e (November 03, 2009)
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg. Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
R0.08 (May 15, 2010) R0.08 (May 15, 2010)
Added a memory configuration option. (_USE_LFN = 3) Added a memory configuration option. (_USE_LFN = 3)
Added file lock feature. (_FS_SHARE) Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK) Added fast seek feature. (_USE_FASTSEEK)
@@ -110,36 +143,48 @@ R0.08 (May 15, 2010)
String functions support UTF-8 encoding files on Unicode cfg. String functions support UTF-8 encoding files on Unicode cfg.
R0.08a (August 16, 2010) R0.08a (August 16, 2010)
Added f_getcwd(). (_FS_RPATH = 2) Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE) Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss. Moved file lock semaphore table from fs object to the bss.
Fixed f_mkfs() creates wrong FAT32 volume. Fixed f_mkfs() creates wrong FAT32 volume.
R0.08b (January 15, 2011) R0.08b (January 15, 2011)
Fast seek feature is also applied to f_read() and f_write(). Fast seek feature is also applied to f_read() and f_write().
f_lseek() reports required table size on creating CLMP. f_lseek() reports required table size on creating CLMP.
Extended format syntax of f_printf(). Extended format syntax of f_printf().
Ignores duplicated directory separators in given path name. Ignores duplicated directory separators in given path name.
R0.09 (September 06, 2011) R0.09 (September 06, 2011)
f_mkfs() supports multiple partition to complete the multiple partition feature. f_mkfs() supports multiple partition to complete the multiple partition feature.
Added f_fdisk(). Added f_fdisk().
R0.09a (August 27, 2012) R0.09a (August 27, 2012)
Changed f_open() and f_opendir() reject null object pointer to avoid crash. Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK. Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume. Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.09b (January 24, 2013) R0.09b (January 24, 2013)
Added f_setlabel() and f_getlabel(). Added f_setlabel() and f_getlabel().
R0.10 (October 02, 2013) R0.10 (October 02, 2013)
Added selection of character encoding on the file. (_STRF_ENCODE) Added selection of character encoding on the file. (_STRF_ENCODE)
Added f_closedir(). Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO) Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
@@ -151,7 +196,9 @@ R0.10 (October 02, 2013)
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code. Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
R0.10a (January 15, 2014) R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID) Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS) Added a configuration option of minimum sector size. (_MIN_SS)
2nd argument of f_rename() can have a drive number and it will be ignored. 2nd argument of f_rename() can have a drive number and it will be ignored.
@@ -161,12 +208,16 @@ R0.10a (January 15, 2014)
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07) Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
R0.10b (May 19, 2014) R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry. Fixed a hard error in the disk I/O layer can collapse the directory entry.
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07) Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
R0.10c (November 09, 2014) R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC) Added a configuration option for the platforms without RTC. (_FS_NORTC)
Changed option name _USE_ERASE to _USE_TRIM. Changed option name _USE_ERASE to _USE_TRIM.
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b) Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
@@ -174,7 +225,21 @@ R0.10c (November 09, 2014)
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08) Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
R0.11 (February 09, 2015) R0.11 (February 09, 2015)
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND) Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c) Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c) Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)
R0.11a (September 05, 2015)
Fixed wrong media change can lead a deadlock at thread-safe configuration.
Added code page 771, 860, 861, 863, 864, 865 and 869. (_CODE_PAGE)
Removed some code pages actually not exist on the standard systems. (_CODE_PAGE)
Fixed errors in the case conversion teble of code page 437 and 850 (ff.c).
Fixed errors in the case conversion teble of Unicode (cc*.c).

View File

@@ -35,6 +35,7 @@ DSTATUS disk_initialize (
) )
{ {
sdmmc_sdcard_init(); sdmmc_sdcard_init();
return RES_OK; return RES_OK;
} }
@@ -52,9 +53,8 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) )
{ {
if (sdmmc_sdcard_readsectors(sector, count, buff)) { if(sdmmc_sdcard_readsectors(sector, count, buff))
return RES_PARERR; return RES_PARERR;
}
return RES_OK; return RES_OK;
} }
@@ -74,9 +74,8 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { if(sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
}
return RES_OK; return RES_OK;
} }

547
loader/source/fatfs/ff.c Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - FAT file system module R0.11 (C)ChaN, 2015 / FatFs - FAT file system module R0.11a (C)ChaN, 2015 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@@ -26,7 +26,7 @@
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#if _FATFS != 32020 /* Revision ID */ #if _FATFS != 64180 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif
@@ -83,7 +83,7 @@ typedef struct {
/* DBCS code ranges and SBCS extend character conversion table */ /* DBCS code ranges and SBCS upper conversion tables */
#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */
#define _DF1S 0x81 /* DBC 1st byte range 1 start */ #define _DF1S 0x81 /* DBC 1st byte range 1 start */
@@ -121,211 +121,192 @@ typedef struct {
#define _DS2S 0xA1 #define _DS2S 0xA1
#define _DS2E 0xFE #define _DS2E 0xFE
#elif _CODE_PAGE == 437 /* U.S. (OEM) */ #elif _CODE_PAGE == 437 /* U.S. */
#define _DF1S 0 #define _DF1S 0
/*#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
static #elif _CODE_PAGE == 720 /* Arabic */
const unsigned short Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
WCHAR ff_convert( /* Converted character, Returns zero on error */
WCHAR src, /* Character code to be converted */
UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
WCHAR c;
if(src < 0x80)
{ /* ASCII */
c = src;
}
else
{
if(dir)
{ /* OEMCP to Unicode */
c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
}
else
{ /* Unicode to OEMCP */
for(c = 0; c < 0x80; c++)
{
if(src == Tbl[c])
break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper(WCHAR chr)
{
if(chr >= 'a' && chr <= 'z')
return (chr - 32);
else
return chr;
}
#elif _CODE_PAGE == 720 /* Arabic (OEM) */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 737 /* Greek (OEM) */ #elif _CODE_PAGE == 737 /* Greek */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
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, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \
0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 775 /* Baltic (OEM) */ #elif _CODE_PAGE == 771 /* KBL */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 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,0xDC,0xDE,0xDE, \
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,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}
#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ #elif _CODE_PAGE == 775 /* Baltic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ #elif _CODE_PAGE == 850 /* Latin 1 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \
0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \
0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ #elif _CODE_PAGE == 852 /* Latin 2 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \
0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \
0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
#elif _CODE_PAGE == 857 /* Turkish (OEM) */ #elif _CODE_PAGE == 855 /* Cyrillic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \
0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ #elif _CODE_PAGE == 857 /* Turkish */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ #elif _CODE_PAGE == 860 /* Portuguese */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 866 /* Russian (OEM) */ #elif _CODE_PAGE == 861 /* Icelandic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ #elif _CODE_PAGE == 862 /* Hebrew */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ #elif _CODE_PAGE == 863 /* Canadian-French */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \
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, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ #elif _CODE_PAGE == 864 /* Arabic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ #elif _CODE_PAGE == 865 /* Nordic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1253 /* Greek (Windows) */ #elif _CODE_PAGE == 866 /* Russian */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ #elif _CODE_PAGE == 869 /* Greek 2 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \
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, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 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, \
#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \
#define _DF1S 0 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
#if _USE_LFN #if _USE_LFN
@@ -377,12 +358,12 @@ WCHAR ff_wtoupper(WCHAR chr)
/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ /* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */
#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ #define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */
#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ #define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */
/* FatFs refers the members in the FAT structures as byte array instead of /* FatFs refers the members in the FAT structures as byte array instead of
/ structure member because the structure is not binary compatible between / structure members because the structure is not binary compatible between
/ different platforms */ / different platforms */
#define BS_jmpBoot 0 /* x86 jump instruction (3) */ #define BS_jmpBoot 0 /* x86 jump instruction (3) */
@@ -399,7 +380,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_NumHeads 26 /* Number of heads (2) */ #define BPB_NumHeads 26 /* Number of heads (2) */
#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ #define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
#define BPB_TotSec32 32 /* Volume size [sector] (4) */ #define BPB_TotSec32 32 /* Volume size [sector] (4) */
#define BS_DrvNum 36 /* Physical drive number (2) */ #define BS_DrvNum 36 /* Physical drive number (1) */
#define BS_NTres 37 /* Error flag (1) */
#define BS_BootSig 38 /* Extended boot signature (1) */ #define BS_BootSig 38 /* Extended boot signature (1) */
#define BS_VolID 39 /* Volume serial number (4) */ #define BS_VolID 39 /* Volume serial number (4) */
#define BS_VolLab 43 /* Volume label (8) */ #define BS_VolLab 43 /* Volume label (8) */
@@ -410,7 +392,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_RootClus 44 /* Root directory first cluster (4) */ #define BPB_RootClus 44 /* Root directory first cluster (4) */
#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ #define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ #define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
#define BS_DrvNum32 64 /* Physical drive number (2) */ #define BS_DrvNum32 64 /* Physical drive number (1) */
#define BS_NTres32 65 /* Error flag (1) */
#define BS_BootSig32 66 /* Extended boot signature (1) */ #define BS_BootSig32 66 /* Extended boot signature (1) */
#define BS_VolID32 67 /* Volume serial number (4) */ #define BS_VolID32 67 /* Volume serial number (4) */
#define BS_VolLab32 71 /* Volume label (8) */ #define BS_VolLab32 71 /* Volume label (8) */
@@ -438,7 +421,7 @@ WCHAR ff_wtoupper(WCHAR chr)
#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
#define LDIR_Attr 11 /* LFN attribute (1) */ #define LDIR_Attr 11 /* LFN attribute (1) */
#define LDIR_Type 12 /* LFN type (1) */ #define LDIR_Type 12 /* LFN type (1) */
#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ #define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */
#define LDIR_FstClusLO 26 /* Must be zero (0) */ #define LDIR_FstClusLO 26 /* Must be zero (0) */
#define SZ_DIRE 32 /* Size of a directory entry */ #define SZ_DIRE 32 /* Size of a directory entry */
#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */
@@ -448,12 +431,15 @@ WCHAR ff_wtoupper(WCHAR chr)
/*------------------------------------------------------------*/ /*--------------------------------------------------------------------------
/* Module private work area */
/*------------------------------------------------------------*/ Module Private Work Area
/* Remark: Uninitialized variables with static duration are
/ guaranteed zero/null at start-up. If not, either the linker ---------------------------------------------------------------------------*/
/ or start-up routine being used is out of ANSI-C standard.
/* Remark: Uninitialized variables with static duration are guaranteed
/ zero/null at start-up. If not, either the linker or start-up routine
/ being used is not compliance with ANSI-C standard.
*/ */
#if _VOLUMES < 1 || _VOLUMES > 9 #if _VOLUMES < 1 || _VOLUMES > 9
@@ -497,7 +483,7 @@ static WCHAR LfnBuf[_MAX_LFN + 1];
#endif #endif
#ifdef _EXCVT #ifdef _EXCVT
static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */
#endif #endif
@@ -711,7 +697,7 @@ void clear_lock ( /* Clear lock entries of the volume */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_window ( FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@@ -740,7 +726,7 @@ FRESULT sync_window (
static static
FRESULT move_window ( FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD sector /* Sector number to make appearance in the fs->win[] */ DWORD sector /* Sector number to make appearance in the fs->win[] */
) )
@@ -771,7 +757,7 @@ FRESULT move_window (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@@ -780,16 +766,16 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
res = sync_window(fs); res = sync_window(fs);
if (res == FR_OK) { if (res == FR_OK) {
/* Update FSINFO sector if needed */ /* Update FSInfo sector if needed */
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
/* Create FSINFO structure */ /* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs)); mem_set(fs->win, 0, SS(fs));
ST_WORD(fs->win + BS_55AA, 0xAA55); ST_WORD(fs->win + BS_55AA, 0xAA55);
ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
/* Write it into the FSINFO sector */ /* Write it into the FSInfo sector */
fs->winsect = fs->volbase + 1; fs->winsect = fs->volbase + 1;
disk_write(fs->drv, fs->win, fs->winsect, 1); disk_write(fs->drv, fs->win, fs->winsect, 1);
fs->fsi_flag = 0; fs->fsi_flag = 0;
@@ -811,7 +797,7 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to be converted */ DWORD clst /* Cluster# to be converted */
) )
@@ -829,7 +815,7 @@ static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* FAT index number (cluster number) to get the value */ DWORD clst /* FAT index number (cluster number) to get the value */
) )
@@ -839,7 +825,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
DWORD val; DWORD val;
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
val = 1; /* Internal error */ val = 1; /* Internal error */
} else { } else {
@@ -884,7 +870,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
#if !_FS_READONLY #if !_FS_READONLY
static FRESULT put_fat ( FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD clst, /* FAT index number (cluster number) to be changed */
DWORD val /* New value to be set to the entry */ DWORD val /* New value to be set to the entry */
@@ -895,7 +881,7 @@ static FRESULT put_fat (
FRESULT res; FRESULT res;
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@@ -948,7 +934,7 @@ static FRESULT put_fat (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT remove_chain ( FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to remove a chain from */ DWORD clst /* Cluster# to remove a chain from */
) )
@@ -959,7 +945,7 @@ FRESULT remove_chain (
DWORD scl = clst, ecl = clst, rt[2]; DWORD scl = clst, ecl = clst, rt[2];
#endif #endif
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@@ -1003,7 +989,7 @@ FRESULT remove_chain (
static static
DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */
) )
{ {
DWORD cs, ncl, scl; DWORD cs, ncl, scl;
@@ -1091,7 +1077,7 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_sdi ( FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to directory object */ DIR* dp, /* Pointer to directory object */
UINT idx /* Index of directory table */ UINT idx /* Index of directory table */
) )
@@ -1139,7 +1125,7 @@ FRESULT dir_sdi (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
) )
@@ -1210,7 +1196,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT dir_alloc ( FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
UINT nent /* Number of contiguous entries to allocate (1-21) */ UINT nent /* Number of contiguous entries to allocate (1-21) */
) )
@@ -1246,9 +1232,9 @@ FRESULT dir_alloc (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
DWORD ld_clust ( DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */
FATFS* fs, /* Pointer to the fs object */ FATFS* fs, /* Pointer to the fs object */
BYTE* dir /* Pointer to the directory entry */ const BYTE* dir /* Pointer to the SFN entry */
) )
{ {
DWORD cl; DWORD cl;
@@ -1264,7 +1250,7 @@ DWORD ld_clust (
#if !_FS_READONLY #if !_FS_READONLY
static static
void st_clust ( void st_clust (
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the SFN entry */
DWORD cl /* Value to be set */ DWORD cl /* Value to be set */
) )
{ {
@@ -1285,27 +1271,29 @@ const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN char
static static
int cmp_lfn ( /* 1:Matched, 0:Not matched */ int cmp_lfn ( /* 1:matched, 0:not matched */
WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */
BYTE* dir /* Pointer to the directory entry containing a part of LFN */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; WCHAR wc, uc;
i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
s = 0; wc = 1;
do { i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */
if (wc) { /* Last character has not been processed */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
wc = ff_wtoupper(uc); /* Convert it to upper case */ uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ if (wc) {
if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */
return 0; /* Not matched */ return 0; /* Not matched */
wc = uc;
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} while (++s < 13); /* Repeat until all characters in the entry are checked */ }
if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
return 0; return 0;
@@ -1316,34 +1304,35 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */
#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 #if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
static static
int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir /* Pointer to the directory entry */ BYTE* dir /* Pointer to the LFN entry */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; WCHAR wc, uc;
if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
s = 0; wc = 1; for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
do { uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ if (wc) {
if (wc) { /* Last character has not been processed */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */ lfnbuf[i++] = wc = uc; /* Store it */
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} while (++s < 13); /* Read all character in the entry */ }
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i] = 0; lfnbuf[i] = 0;
} }
return 1; return 1; /* The part of LFN is valid */
} }
#endif #endif
@@ -1351,22 +1340,22 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
#if !_FS_READONLY #if !_FS_READONLY
static static
void fit_lfn ( void fit_lfn (
const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the LFN entry to be processed */
BYTE ord, /* LFN order (1-20) */ BYTE ord, /* LFN order (1-20) */
BYTE sum /* SFN sum */ BYTE sum /* Checksum of the corresponding SFN */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc; WCHAR wc;
dir[LDIR_Chksum] = sum; /* Set check sum */ dir[LDIR_Chksum] = sum; /* Set checksum */
dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
dir[LDIR_Type] = 0; dir[LDIR_Type] = 0;
ST_WORD(dir + LDIR_FstClusLO, 0); ST_WORD(dir + LDIR_FstClusLO, 0);
i = (ord - 1) * 13; /* Get offset in the LFN buffer */ i = (ord - 1) * 13; /* Get offset in the LFN working buffer */
s = wc = 0; s = wc = 0;
do { do {
if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */
@@ -1443,7 +1432,7 @@ void gen_numname (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Calculate sum of an SFN */ /* Calculate checksum of an SFN entry */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if _USE_LFN #if _USE_LFN
static static
@@ -1467,7 +1456,7 @@ BYTE sum_sfn (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_find ( FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp /* Pointer to the directory object linked to the file name */ DIR* dp /* Pointer to the directory object linked to the file name */
) )
{ {
@@ -1587,7 +1576,7 @@ FRESULT dir_read (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ 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 */ DIR* dp /* Target directory with object name to be created */
) )
{ {
@@ -1627,7 +1616,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
if (res == FR_OK && --nent) { /* Set LFN entry if needed */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */
res = dir_sdi(dp, dp->index - nent); res = dir_sdi(dp, dp->index - nent);
if (res == FR_OK) { if (res == FR_OK) {
sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */
do { /* Store LFN entries in bottom first */ do { /* Store LFN entries in bottom first */
res = move_window(dp->fs, dp->sect); res = move_window(dp->fs, dp->sect);
if (res != FR_OK) break; if (res != FR_OK) break;
@@ -1665,7 +1654,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY && !_FS_MINIMIZE #if !_FS_READONLY && !_FS_MINIMIZE
static static
FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
DIR* dp /* Directory object pointing the entry to be removed */ DIR* dp /* Directory object pointing the entry to be removed */
) )
{ {
@@ -1804,7 +1793,7 @@ WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */
static static
int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ int pattern_matching ( /* 0:mismatched, 1:matched */
const TCHAR* pat, /* Matching pattern */ const TCHAR* pat, /* Matching pattern */
const TCHAR* nam, /* String to be tested */ const TCHAR* nam, /* String to be tested */
int skip, /* Number of pre-skip chars (number of ?s) */ int skip, /* Number of pre-skip chars (number of ?s) */
@@ -1848,11 +1837,11 @@ int pattern_matching ( /* Return value: 0:mismatched, 1:matched */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Pick a segment and create the object name in directory form */ /* Pick a top segment and create the object name in directory form */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT create_name ( FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
const TCHAR** path /* Pointer to pointer to the segment in the path string */ const TCHAR** path /* Pointer to pointer to the segment in the path string */
) )
@@ -1890,22 +1879,21 @@ FRESULT create_name (
*path = &p[si]; /* Return pointer to the next segment */ *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 path */
#if _FS_RPATH #if _FS_RPATH
if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ if ((di == 1 && lfn[di - 1] == '.') ||
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */
lfn[di] = 0; lfn[di] = 0;
for (i = 0; i < 11; i++) for (i = 0; i < 11; i++) /* Create dot name for SFN entry */
dp->fn[i] = (i < di) ? '.' : ' '; dp->fn[i] = (i < di) ? '.' : ' ';
dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
return FR_OK; return FR_OK;
} }
#endif #endif
while (di) { /* Strip trailing spaces and dots */ while (di) { /* Snip off trailing spaces and dots if exist */
w = lfn[di - 1]; w = lfn[di - 1];
if (w != ' ' && w != '.') break; if (w != ' ' && w != '.') break;
di--; di--;
} }
if (!di) return FR_INVALID_NAME; /* Reject nul string */ if (!di) return FR_INVALID_NAME; /* Reject nul string */
lfn[di] = 0; /* LFN is created */ lfn[di] = 0; /* LFN is created */
/* Create SFN in directory form */ /* Create SFN in directory form */
@@ -1942,7 +1930,7 @@ FRESULT create_name (
cf |= NS_LFN; /* Force create LFN entry */ cf |= NS_LFN; /* Force create LFN entry */
} }
if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */
if (i >= ni - 1) { if (i >= ni - 1) {
cf |= NS_LOSS | NS_LFN; i = ni; continue; cf |= NS_LOSS | NS_LFN; i = ni; continue;
} }
@@ -1963,7 +1951,7 @@ FRESULT create_name (
dp->fn[i++] = (BYTE)w; dp->fn[i++] = (BYTE)w;
} }
if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */ if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
if (ni == 8) b <<= 2; if (ni == 8) b <<= 2;
if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
@@ -1984,7 +1972,7 @@ FRESULT create_name (
const char *p; const char *p;
/* Create file name in directory form */ /* Create file name in directory form */
for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */
sfn = dp->fn; sfn = dp->fn;
mem_set(sfn, ' ', 11); mem_set(sfn, ' ', 11);
si = i = b = 0; ni = 8; si = i = b = 0; ni = 8;
@@ -2019,7 +2007,7 @@ FRESULT create_name (
#endif #endif
#endif #endif
} }
if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */
d = (BYTE)p[si++]; /* Get 2nd byte */ d = (BYTE)p[si++]; /* Get 2nd byte */
if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
return FR_INVALID_NAME; return FR_INVALID_NAME;
@@ -2185,7 +2173,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */
FATFS* fs, /* File system object */ 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 boot record or not */
) )
@@ -2343,7 +2331,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
/* Get fsinfo if available */ /* Get fsinfo if available */
fs->fsi_flag = 0x80; fs->fsi_flag = 0x80;
#if (_FS_NOFSINFO & 3) != 3 #if (_FS_NOFSINFO & 3) != 3
if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */
&& LD_WORD(fs->win + BPB_FSInfo) == 1 && LD_WORD(fs->win + BPB_FSInfo) == 1
&& move_window(fs, bsect + 1) == FR_OK) && move_window(fs, bsect + 1) == FR_OK)
{ {
@@ -2389,14 +2377,11 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */
if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT))
return FR_INVALID_OBJECT; return FR_INVALID_OBJECT;
ENTER_FF(fil->fs); /* Lock file system */ ENTER_FF(fil->fs); /* Lock file system */
if (disk_status(fil->fs->drv) & STA_NOINIT)
return FR_NOT_READY;
return FR_OK; return FR_OK;
} }
@@ -2407,7 +2392,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
Public Functions Public Functions
--------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
@@ -2522,12 +2507,13 @@ FRESULT f_open (
} }
} }
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
dw = GET_FATTIME(); /* Created time */ dw = GET_FATTIME();
ST_DWORD(dir + DIR_CrtTime, dw); ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */
ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */
dir[DIR_Attr] = 0; /* Reset attribute */ dir[DIR_Attr] = 0; /* Reset attribute */
ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */
cl = ld_clust(dj.fs, dir); /* Get start cluster */ cl = ld_clust(dj.fs, dir); /* Get cluster chain */
st_clust(dir, 0); /* cluster = 0 */ st_clust(dir, 0); /* Reset cluster */
dj.fs->wflag = 1; dj.fs->wflag = 1;
if (cl) { /* Remove the cluster chain if exist */ if (cl) { /* Remove the cluster chain if exist */
dw = dj.fs->winsect; dw = dj.fs->winsect;
@@ -2540,7 +2526,7 @@ FRESULT f_open (
} }
} }
else { /* Open an existing file */ else { /* Open an existing file */
if (res == FR_OK) { /* Follow succeeded */ if (res == FR_OK) { /* Following succeeded */
if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
res = FR_NO_FILE; res = FR_NO_FILE;
} else { } else {
@@ -2832,10 +2818,9 @@ FRESULT f_sync (
res = validate(fp); /* Check validity of the object */ res = validate(fp); /* Check validity of the object */
if (res == FR_OK) { if (res == FR_OK) {
if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */
/* Write-back dirty buffer */
#if !_FS_TINY #if !_FS_TINY
if (fp->flag & FA__DIRTY) { if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */
if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
LEAVE_FF(fp->fs, FR_DISK_ERR); LEAVE_FF(fp->fs, FR_DISK_ERR);
fp->flag &= ~FA__DIRTY; fp->flag &= ~FA__DIRTY;
@@ -2848,7 +2833,7 @@ FRESULT f_sync (
dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
st_clust(dir, fp->sclust); /* Update start cluster */ st_clust(dir, fp->sclust); /* Update start cluster */
tm = GET_FATTIME(); /* Update updated time */ tm = GET_FATTIME(); /* Update modified time */
ST_DWORD(dir + DIR_WrtTime, tm); ST_DWORD(dir + DIR_WrtTime, tm);
ST_WORD(dir + DIR_LstAccDate, 0); ST_WORD(dir + DIR_LstAccDate, 0);
fp->flag &= ~FA__WRITTEN; fp->flag &= ~FA__WRITTEN;
@@ -3425,7 +3410,7 @@ FRESULT f_getfree (
{ {
FRESULT res; FRESULT res;
FATFS *fs; FATFS *fs;
DWORD n, clst, sect, stat; DWORD nfree, clst, sect, stat;
UINT i; UINT i;
BYTE fat, *p; BYTE fat, *p;
@@ -3440,18 +3425,17 @@ FRESULT f_getfree (
} else { } else {
/* Get number of free clusters */ /* Get number of free clusters */
fat = fs->fs_type; fat = fs->fs_type;
n = 0; nfree = 0;
if (fat == FS_FAT12) { if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */
clst = 2; clst = 2;
do { do {
stat = get_fat(fs, clst); stat = get_fat(fs, clst);
if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; }
if (stat == 0) n++; if (stat == 0) nfree++;
} while (++clst < fs->n_fatent); } while (++clst < fs->n_fatent);
} else { } else { /* Sector alighed entries: Accelerate the FAT search. */
clst = fs->n_fatent; clst = fs->n_fatent; sect = fs->fatbase;
sect = fs->fatbase;
i = 0; p = 0; i = 0; p = 0;
do { do {
if (!i) { if (!i) {
@@ -3461,17 +3445,17 @@ FRESULT f_getfree (
i = SS(fs); i = SS(fs);
} }
if (fat == FS_FAT16) { if (fat == FS_FAT16) {
if (LD_WORD(p) == 0) n++; if (LD_WORD(p) == 0) nfree++;
p += 2; i -= 2; p += 2; i -= 2;
} else { } else {
if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++;
p += 4; i -= 4; p += 4; i -= 4;
} }
} while (--clst); } while (--clst);
} }
fs->free_clust = n; fs->free_clust = nfree; /* free_clust is valid */
fs->fsi_flag |= 1; fs->fsi_flag |= 1; /* FSInfo is to be updated */
*nclst = n; *nclst = nfree; /* Return the free clusters */
} }
} }
LEAVE_FF(fs, res); LEAVE_FF(fs, res);
@@ -3695,8 +3679,7 @@ FRESULT f_chmod (
DEFINE_NAMEBUF; DEFINE_NAMEBUF;
/* Get logical drive number */ res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */
res = find_volume(&dj.fs, &path, 1);
if (res == FR_OK) { if (res == FR_OK) {
INIT_BUF(dj); INIT_BUF(dj);
res = follow_path(&dj, path); /* Follow the file path */ res = follow_path(&dj, path); /* Follow the file path */
@@ -4263,7 +4246,7 @@ FRESULT f_mkfs (
ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ 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 */ if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
return FR_DISK_ERR; return FR_DISK_ERR;
if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */
disk_write(pdrv, tbl, b_vol + 6, 1); disk_write(pdrv, tbl, b_vol + 6, 1);
/* Initialize FAT area */ /* Initialize FAT area */

6
loader/source/fatfs/ff.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - FAT file system module include R0.11a (C)ChaN, 2015
/----------------------------------------------------------------------------/ /----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@@ -17,7 +17,7 @@
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 32020 /* Revision ID */ #define _FATFS 64180 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -200,7 +200,7 @@ typedef enum {
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 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_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT; } FRESULT;

53
loader/source/fatfs/ffconf.h Normal file → Executable file
View File

@@ -1,21 +1,13 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 64180 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_READONLY 1 #define _FS_READONLY 1
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
@@ -23,7 +15,7 @@
/ and optional writing functions as well. */ / and optional writing functions as well. */
#define _FS_MINIMIZE 3 #define _FS_MINIMIZE 1
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: All basic functions are enabled.
@@ -42,7 +34,7 @@
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 0 #define _USE_FIND 1
/* This option switches filtered directory read feature and related functions, /* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ / f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
@@ -69,7 +61,7 @@
/ Locale and Namespace Configurations / Locale and Namespace Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _CODE_PAGE 437 #define _CODE_PAGE 1
/* This option specifies the OEM code page to be used on the target system. /* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure. / Incorrect setting of the code page can cause a file open failure.
/ /
@@ -77,23 +69,28 @@
/ 437 - U.S. / 437 - U.S.
/ 720 - Arabic / 720 - Arabic
/ 737 - Greek / 737 - Greek
/ 771 - KBL
/ 775 - Baltic / 775 - Baltic
/ 850 - Multilingual Latin 1 / 850 - Latin 1
/ 852 - Latin 2 / 852 - Latin 2
/ 855 - Cyrillic / 855 - Cyrillic
/ 857 - Turkish / 857 - Turkish
/ 858 - Multilingual Latin 1 + Euro / 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew / 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian / 866 - Russian
/ 874 - Thai / 869 - Greek 2
/ 932 - Japanese Shift_JIS (DBCS) / 932 - Japanese (DBCS)
/ 936 - Simplified Chinese GBK (DBCS) / 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS) / 949 - Korean (DBCS)
/ 950 - Traditional Chinese Big5 (DBCS) / 950 - Traditional Chinese (DBCS)
*/ */
#define _USE_LFN 2 #define _USE_LFN 0
#define _MAX_LFN 255 #define _MAX_LFN 255
/* The _USE_LFN option switches the LFN feature. /* The _USE_LFN option switches the LFN feature.
/ /
@@ -115,7 +112,7 @@
/ to 1. This option also affects behavior of string I/O functions. */ / to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0 #define _STRF_ENCODE 3
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to /* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/ /
@@ -195,8 +192,16 @@
/ System Configurations / System Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_NORTC 1 #define _FS_NORTC 1
#define _NORTC_MON 2 #define _NORTC_MON 1
#define _NORTC_MDAY 1 #define _NORTC_MDAY 1
#define _NORTC_YEAR 2015 #define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have /* The _FS_NORTC option switches timestamp feature. If the system does not have
@@ -253,7 +258,7 @@
/ * Byte order on the memory is little-endian. / * Byte order on the memory is little-endian.
/ /
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. / If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some processor types. / Following table shows allowable settings of some type of processors.
/ /
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 / Cortex-M3 0 *3 Z80 0/1 V850ES 0/1

10
loader/source/fatfs/integer.h Normal file → Executable file
View File

@@ -5,26 +5,26 @@
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* Development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#else /* Embedded platform */ #else /* Embedded platform */
/* This type MUST be 8 bit */ /* This type MUST be 8-bit */
typedef unsigned char BYTE; typedef unsigned char BYTE;
/* These types MUST be 16 bit */ /* These types MUST be 16-bit */
typedef short SHORT; typedef short SHORT;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned short WCHAR; typedef unsigned short WCHAR;
/* These types MUST be 16 bit or 32 bit */ /* These types MUST be 16-bit or 32-bit */
typedef int INT; typedef int INT;
typedef unsigned int UINT; typedef unsigned int UINT;
/* These types MUST be 32 bit */ /* These types MUST be 32-bit */
typedef long LONG; typedef long LONG;
typedef unsigned long DWORD; typedef unsigned long DWORD;

View File

@@ -3,37 +3,55 @@
#include "fatfs/ff.h" #include "fatfs/ff.h"
#define PAYLOAD_ADDRESS 0x23F00000 #define PAYLOAD_ADDRESS 0x23F00000
#define LOAD_PAYLOAD(a) loadPayload(a "_*.bin")
static u32 loadPayload(const char *pattern)
{
char path[30] = "/aurei/payloads";
DIR dir;
FILINFO info;
FRESULT result = f_findfirst(&dir, &info, path, pattern);
f_closedir(&dir);
if(result != FR_OK || !info.fname[0])
return 0;
path[15] = '/';
u32 i;
for(i = 0; info.fname[i]; i++)
path[16 + i] = info.fname[i];
path[16 + i] = '\0';
static u32 loadPayload(const char *path){
FIL payload; FIL payload;
unsigned int br; unsigned int br;
if(f_open(&payload, path, FA_READ) == FR_OK)
{ f_open(&payload, path, FA_READ);
f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br); f_read(&payload, (void *)PAYLOAD_ADDRESS, f_size(&payload), &br);
f_close(&payload); f_close(&payload);
return 1; return 1;
}
return 0;
} }
void main(void){ void main(void)
{
FATFS fs; FATFS fs;
f_mount(&fs, "0:", 1); f_mount(&fs, "0:", 1);
//Get pressed buttons //Get pressed buttons
u16 pressed = HID_PAD; u32 pressed = HID_PAD;
if(((pressed & BUTTON_B) && loadPayload("/aurei/payloads/b.bin")) || if(((pressed & BUTTON_RIGHT) && LOAD_PAYLOAD("right")) ||
((pressed & BUTTON_X) && loadPayload("/aurei/payloads/x.bin")) || ((pressed & BUTTON_LEFT) && LOAD_PAYLOAD("left")) ||
((pressed & BUTTON_Y) && loadPayload("/aurei/payloads/y.bin")) || ((pressed & BUTTON_UP) && LOAD_PAYLOAD("up")) ||
((pressed & BUTTON_SELECT) && loadPayload("/aurei/payloads/select.bin")) || ((pressed & BUTTON_DOWN) && LOAD_PAYLOAD("down")) ||
((pressed & BUTTON_START) && loadPayload("/aurei/payloads/start.bin")) || ((pressed & BUTTON_X) && LOAD_PAYLOAD("x")) ||
((pressed & BUTTON_RIGHT) && loadPayload("/aurei/payloads/right.bin")) || ((pressed & BUTTON_Y) && LOAD_PAYLOAD("y")) ||
((pressed & BUTTON_LEFT) && loadPayload("/aurei/payloads/left.bin")) || ((pressed & BUTTON_R1) && LOAD_PAYLOAD("r")) ||
((pressed & BUTTON_UP) && loadPayload("/aurei/payloads/up.bin")) || ((pressed & BUTTON_SELECT) && LOAD_PAYLOAD("sel")) ||
((pressed & BUTTON_DOWN) && loadPayload("/aurei/payloads/down.bin")) || LOAD_PAYLOAD("def"))
loadPayload("/aurei/payloads/default.bin"))
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();
} }

View File

@@ -12,7 +12,4 @@ _start:
mcr p15, 0, r0, c7, c6, 0 @ flush D-cache mcr p15, 0, r0, c7, c6, 0 @ flush D-cache
mcr p15, 0, r0, c7, c10, 4 @ drain write buffer mcr p15, 0, r0, c7, c10, 4 @ drain write buffer
bl main b main
.die:
b .die

View File

@@ -1,5 +0,0 @@
%rename link old_link
*link:
%(old_link) -T ../stub.ld%s

View File

@@ -1,221 +1,148 @@
.arm.little .arm.little
byteswritten equ 0x2000E000 payload_addr equ 0x23F00000 ; Brahma payload address.
kernelCode equ 0x080F0000 payload_maxsize equ 0x20000 ; Maximum size for the payload (200 KB will do).
buffer equ 0x24000000
fileOpen equ 0x4E45504F ;dummy
.create "reboot.bin", 0 .create "reboot.bin", 0
.arm .arm
//Code jumps here right after the sprintf call ; Interesting registers and locations to keep in mind, set before this code is ran:
process9Reboot: ; - sp + 0x3A8 - 0x70: FIRM path in exefs.
doPxi: ; - r7 (which is sp + 0x3A8 - 0x198): Reserved space for file handle
ldr r4, =0x44846 ; - *(sp + 0x3A8 - 0x198) + 0x28: fread function.
pxi_wait_recv:
ldr r2, =0x44846
ldr r0, =0x10008000 ldr r0, =0x10008000
readPxiLoop1: readPxiLoop1:
ldrh r1, [r0,#4] ldrh r1, [r0, #4]
.word 0xE1B01B81 //lsls r1, r1, #0x17 lsls r1, #0x17
bmi readPxiLoop1 bmi readPxiLoop1
ldr r0, [r0,#0xC] ldr r0, [r0, #0xC]
cmp r0, r4 cmp r0, r2
bne doPxi bne pxi_wait_recv
GetFirmPath: mov r4, #0
add r0, sp, #0x3A8-0x70+0x24 adr r1, bin_fname
ldr r1, [r0], #4 b open_payload
ldr r2, =0x00300030
cmp r1, r2
ldreq r1, [r0], #4
ldreq r2, =0x002F0032
cmpeq r1, r2
OpenFirm: fallback:
ldreq r1, =(FileName - OpenFirm - 12) mov r4, #1
addeq r1, pc adr r1, dat_fname
addne r1, sp, #0x3A8-0x70
moveq r2, #1 open_payload:
movne r2, #0 ; Open file
str r2, [externalFirm]
mov r2, #1
add r0, r7, #8 add r0, r7, #8
ldr r6, =fileOpen mov r2, #1
ldr r6, [fopen]
orr r6, 1
blx r6 blx r6
cmp r0, #0
bne fallback ; If the .bin is not found, try the .dat.
SeekFirm: read_payload:
ldr r0, [externalFirm] ; Read file
cmp r0, #1
moveq r0, r7
ldreq r1, =byteswritten
ldreq r2, =buffer
ldreq r3, =0x0
ldreq r6, [sp,#0x3A8-0x198]
ldreq r6, [r6,#0x28] //fread function stored here
blxeq r6
ReadFirm:
mov r0, r7 mov r0, r7
ldr r1, =byteswritten adr r1, bytes_read
ldr r2, =buffer ldr r2, =payload_addr
ldr r3, =0x200000 cmp r4, #0
ldr r6, [sp,#0x3A8-0x198] movne r3, #0x12000 ; Skip the first 0x12000 bytes.
ldr r6, [r6,#0x28] //fread function stored here moveq r3, payload_maxsize
ldr r6, [sp, #0x3A8-0x198]
ldr r6, [r6, #0x28]
blx r6 blx r6
cmp r4, #0
movne r4, #0
bne read_payload ; Go read the real payload.
KernelSetState: add r0, sp, #0x3A8 - 0x70
ldr r0, [r0, #0x27]
ldr r1, =payload_addr + 4
str r0, [r1] ; Copy the last digits of the wanted firm to the 5th byte of the payload.
; Set kernel state
mov r0, #0
mov r1, #0
mov r2, #0 mov r2, #0
mov r3, r2 mov r3, #0
mov r1, r2 swi 0x7C
mov r0, r2
.word 0xEF00007C //SVC 0x7C
GoToReboot: goto_reboot:
ldr r0, =(KernelCodeStart - GoToReboot - 12) ; Jump to reboot code
ldr r0, =(kernelcode_start - goto_reboot - 12)
add r0, pc add r0, pc
ldr r1, =kernelCode swi 0x7B
ldr r2, =0x300
bl Memcpy
ldr r0, =kernelCode die:
.word 0xEF00007B //SVC 0x7B b die
InfiniteLoop:
b InfiniteLoop
Memcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
memcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT memcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
FileName:
.dcw "sdmc:/aurei/patched_firmware_sys.bin"
.word 0x0
externalFirm:
.word 0x2000A000
bytes_read: .word 0
fopen: .ascii "OPEN"
.pool .pool
bin_fname: .dcw "sdmc:/arm9loaderhax.bin"
.word 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
dat_fname: .dcw "sdmc:/AuReiNand.dat"
.word 0
// Kernel Code
.align 4 .align 4
KernelCodeStart: kernelcode_start:
memorySetting: ; Set MPU settings
MRC p15, 0, R0,c2,c0, 0 mrc p15, 0, r0, c2, c0, 0 ; dcacheable
MRC p15, 0, R12,c2,c0, 1 mrc p15, 0, r12, c2, c0, 1 ; icacheable
MRC p15, 0, R1,c3,c0, 0 mrc p15, 0, r1, c3, c0, 0 ; write bufferable
MRC p15, 0, R2,c5,c0, 2 mrc p15, 0, r2, c5, c0, 2 ; daccess
MRC p15, 0, R3,c5,c0, 3 mrc p15, 0, r3, c5, c0, 3 ; iaccess
LDR R4, =0x18000035 ldr r4, =0x18000035 ; 0x18000000 128M
BIC R2, R2, #0xF0000 bic r2, r2, #0xF0000 ; unprotect region 4
BIC R3, R3, #0xF0000 bic r3, r3, #0xF0000 ; unprotect region 4
ORR R0, R0, #0x10 orr r0, r0, #0x10 ; dcacheable region 4
ORR R2, R2, #0x30000 orr r2, r2, #0x30000 ; region 4 r/w
ORR R3, R3, #0x30000 orr r3, r3, #0x30000 ; region 4 r/w
ORR R12, R12, #0x10 orr r12, r12, #0x10 ; icacheable region 4
ORR R1, R1, #0x10 orr r1, r1, #0x10 ; write bufferable region 4
MCR p15, 0, R0,c2,c0, 0 mcr p15, 0, r0, c2, c0, 0
MCR p15, 0, R12,c2,c0, 1 mcr p15, 0, r12, c2, c0, 1
MCR p15, 0, R1,c3,c0, 0 mcr p15, 0, r1, c3, c0, 0 ; write bufferable
MCR p15, 0, R2,c5,c0, 2 mcr p15, 0, r2, c5, c0, 2 ; daccess
MCR p15, 0, R3,c5,c0, 3 mcr p15, 0, r3, c5, c0, 3 ; iaccess
MCR p15, 0, R4,c6,c4, 0 mcr p15, 0, r4, c6, c4, 0 ; region 4 (hmmm)
MRC p15, 0, R0,c2,c0, 0
MRC p15, 0, R1,c2,c0, 1
MRC p15, 0, R2,c3,c0, 0
ORR R0, R0, #0x20
ORR R1, R1, #0x20
ORR R2, R2, #0x20
MCR p15, 0, R0,c2,c0, 0
MCR p15, 0, R1,c2,c0, 1
MCR p15, 0, R2,c3,c0, 0
copyFirmPartitions: mrc p15, 0, r0, c2, c0, 0 ; dcacheable
LDR R4, =buffer mrc p15, 0, r1, c2, c0, 1 ; icacheable
ADD R3, R4, #0x40 mrc p15, 0, r2, c3, c0, 0 ; write bufferable
LDR R0, [R3] orr r0, r0, #0x20 ; dcacheable region 5
ADD R0, R0, R4 orr r1, r1, #0x20 ; icacheable region 5
LDR R1, [R3,#4] orr r2, r2, #0x20 ; write bufferable region 5
LDR R2, [R3,#8] mcr p15, 0, r0, c2, c0, 0 ; dcacheable
bl KernelMemcpy mcr p15, 0, r1, c2, c0, 1 ; icacheable
mcr p15, 0, r2, c3, c0, 0 ; write bufferable
ADD R3, R4, #0x70 ; Flush cache
LDR R0, [R3] mov r2, #0
ADD R0, R0, R4 mov r1, r2
LDR R1, [R3,#4] flush_cache:
LDR R2, [R3,#8] mov r0, #0
bl KernelMemcpy mov r3, r2, lsl #30
flush_cache_inner_loop:
orr r12, r3, r0, lsl#5
mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
mcr p15, 0, r12, c7, c14, 2 ; clean and flush dcache entry (index and segment)
add r0, #1
cmp r0, #0x20
bcc flush_cache_inner_loop
add r2, #1
cmp r2, #4
bcc flush_cache
ADD R3, R4, #0xA0 ; Enable MPU
LDR R0, [R3] ldr r0, =0x42078 ; alt vector select, enable itcm
ADD R0, R0, R4 mcr p15, 0, r0, c1, c0, 0
LDR R1, [R3,#4] mcr p15, 0, r1, c7, c5, 0 ; flush dcache
LDR R2, [R3,#8] mcr p15, 0, r1, c7, c6, 0 ; flush icache
bl KernelMemcpy mcr p15, 0, r1, c7, c10, 4 ; drain write buffer
ADD R3, R4, #0xD0 ; Jump to payload
LDR R0, [R3] ldr r0, =payload_addr
CMP R0, #0 bx r0
BEQ invalidateDataCache
ADD R0, R0, R4
LDR R1, [R3,#4]
LDR R2, [R3,#8]
bl KernelMemcpy
invalidateDataCache:
MOV R2, #0
MOV R1, R2
loc_809460C:
MOV R0, #0
MOV R3, R2,LSL#30
loc_8094614:
ORR R12, R3, R0,LSL#5
MCR p15, 0, R1,c7,c10, 4
MCR p15, 0, R12,c7,c14, 2
ADD R0, R0, #1
CMP R0, #0x20
BCC loc_8094614
ADD R2, R2, #1
CMP R2, #4
BCC loc_809460C
jumpToEntrypoint:
MCR p15, 0, R1,c7,c10, 4
LDR R0, =0x42078
MCR p15, 0, R0,c1,c0, 0
MCR p15, 0, R1,c7,c5, 0
MCR p15, 0, R1,c7,c6, 0
MCR p15, 0, R1,c7,c10, 4
LDR R4, =buffer
MOV R1, #0x1FFFFFFC
LDR R2, [R4,#8]
STR R2, [R1]
LDR R0, [R4,#0xC]
BX R0
.pool .pool
KernelMemcpy:
MOV R12, LR
STMFD SP!, {R0-R4}
ADD R2, R2, R0
kmemcpyLoop:
LDR R3, [R0],#4
STR R3, [R1],#4
CMP R0, R2
BLT kmemcpyLoop
LDMFD SP!, {R0-R4}
MOV LR, R12
BX LR
.pool
KernelCodeEnd:
.close .close

98
pathchanger/pathchanger.c Normal file
View File

@@ -0,0 +1,98 @@
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef uint8_t u8;
static u8 *memsearch(u8 *startPos, const void *pattern, int size, int patternSize)
{
const u8 *patternc = (const u8 *)pattern;
//Preprocessing
int table[256];
int i;
for(i = 0; i < 256; ++i)
table[i] = patternSize + 1;
for(i = 0; i < patternSize; ++i)
table[patternc[i]] = patternSize - i;
//Searching
int j = 0;
while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j;
j += table[startPos[j + patternSize]];
}
return NULL;
}
static int fsize(FILE *fp)
{
fseek(fp, 0, SEEK_END);
int size = ftell(fp);
rewind(fp);
return size;
}
static void error(FILE *payload, const char *message)
{
fclose(payload);
printf("%s, are you sure you're using an AuReiNand payload?\n", message);
exit(0);
}
int main(int argc, char **argv)
{
if(argc == 1)
{
printf("Usage: %s <AuReiNand payload path>\n", argv[0]);
exit(0);
}
FILE *payload;
size_t size;
payload = fopen(argv[1], "rb+");
size = fsize(payload);
if(size > 0x20000)
error(payload, "The input file is too large");
u8 *buffer = (u8 *)malloc(size);
fread(buffer, 1, size, payload);
u8 pattern[] = {'s', 0, 'd', 0, 'm', 0, 'c', 0, ':', 0, '/', 0};
u8 *found = memsearch(buffer, pattern, size, sizeof(pattern));
if(found == NULL)
{
free(buffer);
error(payload, "Pattern not found");
}
u8 input[38] = {0};
u8 payloadname[2 * (sizeof(input) - 1)] = {0};
printf("Enter the payload's path (37 characters max): ");
scanf("%37s", input);
unsigned int i;
for (i = 0; i < sizeof(input) - 1; i++)
payloadname[2 * i] = input[i];
memcpy(found + 12, payloadname, sizeof(payloadname));
rewind(payload);
fwrite(buffer, 1, size, payload);
free(buffer);
fclose(payload);
exit(0);
}

47
screeninit/Makefile Executable file
View File

@@ -0,0 +1,47 @@
rwildcard = $(foreach d, $(wildcard $1*), $(filter $(subst *, %, $2), $d) $(call rwildcard, $d/, $2))
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/3ds_rules
CC := arm-none-eabi-gcc
AS := arm-none-eabi-as
LD := arm-none-eabi-ld
OC := arm-none-eabi-objcopy
name := $(shell basename $(CURDIR))
dir_source := source
dir_build := build
ASFLAGS := -mlittle-endian -mcpu=mpcore
CFLAGS := -Wall -Wextra -MMD -MP -marm $(ASFLAGS) -fno-builtin -std=c11 -Wno-main -O2 -flto -ffast-math -mthumb -mthumb-interwork
LDFLAGS := -nostdlib
objects = $(patsubst $(dir_source)/%.s, $(dir_build)/%.o, \
$(patsubst $(dir_source)/%.c, $(dir_build)/%.o, \
$(call rwildcard, $(dir_source), *.s *.c)))
.PHONY: all
all: $(name).bin
.PHONY: clean
clean:
@rm -rf $(dir_build)
$(name).bin: $(dir_build)/$(name).elf
$(OC) -S -O binary $< $@
$(dir_build)/$(name).elf: $(objects)
$(CC) $(LDFLAGS) -T linker.ld $(OUTPUT_OPTION) $^
$(dir_build)/%.o: $(dir_source)/%.c
@mkdir -p "$(@D)"
$(COMPILE.c) $(OUTPUT_OPTION) $<
$(dir_build)/%.o: $(dir_source)/%.s
@mkdir -p "$(@D)"
$(COMPILE.s) $(OUTPUT_OPTION) $<
include $(call rwildcard, $(dir_build), *.d)

12
screeninit/linker.ld Executable file
View File

@@ -0,0 +1,12 @@
ENTRY(_start)
SECTIONS
{
. = 0x24F03000;
.text.start : { *(.text.start) }
.text : { *(.text) }
.data : { *(.data) }
.bss : { *(.bss COMMON) }
.rodata : { *(.rodata) }
. = ALIGN(4);
}

105
screeninit/source/main.c Executable file
View File

@@ -0,0 +1,105 @@
#include "types.h"
void main(void)
{
const u32 brightness[4] = {0x5F, 0x4C, 0x39, 0x26};
u32 brightnessLevel = *(vu32 *)0x24F03008;
vu32 *const arm11 = (u32 *)0x1FFFFFF8;
*(vu32 *)0x10141200 = 0x1007F;
*(vu32 *)0x10202014 = 0x00000001;
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = brightness[brightnessLevel];
*(vu32 *)0x10202A40 = brightness[brightnessLevel];
*(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;
*(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;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}

10
screeninit/source/start.s Normal file
View File

@@ -0,0 +1,10 @@
.section .text.start
.align 4
.global _start
_start:
@ Disable interrupts
CPSID aif
b main
.word 0

19
screeninit/source/types.h Executable file
View File

@@ -0,0 +1,19 @@
/*
* types.h
* by Reisyukaku
* Copyright (c) 2015 All Rights Reserved
*/
#pragma once
#include <stdint.h>
//Common data types
typedef uint8_t u8;
typedef uint16_t u16;
typedef uint32_t u32;
typedef uint64_t u64;
typedef volatile u8 vu8;
typedef volatile u16 vu16;
typedef volatile u32 vu32;
typedef volatile u64 vu64;

View File

@@ -8,19 +8,22 @@
#include "types.h" #include "types.h"
#define HID_PAD (*(vu16 *)0x10146000 ^ 0xFFF) #define HID_PAD (*(vu32 *)0x10146000 ^ 0xFFF)
#define BUTTON_R1 (1 << 8) #define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9) #define BUTTON_L1 (1 << 9)
#define BUTTON_A 1 #define BUTTON_A 1
#define BUTTON_B (1 << 1) #define BUTTON_B (1 << 1)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_SELECT (1 << 2) #define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3) #define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4) #define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5) #define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6) #define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7) #define BUTTON_DOWN (1 << 7)
#define BUTTON_L1R1 ((1 << 8) | (1 << 9)) #define BUTTON_L1R1 (BUTTON_R1 | BUTTON_L1)
#define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP) #define SAFE_MODE (BUTTON_L1R1 | BUTTON_A | BUTTON_UP)
#define OPTION_BUTTONS (BUTTON_L1R1 | BUTTON_A) #define OVERRIDE_BUTTONS (BUTTON_B ^ 0xFFF)
#define PAYLOAD_BUTTONS ((BUTTON_L1 | BUTTON_A) ^ 0xFFF) #define SINGLE_PAYLOAD_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_START | BUTTON_X | BUTTON_Y)
#define L_PAYLOAD_BUTTONS (BUTTON_R1 | BUTTON_SELECT)
#define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START) #define MENU_BUTTONS (BUTTON_LEFT | BUTTON_RIGHT | BUTTON_UP | BUTTON_DOWN | BUTTON_A | BUTTON_START)

184
source/config.c Normal file
View File

@@ -0,0 +1,184 @@
/*
* config.c
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/
#include "config.h"
#include "utils.h"
#include "screeninit.h"
#include "draw.h"
#include "fs.h"
#include "buttons.h"
void configureCFW(const char *configPath)
{
initScreens();
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE);
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE);
const char *multiOptionsText[] = { "Screen-init brightness: 4( ) 3( ) 2( ) 1( )",
"New 3DS CPU: Off( ) Clock( ) L2( ) Clock+L2( )" };
const char *singleOptionsText[] = { "( ) Autoboot SysNAND",
"( ) Use SysNAND FIRM as default (A9LH-only)",
"( ) Force A9LH detection",
"( ) Use second EmuNAND as default",
"( ) Enable region/language emulation",
"( ) Use developer UNITINFO",
"( ) Show current NAND in System Settings",
"( ) Show GBA boot screen in patched AGB_FIRM",
"( ) Enable splash screen with no screen-init" };
struct multiOption {
int posXs[4];
int posY;
u32 enabled;
} multiOptions[] = {
{ .posXs = {26, 31, 36, 41} },
{ .posXs = {17, 26, 32, 44} }
};
//Calculate the amount of the various kinds of options and pre-select the first single one
u32 multiOptionsAmount = sizeof(multiOptions) / sizeof(struct multiOption),
singleOptionsAmount = sizeof(singleOptionsText) / sizeof(char *),
totalIndexes = multiOptionsAmount + singleOptionsAmount - 1,
selectedOption = multiOptionsAmount;
struct singleOption {
int posY;
u32 enabled;
} singleOptions[singleOptionsAmount];
//Parse the existing options
for(u32 i = 0; i < multiOptionsAmount; i++)
multiOptions[i].enabled = MULTICONFIG(i);
for(u32 i = 0; i < singleOptionsAmount; i++)
singleOptions[i].enabled = CONFIG(i);
//Character to display a selected option
char selected = 'x';
int endPos = 42;
//Display all the multiple choice options in white
for(u32 i = 0; i < multiOptionsAmount; i++)
{
multiOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(multiOptionsText[i], 10, multiOptions[i].posY, COLOR_WHITE);
drawCharacter(selected, 10 + multiOptions[i].posXs[multiOptions[i].enabled] * SPACING_X, multiOptions[i].posY, COLOR_WHITE);
}
endPos += SPACING_Y / 2;
u32 color = COLOR_RED;
//Display all the normal options in white except for the first one
for(u32 i = 0; i < singleOptionsAmount; i++)
{
singleOptions[i].posY = endPos + SPACING_Y;
endPos = drawString(singleOptionsText[i], 10, singleOptions[i].posY, color);
if(singleOptions[i].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[i].posY, color);
color = COLOR_WHITE;
}
u32 pressed = 0;
//Boring configuration menu
while(pressed != BUTTON_START)
{
do
{
pressed = waitInput();
}
while(!(pressed & MENU_BUTTONS));
if(pressed != BUTTON_A)
{
//Remember the previously selected option
u32 oldSelectedOption = selectedOption;
switch(pressed)
{
case BUTTON_UP:
selectedOption = !selectedOption ? totalIndexes : selectedOption - 1;
break;
case BUTTON_DOWN:
selectedOption = selectedOption == totalIndexes ? 0 : selectedOption + 1;
break;
case BUTTON_LEFT:
selectedOption = 0;
break;
case BUTTON_RIGHT:
selectedOption = totalIndexes;
break;
default:
continue;
}
if(selectedOption == oldSelectedOption) continue;
//The user moved to a different option, print the old option in white and the new one in red. Only print 'x's if necessary
if(oldSelectedOption < multiOptionsAmount)
{
drawString(multiOptionsText[oldSelectedOption], 10, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
drawCharacter(selected, 10 + multiOptions[oldSelectedOption].posXs[multiOptions[oldSelectedOption].enabled] * SPACING_X, multiOptions[oldSelectedOption].posY, COLOR_WHITE);
}
else
{
u32 singleOldSelected = oldSelectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleOldSelected], 10, singleOptions[singleOldSelected].posY, COLOR_WHITE);
if(singleOptions[singleOldSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleOldSelected].posY, COLOR_WHITE);
}
if(selectedOption < multiOptionsAmount)
drawString(multiOptionsText[selectedOption], 10, multiOptions[selectedOption].posY, COLOR_RED);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
drawString(singleOptionsText[singleSelected], 10, singleOptions[singleSelected].posY, COLOR_RED);
}
}
else
{
//The selected option's status changed, print the 'x's accordingly
if(selectedOption < multiOptionsAmount)
{
u32 oldEnabled = multiOptions[selectedOption].enabled;
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[oldEnabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_BLACK);
multiOptions[selectedOption].enabled = oldEnabled == 3 ? 0 : oldEnabled + 1;
}
else
{
u32 oldEnabled = singleOptions[selectedOption - multiOptionsAmount].enabled;
singleOptions[selectedOption - multiOptionsAmount].enabled = !oldEnabled;
if(oldEnabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[selectedOption - multiOptionsAmount].posY, COLOR_BLACK);
}
}
//In any case, if the current option is enabled (or a multiple choice option is selected) we must display a red 'x'
if(selectedOption < multiOptionsAmount)
drawCharacter(selected, 10 + multiOptions[selectedOption].posXs[multiOptions[selectedOption].enabled] * SPACING_X, multiOptions[selectedOption].posY, COLOR_RED);
else
{
u32 singleSelected = selectedOption - multiOptionsAmount;
if(singleOptions[singleSelected].enabled) drawCharacter(selected, 10 + SPACING_X, singleOptions[singleSelected].posY, COLOR_RED);
}
}
//Preserve the last-used boot options (last 12 bits)
config &= 0x3F;
//Parse and write the new configuration
for(u32 i = 0; i < multiOptionsAmount; i++)
config |= multiOptions[i].enabled << (i * 2 + 6);
for(u32 i = 0; i < singleOptionsAmount; i++)
config |= singleOptions[i].enabled << (i + 16);
fileWrite(&config, configPath, 4);
//Zero the last booted FIRM flag
CFG_BOOTENV = 0;
mcuReboot();
}

19
source/config.h Normal file
View File

@@ -0,0 +1,19 @@
/*
* config.h
* by Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*/
#pragma once
#include "types.h"
#define CFG_BOOTENV (*(vu32 *)0x10010000)
#define CONFIG(a) ((config >> (a + 16)) & 1)
#define MULTICONFIG(a) ((config >> (a * 2 + 6)) & 3)
#define BOOTCONFIG(a, b) ((config >> a) & b)
extern u32 config;
void configureCFW(const char *configPath);

View File

@@ -229,80 +229,173 @@ static void aes(void *dst, const void *src, u32 blockCount, void *iv, u32 mode,
} }
} }
static void sha_wait_idle()
{
while(*REG_SHA_CNT & 1);
}
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++;
}
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 * Nand/FIRM Crypto stuff
****************************************************************/ ****************************************************************/
//Nand key#2 (0x12C10) static u8 nandCTR[0x10],
static const u8 key2[0x10] = { nandSlot;
0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0
};
//Get Nand CTR key static u32 fatStart;
static void getNandCTR(u8 *buf, u32 console){
u8 *addr = (console ? (u8 *)0x080D8BBC : (u8 *)0x080D797C) + 0x0F; //Initialize the CTRNAND crypto
for(u8 keyLen = 0x10; keyLen; keyLen--) void ctrNandInit(void)
*(buf++) = *(addr--); {
u8 cid[0x10];
u8 shaSum[0x20];
sdmmc_get_cid(1, (u32 *)cid);
sha(shaSum, cid, 0x10, SHA_256_MODE);
memcpy(nandCTR, shaSum, 0x10);
if(console)
{
u8 keyY0x5[0x10] = {0x4D, 0x80, 0x4F, 0x4E, 0x99, 0x90, 0x19, 0x46, 0x13, 0xA2, 0x04, 0xAC, 0x58, 0x44, 0x60, 0xBE};
aes_setkey(0x05, keyY0x5, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
nandSlot = 0x05;
fatStart = 0x5CAD7;
}
else
{
nandSlot = 0x04;
fatStart = 0x5CAE5;
}
} }
//Read firm0 from NAND and write to buffer //Read and decrypt from the selected CTRNAND
void nandFirm0(u8 *outbuf, u32 size, u32 console){ u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf)
u8 CTR[0x10]; {
getNandCTR(CTR, console); u8 tmpCTR[0x10];
memcpy(tmpCTR, nandCTR, 0x10);
aes_advctr(tmpCTR, ((sector + fatStart) * 0x200) / AES_BLOCK_SIZE, AES_INPUT_BE | AES_INPUT_NORMAL);
sdmmc_nand_readsectors(0x0B130000 / 0x200, size / 0x200, outbuf); //Read
u32 result;
if(!firmSource)
result = sdmmc_nand_readsectors(sector + fatStart, sectorCount, outbuf);
else
{
sector += emuOffset;
result = sdmmc_sdcard_readsectors(sector + fatStart, sectorCount, outbuf);
}
aes_advctr(CTR, 0x0B130000/0x10, AES_INPUT_BE | AES_INPUT_NORMAL); //Decrypt
aes_use_keyslot(0x06); aes_use_keyslot(nandSlot);
aes(outbuf, outbuf, size / AES_BLOCK_SIZE, CTR, 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;
} }
//Decrypts the N3DS arm9bin //Decrypt a FIRM ExeFS
void decryptArm9Bin(u8 *arm9Section, u32 mode){ void decryptExeFs(u8 *inbuf)
{
u8 *exeFsOffset = inbuf + *(u32 *)(inbuf + 0x1A0) * 0x200;
u32 exeFsSize = *(u32 *)(inbuf + 0x1A4) * 0x200;
u8 ncchCTR[0x10] = {0};
for(u32 i = 0; i < 8; i++)
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);
}
//ARM9Loader replacement
void arm9Loader(u8 *arm9Section, u32 mode)
{
//Firm keys //Firm keys
u8 keyY[0x10]; u8 keyY[0x10];
u8 CTR[0x10]; u8 arm9BinCTR[0x10];
u8 slot = mode ? 0x16 : 0x15; u8 arm9BinSlot = mode ? 0x16 : 0x15;
//Setup keys needed for arm9bin decryption //Setup keys needed for arm9bin decryption
memcpy(keyY, arm9Section + 0x10, 0x10); memcpy(keyY, arm9Section + 0x10, 0x10);
memcpy(CTR, arm9Section + 0x20, 0x10); memcpy(arm9BinCTR, arm9Section + 0x20, 0x10);
u32 size = 0;
//Calculate the size of the ARM9 binary
u32 arm9BinSize = 0;
//http://stackoverflow.com/questions/12791077/atoi-implementation-in-c //http://stackoverflow.com/questions/12791077/atoi-implementation-in-c
for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++) for(u8 *tmp = arm9Section + 0x30; *tmp; tmp++)
size = (size << 3) + (size << 1) + (*tmp) - '0'; arm9BinSize = (arm9BinSize << 3) + (arm9BinSize << 1) + *tmp - '0';
if(mode){ if(mode)
{
const u8 key2[0x10] = {0x42, 0x3F, 0x81, 0x7A, 0x23, 0x52, 0x58, 0x31, 0x6E, 0x75, 0x8E, 0x3A, 0x39, 0x43, 0x2E, 0xD0};
u8 keyX[0x10]; u8 keyX[0x10];
//Set 0x11 to key2 for the arm9bin and misc keys //Set 0x11 to key2 for the arm9bin and misc keys
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(keyX, arm9Section + 0x60, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyX, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
} }
aes_setkey(slot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(arm9BinSlot, keyY, AES_KEYY, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_setiv(CTR, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setiv(arm9BinCTR, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(slot); aes_use_keyslot(arm9BinSlot);
//Decrypt arm9bin //Decrypt arm9bin
aes(arm9Section + 0x800, arm9Section + 0x800, size/AES_BLOCK_SIZE, CTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL); aes(arm9Section + 0x800, arm9Section + 0x800, arm9BinSize / AES_BLOCK_SIZE, arm9BinCTR, AES_CTR_MODE, AES_INPUT_BE | AES_INPUT_NORMAL);
}
//Sets the N3DS 9.6 KeyXs //Set >=9.6 KeyXs
void setKeyXs(u8 *arm9Section){ if(mode)
{
u8 *keyData = arm9Section + 0x89814; u8 keyData[] = {0xDD, 0xDA, 0xA4, 0xC6, 0x2C, 0xC4, 0x50, 0xE9, 0xDA, 0xB6, 0x9B, 0x0D, 0x9D, 0x2A, 0x21, 0x98};
u8 *decKey = keyData + 0x10; u8 decKey[0x10];
//Set keys 0x19..0x1F keyXs //Set keys 0x19..0x1F keyXs
aes_setkey(0x11, key2, AES_KEYNORMAL, AES_INPUT_BE | AES_INPUT_NORMAL);
aes_use_keyslot(0x11); aes_use_keyslot(0x11);
for(u8 slot = 0x19; slot < 0x20; slot++){ for(u8 slot = 0x19; slot < 0x20; slot++)
{
aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0); aes(decKey, keyData, 1, NULL, AES_ECB_DECRYPT_MODE, 0);
aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL); aes_setkey(slot, decKey, AES_KEYX, AES_INPUT_BE | AES_INPUT_NORMAL);
*(keyData + 0xF) += 1; keyData[0xF] += 1;
}
} }
} }

View File

@@ -53,7 +53,37 @@
#define AES_KEYX 1 #define AES_KEYX 1
#define AES_KEYY 2 #define AES_KEYY 2
//NAND/FIRM stuff /**************************SHA****************************/
void nandFirm0(u8 *outbuf, u32 size, u32 console); #define REG_SHA_CNT ((vu32 *)0x1000A000)
void decryptArm9Bin(u8 *arm9Section, u32 mode); #define REG_SHA_BLKCNT ((vu32 *)0x1000A004)
void setKeyXs(u8 *arm9Section); #define REG_SHA_HASH ((vu32 *)0x1000A040)
#define REG_SHA_INFIFO ((vu32 *)0x1000A080)
#define SHA_CNT_STATE 0x00000003
#define SHA_CNT_UNK2 0x00000004
#define SHA_CNT_OUTPUT_ENDIAN 0x00000008
#define SHA_CNT_MODE 0x00000030
#define SHA_CNT_ENABLE 0x00010000
#define SHA_CNT_ACTIVE 0x00020000
#define SHA_HASH_READY 0x00000000
#define SHA_NORMAL_ROUND 0x00000001
#define SHA_FINAL_ROUND 0x00000002
#define SHA_OUTPUT_BE SHA_CNT_OUTPUT_ENDIAN
#define SHA_OUTPUT_LE 0
#define SHA_256_MODE 0
#define SHA_224_MODE 0x00000010
#define SHA_1_MODE 0x00000020
#define SHA_256_HASH_SIZE (256 / 8)
#define SHA_224_HASH_SIZE (224 / 8)
#define SHA_1_HASH_SIZE (160 / 8)
extern u32 emuOffset, console, firmSource;
void ctrNandInit(void);
u32 ctrNandRead(u32 sector, u32 sectorCount, u8 *outbuf);
void decryptExeFs(u8 *inbuf);
void arm9Loader(u8 *arm9Section, u32 mode);

View File

@@ -7,6 +7,7 @@
*/ */
#include "draw.h" #include "draw.h"
#include "screeninit.h"
#include "fs.h" #include "fs.h"
#include "memory.h" #include "memory.h"
#include "font.h" #include "font.h"
@@ -20,59 +21,70 @@ static const struct fb {
u8 *bottom; u8 *bottom;
} *const fb = (struct fb *)0x23FFFE00; } *const fb = (struct fb *)0x23FFFE00;
static int strlen(const char *string){ static inline int strlen(const char *string)
{
char *stringEnd = (char *)string; char *stringEnd = (char *)string;
while(*stringEnd) stringEnd++; while(*stringEnd) stringEnd++;
return stringEnd - string; return stringEnd - string;
} }
void clearScreens(void){ void clearScreens(void)
{
memset32(fb->top_left, 0, 0x46500); memset32(fb->top_left, 0, 0x46500);
memset32(fb->top_right, 0, 0x46500); memset32(fb->top_right, 0, 0x46500);
memset32(fb->bottom, 0, 0x38400); memset32(fb->bottom, 0, 0x38400);
} }
void loadSplash(void){ void loadSplash(void)
clearScreens(); {
initScreens();
//Don't delay boot if no splash image is on the SD //Don't delay boot if no splash image is on the SD
if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) + if(fileRead(fb->top_left, "/aurei/splash.bin", 0x46500) +
fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400)){ fileRead(fb->bottom, "/aurei/splashbottom.bin", 0x38400))
u64 i = 0x1300000; while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func {
u64 i = 0x1400000;
while(--i) __asm("mov r0, r0"); //Less Ghetto sleep func
} }
} }
void drawCharacter(char character, int posX, int posY, u32 color){ void drawCharacter(char character, int posX, int posY, u32 color)
{
u8 *const select = fb->top_left; u8 *const select = fb->top_left;
for(int y = 0; y < 8; y++){ for(int y = 0; y < 8; y++)
{
char charPos = font[character * 8 + y]; char charPos = font[character * 8 + y];
for(int x = 7; x >= 0; x--){ for(int x = 7; x >= 0; x--)
if ((charPos >> x) & 1)
{
int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT; int screenPos = (posX * SCREEN_TOP_HEIGHT * 3 + (SCREEN_TOP_HEIGHT - y - posY - 1) * 3) + (7 - x) * 3 * SCREEN_TOP_HEIGHT;
if ((charPos >> x) & 1) {
select[screenPos] = color >> 16; select[screenPos] = color >> 16;
select[screenPos + 1] = color >> 8; select[screenPos + 1] = color >> 8;
select[screenPos + 2] = color; select[screenPos + 2] = color;
} }
} }
}
} }
int drawString(const char *string, int posX, int posY, u32 color){ int drawString(const char *string, int posX, int posY, u32 color)
int length = strlen(string); {
for(int i = 0, line_i = 0; i < strlen(string); i++, line_i++)
for(int i = 0, line_i = 0; i < length; i++, line_i++){ {
if(string[i] == '\n'){ if(string[i] == '\n')
{
posY += SPACING_Y; posY += SPACING_Y;
line_i = 0; line_i = 0;
i++; i++;
} else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X){ }
else if(line_i >= (SCREEN_TOP_WIDTH - posX) / SPACING_X)
{
// Make sure we never get out of the screen. // Make sure we never get out of the screen.
posY += SPACING_Y; posY += SPACING_Y;
line_i = 2; // Little offset so we know the same string continues. line_i = 2; //Little offset so we know the same string continues.
if(string[i] == ' ') i++; // Spaces at the start look weird if(string[i] == ' ') i++; //Spaces at the start look weird
} }
drawCharacter(string[i], posX + line_i * SPACING_X, posY, color); drawCharacter(string[i], posX + line_i * SPACING_X, posY, color);

View File

@@ -12,6 +12,10 @@
#define SPACING_Y 10 #define SPACING_Y 10
#define SPACING_X 8 #define SPACING_X 8
#define COLOR_TITLE 0xFF9900
#define COLOR_WHITE 0xFFFFFF
#define COLOR_RED 0x0000FF
#define COLOR_BLACK 0x000000
void loadSplash(void); void loadSplash(void);
void clearScreens(void); void clearScreens(void);

View File

@@ -8,32 +8,45 @@
#include "memory.h" #include "memory.h"
#include "fatfs/sdmmc/sdmmc.h" #include "fatfs/sdmmc/sdmmc.h"
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND){ void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND)
u8 *const temp = (u8 *)0x24300000; {
static u8 *const temp = (u8 *)0x24300000;
u32 nandSize = getMMCDevice(0)->total_size; const u32 nandSize = getMMCDevice(0)->total_size;
u32 nandOffset = emuNAND == 1 ? 0 : u32 nandOffset = *emuNAND == 1 ? 0 :
(nandSize > 0x200000 ? 0x400000 : 0x200000); (nandSize > 0x200000 ? 0x400000 : 0x200000);
//Check for RedNAND //Check for RedNAND
if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0){ if(sdmmc_sdcard_readsectors(nandOffset + 1, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset + 1; *off = nandOffset + 1;
*head = nandOffset + 1; *head = nandOffset + 1;
} }
//Check for Gateway emuNAND //Check for Gateway emuNAND
else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0){ else if(sdmmc_sdcard_readsectors(nandOffset + nandSize, 1, temp) == 0)
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC){ {
if(*(u32 *)(temp + 0x100) == NCSD_MAGIC)
{
*off = nandOffset; *off = nandOffset;
*head = nandOffset + nandSize; *head = nandOffset + nandSize;
} }
//Fallback to the first emuNAND if there's no second one
else if(emuNAND == 2) getEmunandSect(off, head, 1); /* Fallback to the first emuNAND if there's no second one,
or to SysNAND if there isn't any */
else
{
(*emuNAND)--;
if(*emuNAND) getEmunandSect(off, head, emuNAND);
}
} }
} }
} }
u32 getSDMMC(u8 *pos, u32 size){ u32 getSDMMC(u8 *pos, u32 size)
{
//Look for struct code //Look for struct code
const u8 pattern[] = {0x21, 0x20, 0x18, 0x20}; const u8 pattern[] = {0x21, 0x20, 0x18, 0x20};
const u8 *off = memsearch(pos, pattern, size, 4) - 1; const u8 *off = memsearch(pos, pattern, size, 4) - 1;
@@ -41,7 +54,8 @@ u32 getSDMMC(u8 *pos, u32 size){
return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E); return *(u32 *)(off + 0x0A) + *(u32 *)(off + 0x0E);
} }
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff)
{
//Look for read/write code //Look for read/write code
const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05}; const u8 pattern[] = {0x1E, 0x00, 0xC8, 0x05};
@@ -49,14 +63,16 @@ void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff){
*writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6; *writeOff = (u32)memsearch((u8 *)(*readOff + 0xA), pattern, 0x100, 4) - 6;
} }
u32 *getMPU(u8 *pos, u32 size){ u32 *getMPU(u8 *pos, u32 size)
{
//Look for MPU pattern //Look for MPU pattern
const u8 pattern[] = {0x03, 0x00, 0x24, 0x00}; const u8 pattern[] = {0x03, 0x00, 0x24, 0x00};
return (u32 *)memsearch(pos, pattern, size, 4); return (u32 *)memsearch(pos, pattern, size, 4);
} }
void *getEmuCode(u8 *proc9Offset){ void *getEmuCode(u8 *proc9Offset)
{
const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00}; const u8 pattern[] = {0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0x00};
//Looking for the last free space before Process9 //Looking for the last free space before Process9

View File

@@ -10,7 +10,7 @@
#define NCSD_MAGIC (0x4453434E) #define NCSD_MAGIC (0x4453434E)
void getEmunandSect(u32 *off, u32 *head, u32 emuNAND); void getEmunandSect(u32 *off, u32 *head, u32 *emuNAND);
u32 getSDMMC(u8 *pos, u32 size); u32 getSDMMC(u8 *pos, u32 size);
void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff); void getEmuRW(u8 *pos, u32 size, u32 *readOff, u32 *writeOff);
u32 *getMPU(u8 *pos, u32 size); u32 *getMPU(u8 *pos, u32 size);

View File

@@ -10,6 +10,9 @@
#include "diskio.h" /* FatFs lower layer API */ #include "diskio.h" /* FatFs lower layer API */
#include "sdmmc/sdmmc.h" #include "sdmmc/sdmmc.h"
/* Definitions of physical drive number for each media */
#define SDCARD 0
#define CTRNAND 1
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Get Drive Status */ /* Get Drive Status */
@@ -34,7 +37,16 @@ DSTATUS disk_initialize (
BYTE pdrv /* Physical drive nmuber to identify the drive */ BYTE pdrv /* Physical drive nmuber to identify the drive */
) )
{ {
switch(pdrv)
{
case SDCARD:
sdmmc_sdcard_init(); sdmmc_sdcard_init();
break;
case CTRNAND:
ctrNandInit();
break;
}
return RES_OK; return RES_OK;
} }
@@ -52,8 +64,16 @@ DRESULT disk_read (
UINT count /* Number of sectors to read */ UINT count /* Number of sectors to read */
) )
{ {
if (sdmmc_sdcard_readsectors(sector, count, buff)) { switch(pdrv)
{
case SDCARD:
if(sdmmc_sdcard_readsectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
break;
case CTRNAND:
if(ctrNandRead(sector, count, (BYTE *)buff))
return RES_PARERR;
break;
} }
return RES_OK; return RES_OK;
@@ -74,9 +94,8 @@ DRESULT disk_write (
UINT count /* Number of sectors to write */ UINT count /* Number of sectors to write */
) )
{ {
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) { if(pdrv == SDCARD && sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff))
return RES_PARERR; return RES_PARERR;
}
return RES_OK; return RES_OK;
} }

547
source/fatfs/ff.c Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*----------------------------------------------------------------------------/ /*----------------------------------------------------------------------------/
/ FatFs - FAT file system module R0.11 (C)ChaN, 2015 / FatFs - FAT file system module R0.11a (C)ChaN, 2015 /
/-----------------------------------------------------------------------------/ /-----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@@ -26,7 +26,7 @@
---------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
#if _FATFS != 32020 /* Revision ID */ #if _FATFS != 64180 /* Revision ID */
#error Wrong include file (ff.h). #error Wrong include file (ff.h).
#endif #endif
@@ -83,7 +83,7 @@ typedef struct {
/* DBCS code ranges and SBCS extend character conversion table */ /* DBCS code ranges and SBCS upper conversion tables */
#if _CODE_PAGE == 932 /* Japanese Shift-JIS */ #if _CODE_PAGE == 932 /* Japanese Shift-JIS */
#define _DF1S 0x81 /* DBC 1st byte range 1 start */ #define _DF1S 0x81 /* DBC 1st byte range 1 start */
@@ -121,211 +121,192 @@ typedef struct {
#define _DS2S 0xA1 #define _DS2S 0xA1
#define _DS2E 0xFE #define _DS2E 0xFE
#elif _CODE_PAGE == 437 /* U.S. (OEM) */ #elif _CODE_PAGE == 437 /* U.S. */
#define _DF1S 0 #define _DF1S 0
/*#define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F,0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}*/ 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
static #elif _CODE_PAGE == 720 /* Arabic */
const unsigned short Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7,
0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9,
0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA,
0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556,
0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F,
0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B,
0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4,
0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248,
0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
WCHAR ff_convert( /* Converted character, Returns zero on error */
WCHAR src, /* Character code to be converted */
UINT dir /* 0: Unicode to OEMCP, 1: OEMCP to Unicode */
)
{
WCHAR c;
if(src < 0x80)
{ /* ASCII */
c = src;
}
else
{
if(dir)
{ /* OEMCP to Unicode */
c = (src >= 0x100) ? 0 : Tbl[src - 0x80];
}
else
{ /* Unicode to OEMCP */
for(c = 0; c < 0x80; c++)
{
if(src == Tbl[c])
break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper(WCHAR chr)
{
if(chr >= 'a' && chr <= 'z')
return (chr - 32);
else
return chr;
}
#elif _CODE_PAGE == 720 /* Arabic (OEM) */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x45,0x41,0x84,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x49,0x49,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 737 /* Greek (OEM) */ #elif _CODE_PAGE == 737 /* Greek */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x93,0x94,0x95,0x96,0x97,0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87, \
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, \ 0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0xAA,0x92,0x93,0x94,0x95,0x96, \
0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xE7,0xE8,0xF1,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x97,0xEA,0xEB,0xEC,0xE4,0xED,0xEE,0xEF,0xF5,0xF0,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 775 /* Baltic (OEM) */ #elif _CODE_PAGE == 771 /* KBL */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 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,0xDC,0xDE,0xDE, \
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,0xF8,0xFA,0xFA,0xFC,0xFC,0xFE,0xFF}
#elif _CODE_PAGE == 850 /* Multilingual Latin 1 (OEM) */ #elif _CODE_PAGE == 775 /* Baltic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x91,0xA0,0x8E,0x95,0x8F,0x80,0xAD,0xED,0x8A,0x8A,0xA1,0x8D,0x8E,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0xE2,0x99,0x95,0x96,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xA0,0xA1,0xE0,0xA3,0xA3,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xA5,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE3,0xE8,0xE8,0xEA,0xEA,0xEE,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 852 /* Latin 2 (OEM) */ #elif _CODE_PAGE == 850 /* Latin 1 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F,0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0x9F, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x41,0x43,0x45,0x45,0x45,0x49,0x49,0x49,0x41,0x41, \
0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \ 0x45,0x92,0x92,0x4F,0x4F,0x4F,0x55,0x55,0x59,0x4F,0x55,0x4F,0x9C,0x4F,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0x41,0x41,0x41,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0x41,0x41,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0x45,0x45,0x45,0x49,0x49,0x49,0x49,0xD9,0xDA,0xDB,0xDC,0xDD,0x49,0xDF, \
0x4F,0xE1,0x4F,0x4F,0x4F,0x4F,0xE6,0xE8,0xE8,0x55,0x55,0x55,0x59,0x59,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 855 /* Cyrillic (OEM) */ #elif _CODE_PAGE == 852 /* Latin 2 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F,0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xDE,0x8F,0x80,0x9D,0xD3,0x8A,0x8A,0xD7,0x8D,0x8E,0x8F, \
0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \ 0x90,0x91,0x91,0xE2,0x99,0x95,0x95,0x97,0x97,0x99,0x9A,0x9B,0x9B,0x9D,0x9E,0xAC, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \ 0xB5,0xD6,0xE0,0xE9,0xA4,0xA4,0xA6,0xA6,0xA8,0xA8,0xAA,0x8D,0xAC,0xB8,0xAE,0xAF, \
0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBD,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC6,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0xD2,0xD3,0xD2,0xD5,0xD6,0xD7,0xB7,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE3,0xD5,0xE6,0xE6,0xE8,0xE9,0xE8,0xEB,0xED,0xED,0xDD,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xEB,0xFC,0xFC,0xFE,0xFF}
#elif _CODE_PAGE == 857 /* Turkish (OEM) */ #elif _CODE_PAGE == 855 /* Cyrillic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x98,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \ #define _EXCVT {0x81,0x81,0x83,0x83,0x85,0x85,0x87,0x87,0x89,0x89,0x8B,0x8B,0x8D,0x8D,0x8F,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x91,0x91,0x93,0x93,0x95,0x95,0x97,0x97,0x99,0x99,0x9B,0x9B,0x9D,0x9D,0x9F,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xA1,0xA1,0xA3,0xA3,0xA5,0xA5,0xA7,0xA7,0xA9,0xA9,0xAB,0xAB,0xAD,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0x59,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB6,0xB6,0xB8,0xB8,0xB9,0xBA,0xBB,0xBC,0xBE,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD1,0xD1,0xD3,0xD3,0xD5,0xD5,0xD7,0xD7,0xDD,0xD9,0xDA,0xDB,0xDC,0xDD,0xE0,0xDF, \
0xE0,0xE2,0xE2,0xE4,0xE4,0xE6,0xE6,0xE8,0xE8,0xEA,0xEA,0xEC,0xEC,0xEE,0xEE,0xEF, \
0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF8,0xFA,0xFA,0xFC,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 858 /* Multilingual Latin 1 + Euro (OEM) */ #elif _CODE_PAGE == 857 /* Turkish */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0xDE,0x8E,0x8F,0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x59,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0xB6,0x8E,0xB7,0x8F,0x80,0xD2,0xD3,0xD4,0xD8,0xD7,0x49,0x8E,0x8F, \
0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0xE2,0x99,0xE3,0xEA,0xEB,0x98,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9E, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD1,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0xB5,0xD6,0xE0,0xE9,0xA5,0xA5,0xA6,0xA6,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE7,0xE9,0xEA,0xEB,0xED,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC7,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0x49,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE5,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xDE,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 862 /* Hebrew (OEM) */ #elif _CODE_PAGE == 860 /* Portuguese */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x8F,0x8E,0x91,0x86,0x80,0x89,0x89,0x92,0x8B,0x8C,0x98,0x8E,0x8F, \
0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0x21,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x8C,0x99,0xA9,0x96,0x9D,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
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, \ 0x86,0x8B,0x9F,0x96,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 866 /* Russian (OEM) */ #elif _CODE_PAGE == 861 /* Icelandic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x8B,0x8B,0x8D,0x8E,0x8F, \
0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x8D,0x55,0x97,0x97,0x99,0x9A,0x9D,0x9C,0x9D,0x9E,0x9F, \
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, \ 0xA4,0xA5,0xA6,0xA7,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F,0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 874 /* Thai (OEM, Windows) */ #elif _CODE_PAGE == 862 /* Hebrew */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1250 /* Central Europe (Windows) */ #elif _CODE_PAGE == 863 /* Canadian-French */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ #define _EXCVT {0x43,0x55,0x45,0x41,0x41,0x41,0x86,0x43,0x45,0x45,0x45,0x49,0x49,0x8D,0x41,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xA3,0xB4,0xB5,0xB6,0xB7,0xB8,0xA5,0xAA,0xBB,0xBC,0xBD,0xBC,0xAF, \ 0x45,0x45,0x45,0x4F,0x45,0x49,0x55,0x55,0x98,0x4F,0x55,0x9B,0x9C,0x55,0x55,0x9F, \
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, \ 0xA0,0xA1,0x4F,0x55,0xA4,0xA5,0xA6,0xA7,0x49,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1251 /* Cyrillic (Windows) */ #elif _CODE_PAGE == 864 /* Arabic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x82,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x80,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x8D,0x8E,0x8F, \ #define _EXCVT {0x80,0x9A,0x45,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0xA0,0xA2,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB2,0xA5,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xA3,0xBD,0xBD,0xAF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1252 /* Latin 1 (Windows) */ #elif _CODE_PAGE == 865 /* Nordic */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0xAd,0x9B,0x8C,0x9D,0xAE,0x9F, \ #define _EXCVT {0x80,0x9A,0x90,0x41,0x8E,0x41,0x8F,0x80,0x45,0x45,0x45,0x49,0x49,0x49,0x8E,0x8F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x92,0x92,0x4F,0x99,0x4F,0x55,0x55,0x59,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \ 0x41,0x49,0x4F,0x55,0xA5,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF, \
0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1253 /* Greek (Windows) */ #elif _CODE_PAGE == 866 /* Russian */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xA2,0xB8,0xB9,0xBA, \ 0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xE0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xFB,0xBC,0xFD,0xBF,0xFF} 0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF, \
0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x90,0x91,0x92,0x93,0x9d,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xF0,0xF0,0xF2,0xF2,0xF4,0xF4,0xF6,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1254 /* Turkish (Windows) */ #elif _CODE_PAGE == 869 /* Greek 2 */
#define _DF1S 0 #define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x8A,0x9B,0x8C,0x9D,0x9E,0x9F, \ #define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \ 0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x86,0x9C,0x8D,0x8F,0x90, \
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, \ 0x91,0x90,0x92,0x95,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x9F} 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, \
#elif _CODE_PAGE == 1255 /* Hebrew (Windows) */ 0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xA4,0xA5,0xA6,0xD9,0xDA,0xDB,0xDC,0xA7,0xA8,0xDF, \
#define _DF1S 0 0xA9,0xAA,0xAC,0xAD,0xB5,0xB6,0xB7,0xB8,0xBD,0xBE,0xC6,0xC7,0xCF,0xCF,0xD0,0xEF, \
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \ 0xF0,0xF1,0xD1,0xD2,0xD3,0xF5,0xD4,0xF7,0xF8,0xF9,0xD5,0x96,0x95,0x98,0xFE,0xFF}
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF7,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1256 /* Arabic (Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x8C,0x9D,0x9E,0x9F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0x41,0xE1,0x41,0xE3,0xE4,0xE5,0xE6,0x43,0x45,0x45,0x45,0x45,0xEC,0xED,0x49,0x49,0xF0,0xF1,0xF2,0xF3,0x4F,0xF5,0xF6,0xF7,0xF8,0x55,0xFA,0x55,0x55,0xFD,0xFE,0xFF}
#elif _CODE_PAGE == 1257 /* Baltic (Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0x9C,0x9D,0x9E,0x9F, \
0xA0,0xA1,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xA8,0xB9,0xAA,0xBB,0xBC,0xBD,0xBE,0xAF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xFF}
#elif _CODE_PAGE == 1258 /* Vietnam (OEM, Windows) */
#define _DF1S 0
#define _EXCVT {0x80,0x81,0x82,0x83,0x84,0x85,0x86,0x87,0x88,0x89,0x8A,0x8B,0x8C,0x8D,0x8E,0x8F,0x90,0x91,0x92,0x93,0x94,0x95,0x96,0x97,0x98,0x99,0x9A,0x9B,0xAC,0x9D,0x9E,0x9F, \
0xA0,0x21,0xA2,0xA3,0xA4,0xA5,0xA6,0xA7,0xA8,0xA9,0xAA,0xAB,0xAC,0xAD,0xAE,0xAF,0xB0,0xB1,0xB2,0xB3,0xB4,0xB5,0xB6,0xB7,0xB8,0xB9,0xBA,0xBB,0xBC,0xBD,0xBE,0xBF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0xDF, \
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xEC,0xCD,0xCE,0xCF,0xD0,0xD1,0xF2,0xD3,0xD4,0xD5,0xD6,0xF7,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xFE,0x9F}
#elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */ #elif _CODE_PAGE == 1 /* ASCII (for only non-LFN cfg) */
#if _USE_LFN #if _USE_LFN
@@ -377,12 +358,12 @@ WCHAR ff_wtoupper(WCHAR chr)
/* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */ /* FAT sub-type boundaries (Differ from specs but correct for real DOS/Windows) */
#define MIN_FAT16 4086U /* Minimum number of clusters as FAT16 */ #define MIN_FAT16 4086U /* Minimum number of clusters of FAT16 */
#define MIN_FAT32 65526U /* Minimum number of clusters as FAT32 */ #define MIN_FAT32 65526U /* Minimum number of clusters of FAT32 */
/* FatFs refers the members in the FAT structures as byte array instead of /* FatFs refers the members in the FAT structures as byte array instead of
/ structure member because the structure is not binary compatible between / structure members because the structure is not binary compatible between
/ different platforms */ / different platforms */
#define BS_jmpBoot 0 /* x86 jump instruction (3) */ #define BS_jmpBoot 0 /* x86 jump instruction (3) */
@@ -399,7 +380,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_NumHeads 26 /* Number of heads (2) */ #define BPB_NumHeads 26 /* Number of heads (2) */
#define BPB_HiddSec 28 /* Number of special hidden sectors (4) */ #define BPB_HiddSec 28 /* Number of special hidden sectors (4) */
#define BPB_TotSec32 32 /* Volume size [sector] (4) */ #define BPB_TotSec32 32 /* Volume size [sector] (4) */
#define BS_DrvNum 36 /* Physical drive number (2) */ #define BS_DrvNum 36 /* Physical drive number (1) */
#define BS_NTres 37 /* Error flag (1) */
#define BS_BootSig 38 /* Extended boot signature (1) */ #define BS_BootSig 38 /* Extended boot signature (1) */
#define BS_VolID 39 /* Volume serial number (4) */ #define BS_VolID 39 /* Volume serial number (4) */
#define BS_VolLab 43 /* Volume label (8) */ #define BS_VolLab 43 /* Volume label (8) */
@@ -410,7 +392,8 @@ WCHAR ff_wtoupper(WCHAR chr)
#define BPB_RootClus 44 /* Root directory first cluster (4) */ #define BPB_RootClus 44 /* Root directory first cluster (4) */
#define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */ #define BPB_FSInfo 48 /* Offset of FSINFO sector (2) */
#define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */ #define BPB_BkBootSec 50 /* Offset of backup boot sector (2) */
#define BS_DrvNum32 64 /* Physical drive number (2) */ #define BS_DrvNum32 64 /* Physical drive number (1) */
#define BS_NTres32 65 /* Error flag (1) */
#define BS_BootSig32 66 /* Extended boot signature (1) */ #define BS_BootSig32 66 /* Extended boot signature (1) */
#define BS_VolID32 67 /* Volume serial number (4) */ #define BS_VolID32 67 /* Volume serial number (4) */
#define BS_VolLab32 71 /* Volume label (8) */ #define BS_VolLab32 71 /* Volume label (8) */
@@ -438,7 +421,7 @@ WCHAR ff_wtoupper(WCHAR chr)
#define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */ #define LDIR_Ord 0 /* LFN entry order and LLE flag (1) */
#define LDIR_Attr 11 /* LFN attribute (1) */ #define LDIR_Attr 11 /* LFN attribute (1) */
#define LDIR_Type 12 /* LFN type (1) */ #define LDIR_Type 12 /* LFN type (1) */
#define LDIR_Chksum 13 /* Sum of corresponding SFN entry */ #define LDIR_Chksum 13 /* Checksum of corresponding SFN entry */
#define LDIR_FstClusLO 26 /* Must be zero (0) */ #define LDIR_FstClusLO 26 /* Must be zero (0) */
#define SZ_DIRE 32 /* Size of a directory entry */ #define SZ_DIRE 32 /* Size of a directory entry */
#define LLEF 0x40 /* Last long entry flag in LDIR_Ord */ #define LLEF 0x40 /* Last long entry flag in LDIR_Ord */
@@ -448,12 +431,15 @@ WCHAR ff_wtoupper(WCHAR chr)
/*------------------------------------------------------------*/ /*--------------------------------------------------------------------------
/* Module private work area */
/*------------------------------------------------------------*/ Module Private Work Area
/* Remark: Uninitialized variables with static duration are
/ guaranteed zero/null at start-up. If not, either the linker ---------------------------------------------------------------------------*/
/ or start-up routine being used is out of ANSI-C standard.
/* Remark: Uninitialized variables with static duration are guaranteed
/ zero/null at start-up. If not, either the linker or start-up routine
/ being used is not compliance with ANSI-C standard.
*/ */
#if _VOLUMES < 1 || _VOLUMES > 9 #if _VOLUMES < 1 || _VOLUMES > 9
@@ -497,7 +483,7 @@ static WCHAR LfnBuf[_MAX_LFN + 1];
#endif #endif
#ifdef _EXCVT #ifdef _EXCVT
static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for extended characters */ static const BYTE ExCvt[] = _EXCVT; /* Upper conversion table for SBCS extended characters */
#endif #endif
@@ -711,7 +697,7 @@ void clear_lock ( /* Clear lock entries of the volume */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_window ( FRESULT sync_window ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@@ -740,7 +726,7 @@ FRESULT sync_window (
static static
FRESULT move_window ( FRESULT move_window ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD sector /* Sector number to make appearance in the fs->win[] */ DWORD sector /* Sector number to make appearance in the fs->win[] */
) )
@@ -771,7 +757,7 @@ FRESULT move_window (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */ FRESULT sync_fs ( /* FR_OK:succeeded, !=0:error */
FATFS* fs /* File system object */ FATFS* fs /* File system object */
) )
{ {
@@ -780,16 +766,16 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
res = sync_window(fs); res = sync_window(fs);
if (res == FR_OK) { if (res == FR_OK) {
/* Update FSINFO sector if needed */ /* Update FSInfo sector if needed */
if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) { if (fs->fs_type == FS_FAT32 && fs->fsi_flag == 1) {
/* Create FSINFO structure */ /* Create FSInfo structure */
mem_set(fs->win, 0, SS(fs)); mem_set(fs->win, 0, SS(fs));
ST_WORD(fs->win + BS_55AA, 0xAA55); ST_WORD(fs->win + BS_55AA, 0xAA55);
ST_DWORD(fs->win + FSI_LeadSig, 0x41615252); ST_DWORD(fs->win + FSI_LeadSig, 0x41615252);
ST_DWORD(fs->win + FSI_StrucSig, 0x61417272); ST_DWORD(fs->win + FSI_StrucSig, 0x61417272);
ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust); ST_DWORD(fs->win + FSI_Free_Count, fs->free_clust);
ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust); ST_DWORD(fs->win + FSI_Nxt_Free, fs->last_clust);
/* Write it into the FSINFO sector */ /* Write it into the FSInfo sector */
fs->winsect = fs->volbase + 1; fs->winsect = fs->volbase + 1;
disk_write(fs->drv, fs->win, fs->winsect, 1); disk_write(fs->drv, fs->win, fs->winsect, 1);
fs->fsi_flag = 0; fs->fsi_flag = 0;
@@ -811,7 +797,7 @@ FRESULT sync_fs ( /* FR_OK: successful, FR_DISK_ERR: failed */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */ DWORD clust2sect ( /* !=0:Sector number, 0:Failed (invalid cluster#) */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to be converted */ DWORD clst /* Cluster# to be converted */
) )
@@ -829,7 +815,7 @@ static DWORD clust2sect ( /* !=0: Sector number, 0: Failed - invalid cluster# */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */ DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF:Cluster status */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* FAT index number (cluster number) to get the value */ DWORD clst /* FAT index number (cluster number) to get the value */
) )
@@ -839,7 +825,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
DWORD val; DWORD val;
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
val = 1; /* Internal error */ val = 1; /* Internal error */
} else { } else {
@@ -884,7 +870,7 @@ static DWORD get_fat ( /* 0xFFFFFFFF:Disk error, 1:Internal error, 2..0x0FFFFFFF
/* Hidden API for hacks and disk tools */ /* Hidden API for hacks and disk tools */
#if !_FS_READONLY #if !_FS_READONLY
static FRESULT put_fat ( FRESULT put_fat ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst, /* FAT index number (cluster number) to be changed */ DWORD clst, /* FAT index number (cluster number) to be changed */
DWORD val /* New value to be set to the entry */ DWORD val /* New value to be set to the entry */
@@ -895,7 +881,7 @@ static FRESULT put_fat (
FRESULT res; FRESULT res;
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@@ -948,7 +934,7 @@ static FRESULT put_fat (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT remove_chain ( FRESULT remove_chain ( /* FR_OK(0):succeeded, !=0:error */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to remove a chain from */ DWORD clst /* Cluster# to remove a chain from */
) )
@@ -959,7 +945,7 @@ FRESULT remove_chain (
DWORD scl = clst, ecl = clst, rt[2]; DWORD scl = clst, ecl = clst, rt[2];
#endif #endif
if (clst < 2 || clst >= fs->n_fatent) { /* Check range */ if (clst < 2 || clst >= fs->n_fatent) { /* Check if in valid range */
res = FR_INT_ERR; res = FR_INT_ERR;
} else { } else {
@@ -1003,7 +989,7 @@ FRESULT remove_chain (
static static
DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */ DWORD create_chain ( /* 0:No free cluster, 1:Internal error, 0xFFFFFFFF:Disk error, >=2:New cluster# */
FATFS* fs, /* File system object */ FATFS* fs, /* File system object */
DWORD clst /* Cluster# to stretch. 0 means create a new chain. */ DWORD clst /* Cluster# to stretch, 0:Create a new chain */
) )
{ {
DWORD cs, ncl, scl; DWORD cs, ncl, scl;
@@ -1091,7 +1077,7 @@ DWORD clmt_clust ( /* <2:Error, >=2:Cluster number */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_sdi ( FRESULT dir_sdi ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to directory object */ DIR* dp, /* Pointer to directory object */
UINT idx /* Index of directory table */ UINT idx /* Index of directory table */
) )
@@ -1139,7 +1125,7 @@ FRESULT dir_sdi (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */ FRESULT dir_next ( /* FR_OK(0):succeeded, FR_NO_FILE:End of table, FR_DENIED:Could not stretch */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
int stretch /* 0: Do not stretch table, 1: Stretch table if needed */ int stretch /* 0: Do not stretch table, 1: Stretch table if needed */
) )
@@ -1210,7 +1196,7 @@ FRESULT dir_next ( /* FR_OK:Succeeded, FR_NO_FILE:End of table, FR_DENIED:Could
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT dir_alloc ( FRESULT dir_alloc ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
UINT nent /* Number of contiguous entries to allocate (1-21) */ UINT nent /* Number of contiguous entries to allocate (1-21) */
) )
@@ -1246,9 +1232,9 @@ FRESULT dir_alloc (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
DWORD ld_clust ( DWORD ld_clust ( /* Returns the top cluster value of the SFN entry */
FATFS* fs, /* Pointer to the fs object */ FATFS* fs, /* Pointer to the fs object */
BYTE* dir /* Pointer to the directory entry */ const BYTE* dir /* Pointer to the SFN entry */
) )
{ {
DWORD cl; DWORD cl;
@@ -1264,7 +1250,7 @@ DWORD ld_clust (
#if !_FS_READONLY #if !_FS_READONLY
static static
void st_clust ( void st_clust (
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the SFN entry */
DWORD cl /* Value to be set */ DWORD cl /* Value to be set */
) )
{ {
@@ -1285,27 +1271,29 @@ const BYTE LfnOfs[] = {1,3,5,7,9,14,16,18,20,22,24,28,30}; /* Offset of LFN char
static static
int cmp_lfn ( /* 1:Matched, 0:Not matched */ int cmp_lfn ( /* 1:matched, 0:not matched */
WCHAR* lfnbuf, /* Pointer to the LFN to be compared */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer to be compared */
BYTE* dir /* Pointer to the directory entry containing a part of LFN */ BYTE* dir /* Pointer to the directory entry containing the part of LFN */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; WCHAR wc, uc;
i = ((dir[LDIR_Ord] & ~LLEF) - 1) * 13; /* Get offset in the LFN buffer */ if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
s = 0; wc = 1;
do { i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */
if (wc) { /* Last character has not been processed */ for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
wc = ff_wtoupper(uc); /* Convert it to upper case */ uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
if (i >= _MAX_LFN || wc != ff_wtoupper(lfnbuf[i++])) /* Compare it */ if (wc) {
if (i >= _MAX_LFN || ff_wtoupper(uc) != ff_wtoupper(lfnbuf[i++])) /* Compare it */
return 0; /* Not matched */ return 0; /* Not matched */
wc = uc;
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} while (++s < 13); /* Repeat until all characters in the entry are checked */ }
if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */ if ((dir[LDIR_Ord] & LLEF) && wc && lfnbuf[i]) /* Last segment matched but different length */
return 0; return 0;
@@ -1316,34 +1304,35 @@ int cmp_lfn ( /* 1:Matched, 0:Not matched */
#if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2 #if _FS_MINIMIZE <= 1 || _USE_LABEL || _FS_RPATH >= 2
static static
int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */ int pick_lfn ( /* 1:succeeded, 0:buffer overflow or invalid LFN entry */
WCHAR* lfnbuf, /* Pointer to the Unicode-LFN buffer */ WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir /* Pointer to the directory entry */ BYTE* dir /* Pointer to the LFN entry */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc, uc; WCHAR wc, uc;
if (LD_WORD(dir + LDIR_FstClusLO) != 0) return 0; /* Check LDIR_FstClusLO */
i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */ i = ((dir[LDIR_Ord] & 0x3F) - 1) * 13; /* Offset in the LFN buffer */
s = 0; wc = 1; for (wc = 1, s = 0; s < 13; s++) { /* Process all characters in the entry */
do { uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character */
uc = LD_WORD(dir + LfnOfs[s]); /* Pick an LFN character from the entry */ if (wc) {
if (wc) { /* Last character has not been processed */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i++] = wc = uc; /* Store it */ lfnbuf[i++] = wc = uc; /* Store it */
} else { } else {
if (uc != 0xFFFF) return 0; /* Check filler */ if (uc != 0xFFFF) return 0; /* Check filler */
} }
} while (++s < 13); /* Read all character in the entry */ }
if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */ if (dir[LDIR_Ord] & LLEF) { /* Put terminator if it is the last LFN part */
if (i >= _MAX_LFN) return 0; /* Buffer overflow? */ if (i >= _MAX_LFN) return 0; /* Buffer overflow? */
lfnbuf[i] = 0; lfnbuf[i] = 0;
} }
return 1; return 1; /* The part of LFN is valid */
} }
#endif #endif
@@ -1351,22 +1340,22 @@ int pick_lfn ( /* 1:Succeeded, 0:Buffer overflow */
#if !_FS_READONLY #if !_FS_READONLY
static static
void fit_lfn ( void fit_lfn (
const WCHAR* lfnbuf, /* Pointer to the LFN buffer */ const WCHAR* lfnbuf, /* Pointer to the LFN working buffer */
BYTE* dir, /* Pointer to the directory entry */ BYTE* dir, /* Pointer to the LFN entry to be processed */
BYTE ord, /* LFN order (1-20) */ BYTE ord, /* LFN order (1-20) */
BYTE sum /* SFN sum */ BYTE sum /* Checksum of the corresponding SFN */
) )
{ {
UINT i, s; UINT i, s;
WCHAR wc; WCHAR wc;
dir[LDIR_Chksum] = sum; /* Set check sum */ dir[LDIR_Chksum] = sum; /* Set checksum */
dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */ dir[LDIR_Attr] = AM_LFN; /* Set attribute. LFN entry */
dir[LDIR_Type] = 0; dir[LDIR_Type] = 0;
ST_WORD(dir + LDIR_FstClusLO, 0); ST_WORD(dir + LDIR_FstClusLO, 0);
i = (ord - 1) * 13; /* Get offset in the LFN buffer */ i = (ord - 1) * 13; /* Get offset in the LFN working buffer */
s = wc = 0; s = wc = 0;
do { do {
if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */ if (wc != 0xFFFF) wc = lfnbuf[i++]; /* Get an effective character */
@@ -1443,7 +1432,7 @@ void gen_numname (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Calculate sum of an SFN */ /* Calculate checksum of an SFN entry */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if _USE_LFN #if _USE_LFN
static static
@@ -1467,7 +1456,7 @@ BYTE sum_sfn (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT dir_find ( FRESULT dir_find ( /* FR_OK(0):succeeded, !=0:error */
DIR* dp /* Pointer to the directory object linked to the file name */ DIR* dp /* Pointer to the directory object linked to the file name */
) )
{ {
@@ -1587,7 +1576,7 @@ FRESULT dir_read (
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY #if !_FS_READONLY
static static
FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many SFN collision, FR_DISK_ERR:Disk error */ 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 */ DIR* dp /* Target directory with object name to be created */
) )
{ {
@@ -1627,7 +1616,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
if (res == FR_OK && --nent) { /* Set LFN entry if needed */ if (res == FR_OK && --nent) { /* Set LFN entry if needed */
res = dir_sdi(dp, dp->index - nent); res = dir_sdi(dp, dp->index - nent);
if (res == FR_OK) { if (res == FR_OK) {
sum = sum_sfn(dp->fn); /* Sum value of the SFN tied to the LFN */ sum = sum_sfn(dp->fn); /* Checksum value of the SFN tied to the LFN */
do { /* Store LFN entries in bottom first */ do { /* Store LFN entries in bottom first */
res = move_window(dp->fs, dp->sect); res = move_window(dp->fs, dp->sect);
if (res != FR_OK) break; if (res != FR_OK) break;
@@ -1665,7 +1654,7 @@ FRESULT dir_register ( /* FR_OK:Successful, FR_DENIED:No free entry or too many
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
#if !_FS_READONLY && !_FS_MINIMIZE #if !_FS_READONLY && !_FS_MINIMIZE
static static
FRESULT dir_remove ( /* FR_OK: Successful, FR_DISK_ERR: A disk error */ FRESULT dir_remove ( /* FR_OK:Succeeded, FR_DISK_ERR:A disk error */
DIR* dp /* Directory object pointing the entry to be removed */ DIR* dp /* Directory object pointing the entry to be removed */
) )
{ {
@@ -1804,7 +1793,7 @@ WCHAR get_achar ( /* Get a character and advances ptr 1 or 2 */
static static
int pattern_matching ( /* Return value: 0:mismatched, 1:matched */ int pattern_matching ( /* 0:mismatched, 1:matched */
const TCHAR* pat, /* Matching pattern */ const TCHAR* pat, /* Matching pattern */
const TCHAR* nam, /* String to be tested */ const TCHAR* nam, /* String to be tested */
int skip, /* Number of pre-skip chars (number of ?s) */ int skip, /* Number of pre-skip chars (number of ?s) */
@@ -1848,11 +1837,11 @@ int pattern_matching ( /* Return value: 0:mismatched, 1:matched */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
/* Pick a segment and create the object name in directory form */ /* Pick a top segment and create the object name in directory form */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
FRESULT create_name ( FRESULT create_name ( /* FR_OK: successful, FR_INVALID_NAME: could not create */
DIR* dp, /* Pointer to the directory object */ DIR* dp, /* Pointer to the directory object */
const TCHAR** path /* Pointer to pointer to the segment in the path string */ const TCHAR** path /* Pointer to pointer to the segment in the path string */
) )
@@ -1890,22 +1879,21 @@ FRESULT create_name (
*path = &p[si]; /* Return pointer to the next segment */ *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 path */
#if _FS_RPATH #if _FS_RPATH
if ((di == 1 && lfn[di - 1] == '.') || /* Is this a dot entry? */ if ((di == 1 && lfn[di - 1] == '.') ||
(di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { (di == 2 && lfn[di - 1] == '.' && lfn[di - 2] == '.')) { /* Is this segment a dot entry? */
lfn[di] = 0; lfn[di] = 0;
for (i = 0; i < 11; i++) for (i = 0; i < 11; i++) /* Create dot name for SFN entry */
dp->fn[i] = (i < di) ? '.' : ' '; dp->fn[i] = (i < di) ? '.' : ' ';
dp->fn[i] = cf | NS_DOT; /* This is a dot entry */ dp->fn[i] = cf | NS_DOT; /* This is a dot entry */
return FR_OK; return FR_OK;
} }
#endif #endif
while (di) { /* Strip trailing spaces and dots */ while (di) { /* Snip off trailing spaces and dots if exist */
w = lfn[di - 1]; w = lfn[di - 1];
if (w != ' ' && w != '.') break; if (w != ' ' && w != '.') break;
di--; di--;
} }
if (!di) return FR_INVALID_NAME; /* Reject nul string */ if (!di) return FR_INVALID_NAME; /* Reject nul string */
lfn[di] = 0; /* LFN is created */ lfn[di] = 0; /* LFN is created */
/* Create SFN in directory form */ /* Create SFN in directory form */
@@ -1942,7 +1930,7 @@ FRESULT create_name (
cf |= NS_LFN; /* Force create LFN entry */ cf |= NS_LFN; /* Force create LFN entry */
} }
if (_DF1S && w >= 0x100) { /* DBC (always false at SBCS cfg) */ if (_DF1S && w >= 0x100) { /* Is this DBC? (always false at SBCS cfg) */
if (i >= ni - 1) { if (i >= ni - 1) {
cf |= NS_LOSS | NS_LFN; i = ni; continue; cf |= NS_LOSS | NS_LFN; i = ni; continue;
} }
@@ -1963,7 +1951,7 @@ FRESULT create_name (
dp->fn[i++] = (BYTE)w; dp->fn[i++] = (BYTE)w;
} }
if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with deleted mark, replace it with RDDEM */ if (dp->fn[0] == DDEM) dp->fn[0] = RDDEM; /* If the first character collides with DDEM, replace it with RDDEM */
if (ni == 8) b <<= 2; if (ni == 8) b <<= 2;
if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */ if ((b & 0x0C) == 0x0C || (b & 0x03) == 0x03) /* Create LFN entry when there are composite capitals */
@@ -1984,7 +1972,7 @@ FRESULT create_name (
const char *p; const char *p;
/* Create file name in directory form */ /* Create file name in directory form */
for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Strip duplicated separator */ for (p = *path; *p == '/' || *p == '\\'; p++) ; /* Skip duplicated separator */
sfn = dp->fn; sfn = dp->fn;
mem_set(sfn, ' ', 11); mem_set(sfn, ' ', 11);
si = i = b = 0; ni = 8; si = i = b = 0; ni = 8;
@@ -2019,7 +2007,7 @@ FRESULT create_name (
#endif #endif
#endif #endif
} }
if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false on SBCS cfg) */ if (IsDBCS1(c)) { /* Check if it is a DBC 1st byte (always false at SBCS cfg.) */
d = (BYTE)p[si++]; /* Get 2nd byte */ d = (BYTE)p[si++]; /* Get 2nd byte */
if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */ if (!IsDBCS2(d) || i >= ni - 1) /* Reject invalid DBC */
return FR_INVALID_NAME; return FR_INVALID_NAME;
@@ -2185,7 +2173,7 @@ int get_ldnumber ( /* Returns logical drive number (-1:invalid drive) */
/*-----------------------------------------------------------------------*/ /*-----------------------------------------------------------------------*/
static static
BYTE check_fs ( /* 0:FAT boor sector, 1:Valid boor sector but not FAT, 2:Not a boot sector, 3:Disk error */ BYTE check_fs ( /* 0:Valid FAT-BS, 1:Valid BS but not FAT, 2:Not a BS, 3:Disk error */
FATFS* fs, /* File system object */ 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 boot record or not */
) )
@@ -2343,7 +2331,7 @@ FRESULT find_volume ( /* FR_OK(0): successful, !=0: any error occurred */
/* Get fsinfo if available */ /* Get fsinfo if available */
fs->fsi_flag = 0x80; fs->fsi_flag = 0x80;
#if (_FS_NOFSINFO & 3) != 3 #if (_FS_NOFSINFO & 3) != 3
if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo is 1 */ if (fmt == FS_FAT32 /* Enable FSINFO only if FAT32 and BPB_FSInfo == 1 */
&& LD_WORD(fs->win + BPB_FSInfo) == 1 && LD_WORD(fs->win + BPB_FSInfo) == 1
&& move_window(fs, bsect + 1) == FR_OK) && move_window(fs, bsect + 1) == FR_OK)
{ {
@@ -2389,14 +2377,11 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */ FIL *fil = (FIL*)obj; /* Assuming offset of .fs and .id in the FIL/DIR structure is identical */
if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id) if (!fil || !fil->fs || !fil->fs->fs_type || fil->fs->id != fil->id || (disk_status(fil->fs->drv) & STA_NOINIT))
return FR_INVALID_OBJECT; return FR_INVALID_OBJECT;
ENTER_FF(fil->fs); /* Lock file system */ ENTER_FF(fil->fs); /* Lock file system */
if (disk_status(fil->fs->drv) & STA_NOINIT)
return FR_NOT_READY;
return FR_OK; return FR_OK;
} }
@@ -2407,7 +2392,7 @@ FRESULT validate ( /* FR_OK(0): The object is valid, !=0: Invalid */
Public Functions Public Functions
--------------------------------------------------------------------------*/ ---------------------------------------------------------------------------*/
@@ -2522,12 +2507,13 @@ FRESULT f_open (
} }
} }
if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */ if (res == FR_OK && (mode & FA_CREATE_ALWAYS)) { /* Truncate it if overwrite mode */
dw = GET_FATTIME(); /* Created time */ dw = GET_FATTIME();
ST_DWORD(dir + DIR_CrtTime, dw); ST_DWORD(dir + DIR_CrtTime, dw);/* Set created time */
ST_DWORD(dir + DIR_WrtTime, dw);/* Set modified time */
dir[DIR_Attr] = 0; /* Reset attribute */ dir[DIR_Attr] = 0; /* Reset attribute */
ST_DWORD(dir + DIR_FileSize, 0);/* size = 0 */ ST_DWORD(dir + DIR_FileSize, 0);/* Reset file size */
cl = ld_clust(dj.fs, dir); /* Get start cluster */ cl = ld_clust(dj.fs, dir); /* Get cluster chain */
st_clust(dir, 0); /* cluster = 0 */ st_clust(dir, 0); /* Reset cluster */
dj.fs->wflag = 1; dj.fs->wflag = 1;
if (cl) { /* Remove the cluster chain if exist */ if (cl) { /* Remove the cluster chain if exist */
dw = dj.fs->winsect; dw = dj.fs->winsect;
@@ -2540,7 +2526,7 @@ FRESULT f_open (
} }
} }
else { /* Open an existing file */ else { /* Open an existing file */
if (res == FR_OK) { /* Follow succeeded */ if (res == FR_OK) { /* Following succeeded */
if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */ if (dir[DIR_Attr] & AM_DIR) { /* It is a directory */
res = FR_NO_FILE; res = FR_NO_FILE;
} else { } else {
@@ -2832,10 +2818,9 @@ FRESULT f_sync (
res = validate(fp); /* Check validity of the object */ res = validate(fp); /* Check validity of the object */
if (res == FR_OK) { if (res == FR_OK) {
if (fp->flag & FA__WRITTEN) { /* Has the file been written? */ if (fp->flag & FA__WRITTEN) { /* Is there any change to the file? */
/* Write-back dirty buffer */
#if !_FS_TINY #if !_FS_TINY
if (fp->flag & FA__DIRTY) { if (fp->flag & FA__DIRTY) { /* Write-back cached data if needed */
if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK) if (disk_write(fp->fs->drv, fp->buf, fp->dsect, 1) != RES_OK)
LEAVE_FF(fp->fs, FR_DISK_ERR); LEAVE_FF(fp->fs, FR_DISK_ERR);
fp->flag &= ~FA__DIRTY; fp->flag &= ~FA__DIRTY;
@@ -2848,7 +2833,7 @@ FRESULT f_sync (
dir[DIR_Attr] |= AM_ARC; /* Set archive bit */ dir[DIR_Attr] |= AM_ARC; /* Set archive bit */
ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */ ST_DWORD(dir + DIR_FileSize, fp->fsize); /* Update file size */
st_clust(dir, fp->sclust); /* Update start cluster */ st_clust(dir, fp->sclust); /* Update start cluster */
tm = GET_FATTIME(); /* Update updated time */ tm = GET_FATTIME(); /* Update modified time */
ST_DWORD(dir + DIR_WrtTime, tm); ST_DWORD(dir + DIR_WrtTime, tm);
ST_WORD(dir + DIR_LstAccDate, 0); ST_WORD(dir + DIR_LstAccDate, 0);
fp->flag &= ~FA__WRITTEN; fp->flag &= ~FA__WRITTEN;
@@ -3425,7 +3410,7 @@ FRESULT f_getfree (
{ {
FRESULT res; FRESULT res;
FATFS *fs; FATFS *fs;
DWORD n, clst, sect, stat; DWORD nfree, clst, sect, stat;
UINT i; UINT i;
BYTE fat, *p; BYTE fat, *p;
@@ -3440,18 +3425,17 @@ FRESULT f_getfree (
} else { } else {
/* Get number of free clusters */ /* Get number of free clusters */
fat = fs->fs_type; fat = fs->fs_type;
n = 0; nfree = 0;
if (fat == FS_FAT12) { if (fat == FS_FAT12) { /* Sector unalighed entries: Search FAT via regular routine. */
clst = 2; clst = 2;
do { do {
stat = get_fat(fs, clst); stat = get_fat(fs, clst);
if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; } if (stat == 0xFFFFFFFF) { res = FR_DISK_ERR; break; }
if (stat == 1) { res = FR_INT_ERR; break; } if (stat == 1) { res = FR_INT_ERR; break; }
if (stat == 0) n++; if (stat == 0) nfree++;
} while (++clst < fs->n_fatent); } while (++clst < fs->n_fatent);
} else { } else { /* Sector alighed entries: Accelerate the FAT search. */
clst = fs->n_fatent; clst = fs->n_fatent; sect = fs->fatbase;
sect = fs->fatbase;
i = 0; p = 0; i = 0; p = 0;
do { do {
if (!i) { if (!i) {
@@ -3461,17 +3445,17 @@ FRESULT f_getfree (
i = SS(fs); i = SS(fs);
} }
if (fat == FS_FAT16) { if (fat == FS_FAT16) {
if (LD_WORD(p) == 0) n++; if (LD_WORD(p) == 0) nfree++;
p += 2; i -= 2; p += 2; i -= 2;
} else { } else {
if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) n++; if ((LD_DWORD(p) & 0x0FFFFFFF) == 0) nfree++;
p += 4; i -= 4; p += 4; i -= 4;
} }
} while (--clst); } while (--clst);
} }
fs->free_clust = n; fs->free_clust = nfree; /* free_clust is valid */
fs->fsi_flag |= 1; fs->fsi_flag |= 1; /* FSInfo is to be updated */
*nclst = n; *nclst = nfree; /* Return the free clusters */
} }
} }
LEAVE_FF(fs, res); LEAVE_FF(fs, res);
@@ -3695,8 +3679,7 @@ FRESULT f_chmod (
DEFINE_NAMEBUF; DEFINE_NAMEBUF;
/* Get logical drive number */ res = find_volume(&dj.fs, &path, 1); /* Get logical drive number */
res = find_volume(&dj.fs, &path, 1);
if (res == FR_OK) { if (res == FR_OK) {
INIT_BUF(dj); INIT_BUF(dj);
res = follow_path(&dj, path); /* Follow the file path */ res = follow_path(&dj, path); /* Follow the file path */
@@ -4263,7 +4246,7 @@ FRESULT f_mkfs (
ST_WORD(tbl + BS_55AA, 0xAA55); /* Signature (Offset is fixed here regardless of sector size) */ 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 */ if (disk_write(pdrv, tbl, b_vol, 1) != RES_OK) /* Write it to the VBR sector */
return FR_DISK_ERR; return FR_DISK_ERR;
if (fmt == FS_FAT32) /* Write backup VBR if needed (VBR + 6) */ if (fmt == FS_FAT32) /* Write it to the backup VBR if needed (VBR + 6) */
disk_write(pdrv, tbl, b_vol + 6, 1); disk_write(pdrv, tbl, b_vol + 6, 1);
/* Initialize FAT area */ /* Initialize FAT area */

6
source/fatfs/ff.h Normal file → Executable file
View File

@@ -1,5 +1,5 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015 / FatFs - FAT file system module include R0.11a (C)ChaN, 2015
/----------------------------------------------------------------------------/ /----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of / FatFs module is a free software that opened under license policy of
/ following conditions. / following conditions.
@@ -17,7 +17,7 @@
#ifndef _FATFS #ifndef _FATFS
#define _FATFS 32020 /* Revision ID */ #define _FATFS 64180 /* Revision ID */
#ifdef __cplusplus #ifdef __cplusplus
extern "C" { extern "C" {
@@ -200,7 +200,7 @@ typedef enum {
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */ 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_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */ FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */ FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_LOCK */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */ FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT; } FRESULT;

51
source/fatfs/ffconf.h Normal file → Executable file
View File

@@ -1,21 +1,13 @@
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015 / FatFs - FAT file system module configuration file R0.11a (C)ChaN, 2015
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */ #define _FFCONF 64180 /* Revision ID */
/*---------------------------------------------------------------------------/ /*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations / Function Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_READONLY 0 #define _FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only) /* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(), / Read-only configuration removes writing API functions, f_write(), f_sync(),
@@ -23,7 +15,7 @@
/ and optional writing functions as well. */ / and optional writing functions as well. */
#define _FS_MINIMIZE 0 #define _FS_MINIMIZE 1
/* This option defines minimization level to remove some basic API functions. /* This option defines minimization level to remove some basic API functions.
/ /
/ 0: All basic functions are enabled. / 0: All basic functions are enabled.
@@ -42,7 +34,7 @@
/ 2: Enable with LF-CRLF conversion. */ / 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 0 #define _USE_FIND 1
/* This option switches filtered directory read feature and related functions, /* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */ / f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
@@ -77,19 +69,24 @@
/ 437 - U.S. / 437 - U.S.
/ 720 - Arabic / 720 - Arabic
/ 737 - Greek / 737 - Greek
/ 771 - KBL
/ 775 - Baltic / 775 - Baltic
/ 850 - Multilingual Latin 1 / 850 - Latin 1
/ 852 - Latin 2 / 852 - Latin 2
/ 855 - Cyrillic / 855 - Cyrillic
/ 857 - Turkish / 857 - Turkish
/ 858 - Multilingual Latin 1 + Euro / 860 - Portuguese
/ 861 - Icelandic
/ 862 - Hebrew / 862 - Hebrew
/ 863 - Canadian French
/ 864 - Arabic
/ 865 - Nordic
/ 866 - Russian / 866 - Russian
/ 874 - Thai / 869 - Greek 2
/ 932 - Japanese Shift_JIS (DBCS) / 932 - Japanese (DBCS)
/ 936 - Simplified Chinese GBK (DBCS) / 936 - Simplified Chinese (DBCS)
/ 949 - Korean (DBCS) / 949 - Korean (DBCS)
/ 950 - Traditional Chinese Big5 (DBCS) / 950 - Traditional Chinese (DBCS)
*/ */
@@ -115,7 +112,7 @@
/ to 1. This option also affects behavior of string I/O functions. */ / to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0 #define _STRF_ENCODE 3
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to /* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf(). / be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/ /
@@ -141,7 +138,7 @@
/ Drive/Volume Configurations / Drive/Volume Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _VOLUMES 1 #define _VOLUMES 2
/* Number of volumes (logical drives) to be used. */ /* Number of volumes (logical drives) to be used. */
@@ -195,8 +192,16 @@
/ System Configurations / System Configurations
/---------------------------------------------------------------------------*/ /---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_NORTC 1 #define _FS_NORTC 1
#define _NORTC_MON 2 #define _NORTC_MON 1
#define _NORTC_MDAY 1 #define _NORTC_MDAY 1
#define _NORTC_YEAR 2015 #define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have /* The _FS_NORTC option switches timestamp feature. If the system does not have
@@ -253,7 +258,7 @@
/ * Byte order on the memory is little-endian. / * Byte order on the memory is little-endian.
/ /
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size. / If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some processor types. / Following table shows allowable settings of some type of processors.
/ /
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2 / ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1 / Cortex-M3 0 *3 Z80 0/1 V850ES 0/1

10
source/fatfs/integer.h Normal file → Executable file
View File

@@ -5,26 +5,26 @@
#ifndef _FF_INTEGER #ifndef _FF_INTEGER
#define _FF_INTEGER #define _FF_INTEGER
#ifdef _WIN32 /* FatFs development platform */ #ifdef _WIN32 /* Development platform */
#include <windows.h> #include <windows.h>
#include <tchar.h> #include <tchar.h>
#else /* Embedded platform */ #else /* Embedded platform */
/* This type MUST be 8 bit */ /* This type MUST be 8-bit */
typedef unsigned char BYTE; typedef unsigned char BYTE;
/* These types MUST be 16 bit */ /* These types MUST be 16-bit */
typedef short SHORT; typedef short SHORT;
typedef unsigned short WORD; typedef unsigned short WORD;
typedef unsigned short WCHAR; typedef unsigned short WCHAR;
/* These types MUST be 16 bit or 32 bit */ /* These types MUST be 16-bit or 32-bit */
typedef int INT; typedef int INT;
typedef unsigned int UINT; typedef unsigned int UINT;
/* These types MUST be 32 bit */ /* These types MUST be 32-bit */
typedef long LONG; typedef long LONG;
typedef unsigned long DWORD; typedef unsigned long DWORD;

348
source/fatfs/option/ccsbcs.c Executable file
View File

@@ -0,0 +1,348 @@
/*------------------------------------------------------------------------*/
/* Unicode - Local code bidirectional converter (C)ChaN, 2015 */
/* (SBCS code pages) */
/*------------------------------------------------------------------------*/
/* 437 U.S.
/ 720 Arabic
/ 737 Greek
/ 771 KBL
/ 775 Baltic
/ 850 Latin 1
/ 852 Latin 2
/ 855 Cyrillic
/ 857 Turkish
/ 860 Portuguese
/ 861 Icelandic
/ 862 Hebrew
/ 863 Canadian French
/ 864 Arabic
/ 865 Nordic
/ 866 Russian
/ 869 Greek 2
*/
#include "../ff.h"
#if _CODE_PAGE == 437
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP437(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 720
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP720(0x80-0xFF) to Unicode conversion table */
0x0000, 0x0000, 0x00E9, 0x00E2, 0x0000, 0x00E0, 0x0000, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0000, 0x0000, 0x0000,
0x0000, 0x0651, 0x0652, 0x00F4, 0x00A4, 0x0640, 0x00FB, 0x00F9, 0x0621, 0x0622, 0x0623, 0x0624, 0x00A3, 0x0625, 0x0626, 0x0627,
0x0628, 0x0629, 0x062A, 0x062B, 0x062C, 0x062D, 0x062E, 0x062F, 0x0630, 0x0631, 0x0632, 0x0633, 0x0634, 0x0635, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0636, 0x0637, 0x0638, 0x0639, 0x063A, 0x0641, 0x00B5, 0x0642, 0x0643, 0x0644, 0x0645, 0x0646, 0x0647, 0x0648, 0x0649, 0x064A,
0x2261, 0x064B, 0x064C, 0x064D, 0x064E, 0x064F, 0x0650, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 737
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP737(0x80-0xFF) to Unicode conversion table */
0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x0398, 0x0399, 0x039A, 0x039B, 0x039C, 0x039D, 0x039E, 0x039F, 0x03A0,
0x03A1, 0x03A3, 0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x03B4, 0x03B5, 0x03B6, 0x03B7, 0x03B8,
0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x03C5, 0x03C6, 0x03C7, 0x03C8,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03C9, 0x03AC, 0x03AD, 0x03AE, 0x03CA, 0x03AF, 0x03CC, 0x03CD, 0x03CB, 0x03CE, 0x0386, 0x0388, 0x0389, 0x038A, 0x038C, 0x038E,
0x038F, 0x00B1, 0x2265, 0x2264, 0x03AA, 0x03AB, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 771
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP771(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x0104, 0x0105, 0x010C, 0x010D,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0118, 0x0119, 0x0116, 0x0117, 0x012E, 0x012F, 0x0160, 0x0161, 0x0172, 0x0173, 0x016A, 0x016B, 0x017D, 0x017E, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 775
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP775(0x80-0xFF) to Unicode conversion table */
0x0106, 0x00FC, 0x00E9, 0x0101, 0x00E4, 0x0123, 0x00E5, 0x0107, 0x0142, 0x0113, 0x0156, 0x0157, 0x012B, 0x0179, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x014D, 0x00F6, 0x0122, 0x00A2, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x00A4,
0x0100, 0x012A, 0x00F3, 0x017B, 0x017C, 0x017A, 0x201D, 0x00A6, 0x00A9, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x0141, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0104, 0x010C, 0x0118, 0x0116, 0x2563, 0x2551, 0x2557, 0x255D, 0x012E, 0x0160, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0172, 0x016A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x017D,
0x0105, 0x010D, 0x0119, 0x0117, 0x012F, 0x0161, 0x0173, 0x016B, 0x017E, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x00D3, 0x00DF, 0x014C, 0x0143, 0x00F5, 0x00D5, 0x00B5, 0x0144, 0x0136, 0x0137, 0x013B, 0x013C, 0x0146, 0x0112, 0x0145, 0x2019,
0x00AD, 0x00B1, 0x201C, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x201E, 0x00B0, 0x2219, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 850
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP850(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x00D7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00F0, 0x00D0, 0x00CA, 0x00CB, 0x00C8, 0x0131, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x00FE, 0x00DE, 0x00DA, 0x00DB, 0x00D9, 0x00FD, 0x00DD, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x2017, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 852
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP852(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x016F, 0x0107, 0x00E7, 0x0142, 0x00EB, 0x0150, 0x0151, 0x00EE, 0x0179, 0x00C4, 0x0106,
0x00C9, 0x0139, 0x013A, 0x00F4, 0x00F6, 0x013D, 0x013E, 0x015A, 0x015B, 0x00D6, 0x00DC, 0x0164, 0x0165, 0x0141, 0x00D7, 0x010D,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x0104, 0x0105, 0x017D, 0x017E, 0x0118, 0x0119, 0x00AC, 0x017A, 0x010C, 0x015F, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x011A, 0x015E, 0x2563, 0x2551, 0x2557, 0x255D, 0x017B, 0x017C, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0102, 0x0103, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x0111, 0x0110, 0x010E, 0x00CB, 0x010F, 0x0147, 0x00CD, 0x00CE, 0x011B, 0x2518, 0x250C, 0x2588, 0x2584, 0x0162, 0x016E, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x0143, 0x0144, 0x0148, 0x0160, 0x0161, 0x0154, 0x00DA, 0x0155, 0x0170, 0x00FD, 0x00DD, 0x0163, 0x00B4,
0x00AD, 0x02DD, 0x02DB, 0x02C7, 0x02D8, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x02D9, 0x0171, 0x0158, 0x0159, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 855
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP855(0x80-0xFF) to Unicode conversion table */
0x0452, 0x0402, 0x0453, 0x0403, 0x0451, 0x0401, 0x0454, 0x0404, 0x0455, 0x0405, 0x0456, 0x0406, 0x0457, 0x0407, 0x0458, 0x0408,
0x0459, 0x0409, 0x045A, 0x040A, 0x045B, 0x040B, 0x045C, 0x040C, 0x045E, 0x040E, 0x045F, 0x040F, 0x044E, 0x042E, 0x044A, 0x042A,
0x0430, 0x0410, 0x0431, 0x0411, 0x0446, 0x0426, 0x0434, 0x0414, 0x0435, 0x0415, 0x0444, 0x0424, 0x0433, 0x0413, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x0445, 0x0425, 0x0438, 0x0418, 0x2563, 0x2551, 0x2557, 0x255D, 0x0439, 0x0419, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x043A, 0x041A, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x043B, 0x041B, 0x043C, 0x041C, 0x043D, 0x041D, 0x043E, 0x041E, 0x043F, 0x2518, 0x250C, 0x2588, 0x2584, 0x041F, 0x044F, 0x2580,
0x042F, 0x0440, 0x0420, 0x0441, 0x0421, 0x0442, 0x0422, 0x0443, 0x0423, 0x0436, 0x0416, 0x0432, 0x0412, 0x044C, 0x042C, 0x2116,
0x00AD, 0x044B, 0x042B, 0x0437, 0x0417, 0x0448, 0x0428, 0x044D, 0x042D, 0x0449, 0x0429, 0x0447, 0x0427, 0x00A7, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 857
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP857(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x0131, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x0130, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x015E, 0x015F,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x011E, 0x011F, 0x00BF, 0x00AE, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x00C1, 0x00C2, 0x00C0, 0x00A9, 0x2563, 0x2551, 0x2557, 0x255D, 0x00A2, 0x00A5, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x00E3, 0x00C3, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x00A4,
0x00BA, 0x00AA, 0x00CA, 0x00CB, 0x00C8, 0x0000, 0x00CD, 0x00CE, 0x00CF, 0x2518, 0x250C, 0x2588, 0x2584, 0x00A6, 0x00CC, 0x2580,
0x00D3, 0x00DF, 0x00D4, 0x00D2, 0x00F5, 0x00D5, 0x00B5, 0x0000, 0x00D7, 0x00DA, 0x00DB, 0x00D9, 0x00EC, 0x00FF, 0x00AF, 0x00B4,
0x00AD, 0x00B1, 0x0000, 0x00BE, 0x00B6, 0x00A7, 0x00F7, 0x00B8, 0x00B0, 0x00A8, 0x00B7, 0x00B9, 0x00B3, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 860
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP860(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E3, 0x00E0, 0x00C1, 0x00E7, 0x00EA, 0x00CA, 0x00E8, 0x00CD, 0x00D4, 0x00EC, 0x00C3, 0x00C2,
0x00C9, 0x00C0, 0x00C8, 0x00F4, 0x00F5, 0x00F2, 0x00DA, 0x00F9, 0x00CC, 0x00D5, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x20A7, 0x00D3,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x00D2, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 861
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP861(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00D0, 0x00F0, 0x00DE, 0x00C4, 0x00C5,
0x00C9, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00FE, 0x00FB, 0x00DD, 0x00FD, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00C1, 0x00CD, 0x00D3, 0x00DA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 862
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP862(0x80-0xFF) to Unicode conversion table */
0x05D0, 0x05D1, 0x05D2, 0x05D3, 0x05D4, 0x05D5, 0x05D6, 0x05D7, 0x05D8, 0x05D9, 0x05DA, 0x05DB, 0x05DC, 0x05DD, 0x05DE, 0x05DF,
0x05E0, 0x05E1, 0x05E2, 0x05E3, 0x05E4, 0x05E5, 0x05E6, 0x05E7, 0x05E8, 0x05E9, 0x05EA, 0x00A2, 0x00A3, 0x00A5, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 863
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP863(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00C2, 0x00E0, 0x00B6, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x2017, 0x00C0,
0x00C9, 0x00C8, 0x00CA, 0x00F4, 0x00CB, 0x00CF, 0x00FB, 0x00F9, 0x00A4, 0x00D4, 0x00DC, 0x00A2, 0x00A3, 0x00D9, 0x00DB, 0x0192,
0x00A6, 0x00B4, 0x00F3, 0x00FA, 0x00A8, 0x00BB, 0x00B3, 0x00AF, 0x00CE, 0x3210, 0x00AC, 0x00BD, 0x00BC, 0x00BE, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2219,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 864
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP864(0x80-0xFF) to Unicode conversion table */
0x00B0, 0x00B7, 0x2219, 0x221A, 0x2592, 0x2500, 0x2502, 0x253C, 0x2524, 0x252C, 0x251C, 0x2534, 0x2510, 0x250C, 0x2514, 0x2518,
0x03B2, 0x221E, 0x03C6, 0x00B1, 0x00BD, 0x00BC, 0x2248, 0x00AB, 0x00BB, 0xFEF7, 0xFEF8, 0x0000, 0x0000, 0xFEFB, 0xFEFC, 0x0000,
0x00A0, 0x00AD, 0xFE82, 0x00A3, 0x00A4, 0xFE84, 0x0000, 0x20AC, 0xFE8E, 0xFE8F, 0xFE95, 0xFE99, 0x060C, 0xFE9D, 0xFEA1, 0xFEA5,
0x0660, 0x0661, 0x0662, 0x0663, 0x0664, 0x0665, 0x0666, 0x0667, 0x0668, 0x0669, 0xFED1, 0x061B, 0xFEB1, 0xFEB5, 0xFEB9, 0x061F,
0x00A2, 0xFE80, 0xFE81, 0xFE83, 0xFE85, 0xFECA, 0xFE8B, 0xFE8D, 0xFE91, 0xFE93, 0xFE97, 0xFE9B, 0xFE9F, 0xFEA3, 0xFEA7, 0xFEA9,
0xFEAB, 0xFEAD, 0xFEAF, 0xFEB3, 0xFEB7, 0xFEBB, 0xFEBF, 0xFEC1, 0xFEC5, 0xFECB, 0xFECF, 0x00A6, 0x00AC, 0x00F7, 0x00D7, 0xFEC9,
0x0640, 0xFED3, 0xFED7, 0xFEDB, 0xFEDF, 0xFEE3, 0xFEE7, 0xFEEB, 0xFEED, 0xFEEF, 0xFEF3, 0xFEBD, 0xFECC, 0xFECE, 0xFECD, 0xFEE1,
0xFE7D, 0x0651, 0xFEE5, 0xFEE9, 0xFEEC, 0xFEF0, 0xFEF2, 0xFED0, 0xFED5, 0xFEF5, 0xFEF6, 0xFEDD, 0xFED9, 0xFEF1, 0x25A0, 0x0000
};
#elif _CODE_PAGE == 865
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP865(0x80-0xFF) to Unicode conversion table */
0x00C7, 0x00FC, 0x00E9, 0x00E2, 0x00E4, 0x00E0, 0x00E5, 0x00E7, 0x00EA, 0x00EB, 0x00E8, 0x00EF, 0x00EE, 0x00EC, 0x00C4, 0x00C5,
0x00C5, 0x00E6, 0x00C6, 0x00F4, 0x00F6, 0x00F2, 0x00FB, 0x00F9, 0x00FF, 0x00D6, 0x00DC, 0x00F8, 0x00A3, 0x00D8, 0x20A7, 0x0192,
0x00E1, 0x00ED, 0x00F3, 0x00FA, 0x00F1, 0x00D1, 0x00AA, 0x00BA, 0x00BF, 0x2310, 0x00AC, 0x00BD, 0x00BC, 0x00A1, 0x00AB, 0x00A4,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x2558, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x03B1, 0x00DF, 0x0393, 0x03C0, 0x03A3, 0x03C3, 0x00B5, 0x03C4, 0x03A6, 0x0398, 0x03A9, 0x03B4, 0x221E, 0x03C6, 0x03B5, 0x2229,
0x2261, 0x00B1, 0x2265, 0x2264, 0x2320, 0x2321, 0x00F7, 0x2248, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x207F, 0x00B2, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 866
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP866(0x80-0xFF) to Unicode conversion table */
0x0410, 0x0411, 0x0412, 0x0413, 0x0414, 0x0415, 0x0416, 0x0417, 0x0418, 0x0419, 0x041A, 0x041B, 0x041C, 0x041D, 0x041E, 0x041F,
0x0420, 0x0421, 0x0422, 0x0423, 0x0424, 0x0425, 0x0426, 0x0427, 0x0428, 0x0429, 0x042A, 0x042B, 0x042C, 0x042D, 0x042E, 0x042F,
0x0430, 0x0431, 0x0432, 0x0433, 0x0434, 0x0435, 0x0436, 0x0437, 0x0438, 0x0439, 0x043A, 0x043B, 0x043C, 0x043D, 0x043E, 0x043F,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x2561, 0x2562, 0x2556, 0x2555, 0x2563, 0x2551, 0x2557, 0x255D, 0x255C, 0x255B, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x255E, 0x255F, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x2567,
0x2568, 0x2564, 0x2565, 0x2559, 0x2558, 0x2552, 0x2553, 0x256B, 0x256A, 0x2518, 0x250C, 0x2588, 0x2584, 0x258C, 0x2590, 0x2580,
0x0440, 0x0441, 0x0442, 0x0443, 0x0444, 0x0445, 0x0446, 0x0447, 0x0448, 0x0449, 0x044A, 0x044B, 0x044C, 0x044D, 0x044E, 0x044F,
0x0401, 0x0451, 0x0404, 0x0454, 0x0407, 0x0457, 0x040E, 0x045E, 0x00B0, 0x2219, 0x00B7, 0x221A, 0x2116, 0x00A4, 0x25A0, 0x00A0
};
#elif _CODE_PAGE == 869
#define _TBLDEF 1
static
const WCHAR Tbl[] = { /* CP869(0x80-0xFF) to Unicode conversion table */
0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x00B7, 0x0386, 0x00B7, 0x00B7, 0x00AC, 0x00A6, 0x2018, 0x2019, 0x0388, 0x2015, 0x0389,
0x038A, 0x03AA, 0x038C, 0x00B7, 0x00B7, 0x038E, 0x03AB, 0x00A9, 0x038F, 0x00B2, 0x00B3, 0x03AC, 0x00A3, 0x03AD, 0x03AE, 0x03AF,
0x03CA, 0x0390, 0x03CC, 0x03CD, 0x0391, 0x0392, 0x0393, 0x0394, 0x0395, 0x0396, 0x0397, 0x00BD, 0x0398, 0x0399, 0x00AB, 0x00BB,
0x2591, 0x2592, 0x2593, 0x2502, 0x2524, 0x039A, 0x039B, 0x039C, 0x039D, 0x2563, 0x2551, 0x2557, 0x255D, 0x039E, 0x039F, 0x2510,
0x2514, 0x2534, 0x252C, 0x251C, 0x2500, 0x253C, 0x0A30, 0x03A1, 0x255A, 0x2554, 0x2569, 0x2566, 0x2560, 0x2550, 0x256C, 0x03A3,
0x03A4, 0x03A5, 0x03A6, 0x03A7, 0x03A8, 0x03A9, 0x03B1, 0x03B2, 0x03B3, 0x2518, 0x250C, 0x2588, 0x2584, 0x03B4, 0x03B5, 0x2580,
0x03B6, 0x03B7, 0x03B8, 0x03B9, 0x03BA, 0x03BB, 0x03BC, 0x03BD, 0x03BE, 0x03BF, 0x03C0, 0x03C1, 0x03C3, 0x03C2, 0x03C4, 0x0384,
0x00AD, 0x00B1, 0x03C5, 0x03C6, 0x03C7, 0x00A7, 0x03C8, 0x0385, 0x00B0, 0x00A8, 0x03C9, 0x03CB, 0x03B0, 0x03CE, 0x25A0, 0x00A0
};
#endif
#if !_TBLDEF || !_USE_LFN
#error This file is not needed at current configuration. Remove from the project.
#endif
WCHAR ff_convert ( /* Converted character, Returns zero on error */
WCHAR chr, /* Character code to be converted */
UINT dir /* 0: Unicode to OEM code, 1: OEM code to Unicode */
)
{
WCHAR c;
if (chr < 0x80) { /* ASCII */
c = chr;
} else {
if (dir) { /* OEM code to Unicode */
c = (chr >= 0x100) ? 0 : Tbl[chr - 0x80];
} else { /* Unicode to OEM code */
for (c = 0; c < 0x80; c++) {
if (chr == Tbl[c]) break;
}
c = (c + 0x80) & 0xFF;
}
}
return c;
}
WCHAR ff_wtoupper ( /* Returns upper converted character */
WCHAR chr /* Unicode character to be upper converted */
)
{
static const WCHAR lower[] = { /* Lower case characters to be converted */
/* Latin Supplement */ 0xE0,0xE1,0xE2,0xE3,0xE4,0xE5,0xE6,0xE7,0xE8,0xE9,0xEA,0xEB,0xEC,0xED,0xEE,0xEF,0xF0,0xF1,0xF2,0xF3,0xF4,0xF5,0xF6,0xF8,0xF9,0xFA,0xFB,0xFC,0xFD,0xFE,0xFF,
/* Latin Extended-A */ 0x101,0x103,0x105,0x107,0x109,0x10B,0x10D,0x10F,0x111,0x113,0x115,0x117,0x119,0x11B,0x11D,0x11F,0x121,0x123,0x125,0x127,0x129,0x12B,0x12D,0x12F,0x131,0x133,0x135,0x137,0x13A,0x13C,0x13E,0x140,0x142,0x144,0x146,0x148,0x14B,0x14D,0x14F,0x151,0x153,0x155,0x157,0x159,0x15B,0x15D,0x15F,0x161,0x163,0x165,0x167,0x169,0x16B,0x16D,0x16F,0x171,0x173,0x175,0x177,0x17A,0x17C,0x17E,
/* Latin Extended-B */ 0x183,0x185,0x188,0x18C,0x192,0x199,0x1A1,0x1A3,0x1A8,0x1AD,0x1B0,0x1B4,0x1B6,0x1B9,0x1BD,0x1C6,0x1C9,0x1CC,0x1CE,0x1D0,0x1D2,0x1D4,0x1D6,0x1D8,0x1DA,0x1DC,0x1DD,0x1DF,0x1E1,0x1E3,0x1E5,0x1E7,0x1E9,0x1EB,0x1ED,0x1EF,0x1F3,0x1F5,0x1FB,0x1FD,0x1FF,0x201,0x203,0x205,0x207,0x209,0x20B,0x20D,0x20F,0x211,0x213,0x215,0x217,
/* Greek, Coptic */ 0x3B1,0x3B2,0x3B3,0x3B4,0x3B5,0x3B6,0x3B7,0x3B8,0x3B9,0x3BA,0x3BB,0x3BC,0x3BD,0x3BE,0x3BF,0x3C0,0x3C1,0x3C3,0x3C4,0x3C5,0x3C6,0x3C7,0x3C8,0x3C9,0x3CA,0x3CB,0x3CC,0x3CD,0x3CE,0x3E3,0x3E5,0x3E7,0x3E9,0x3EB,
/* Cyrillic */ 0x430,0x431,0x432,0x433,0x434,0x435,0x436,0x437,0x438,0x439,0x43A,0x43B,0x43C,0x43D,0x43E,0x43F,0x440,0x441,0x442,0x443,0x444,0x445,0x446,0x447,0x448,0x449,0x44A,0x44B,0x44C,0x44D,0x44E,0x44F,0x452,0x453,0x454,0x455,0x456,0x457,0x458,0x459,0x45A,0x45B,0x45C,0x45E,0x45F,0x461,0x463,0x465,0x467,0x469,0x46B,0x46D,0x46F,0x471,0x473,0x475,0x477,0x479,0x47B,0x47D,0x47F,0x481,0x491,0x493,0x495,0x497,0x499,0x49B,0x49D,0x49F,0x4A1,0x4A3,0x4A5,0x4A7,0x4A9,0x4AB,0x4AD,0x4AF,0x4B1,0x4B3,0x4B5,0x4B7,0x4B9,0x4BB,0x4BD,0x4BF,0x4C2,0x4C4,0x4C8,0x4D1,0x4D3,0x4D5,0x4D7,0x4D9,0x4DB,0x4DD,0x4DF,0x4E1,0x4E3,0x4E5,0x4E7,0x4E9,0x4EB,0x4ED,0x4EF,0x4F1,0x4F3,0x4F5,0x4F9,
/* Armenian */ 0x561,0x562,0x563,0x564,0x565,0x566,0x567,0x568,0x569,0x56A,0x56B,0x56C,0x56D,0x56E,0x56F,0x570,0x571,0x572,0x573,0x574,0x575,0x576,0x577,0x578,0x579,0x57A,0x57B,0x57C,0x57D,0x57E,0x57F,0x580,0x581,0x582,0x583,0x584,0x585,0x586,
/* Latin Extended Additional */ 0x1E01,0x1E03,0x1E05,0x1E07,0x1E09,0x1E0B,0x1E0D,0x1E0F,0x1E11,0x1E13,0x1E15,0x1E17,0x1E19,0x1E1B,0x1E1D,0x1E1F,0x1E21,0x1E23,0x1E25,0x1E27,0x1E29,0x1E2B,0x1E2D,0x1E2F,0x1E31,0x1E33,0x1E35,0x1E37,0x1E39,0x1E3B,0x1E3D,0x1E3F,0x1E41,0x1E43,0x1E45,0x1E47,0x1E49,0x1E4B,0x1E4D,0x1E4F,0x1E51,0x1E53,0x1E55,0x1E57,0x1E59,0x1E5B,0x1E5D,0x1E5F,0x1E61,0x1E63,0x1E65,0x1E67,0x1E69,0x1E6B,0x1E6D,0x1E6F,0x1E71,0x1E73,0x1E75,0x1E77,0x1E79,0x1E7B,0x1E7D,0x1E7F,0x1E81,0x1E83,0x1E85,0x1E87,0x1E89,0x1E8B,0x1E8D,0x1E8F,0x1E91,0x1E93,0x1E95,0x1E97,0x1E99,0x1E9B,0x1E9D,0x1E9F,0x1EA1,0x1EA3,0x1EA5,0x1EA7,0x1EA9,0x1EAB,0x1EAD,0x1EAF,0x1EB1,0x1EB3,0x1EB5,0x1EB7,0x1EB9,0x1EBB,0x1EBD,0x1EBF,0x1EC1,0x1EC3,0x1EC5,0x1EC7,0x1EC9,0x1ECB,0x1ECD,0x1ECF,0x1ED1,0x1ED3,0x1ED5,0x1ED7,0x1ED9,0x1EDB,0x1EDD,0x1EDF,0x1EE1,0x1EE3,0x1EE5,0x1EE7,0x1EE9,0x1EEB,0x1EED,0x1EEF,0x1EF1,0x1EF3,0x1EF5,0x1EF7,0x1EF9,
/* Number forms */ 0x2170,0x2171,0x2172,0x2173,0x2174,0x2175,0x2176,0x2177,0x2178,0x2179,0x217A,0x217B,0x217C,0x217D,0x217E,0x217F,
/* Full-width */ 0xFF41,0xFF42,0xFF43,0xFF44,0xFF45,0xFF46,0xFF47,0xFF48,0xFF49,0xFF4A,0xFF4B,0xFF4C,0xFF4D,0xFF4E,0xFF4F,0xFF50,0xFF51,0xFF52,0xFF53,0xFF54,0xFF55,0xFF56,0xFF57,0xFF58,0xFF59,0xFF5A
};
static const WCHAR upper[] = { /* Upper case characters correspond to lower[] */
0xC0,0xC1,0xC2,0xC3,0xC4,0xC5,0xC6,0xC7,0xC8,0xC9,0xCA,0xCB,0xCC,0xCD,0xCE,0xCF,0xD0,0xD1,0xD2,0xD3,0xD4,0xD5,0xD6,0xD8,0xD9,0xDA,0xDB,0xDC,0xDD,0xDE,0x178,
0x100,0x102,0x104,0x106,0x108,0x10A,0x10C,0x10E,0x110,0x112,0x114,0x116,0x118,0x11A,0x11C,0x11E,0x120,0x122,0x124,0x126,0x128,0x12A,0x12C,0x12E,0x130,0x132,0x134,0x136,0x139,0x13B,0x13D,0x13F,0x141,0x143,0x145,0x147,0x14A,0x14C,0x14E,0x150,0x152,0x154,0x156,0x158,0x15A,0x15C,0x15E,0x160,0x162,0x164,0x166,0x168,0x16A,0x16C,0x16E,0x170,0x172,0x174,0x176,0x179,0x17B,0x17D,
0x182,0x184,0x187,0x18B,0x191,0x198,0x1A0,0x1A2,0x1A7,0x1AC,0x1AF,0x1B3,0x1B5,0x1B8,0x1BC,0x1C4,0x1C7,0x1CA,0x1CD,0x1CF,0x1D1,0x1D3,0x1D5,0x1D7,0x1D9,0x1DB,0x18E,0x1DE,0x1E0,0x1E2,0x1E4,0x1E6,0x1E8,0x1EA,0x1EC,0x1EE,0x1F1,0x1F4,0x1FA,0x1FC,0x1FE,0x200,0x202,0x204,0x206,0x208,0x20A,0x20C,0x20E,0x210,0x212,0x214,0x216,
0x391,0x392,0x393,0x394,0x395,0x396,0x397,0x398,0x399,0x39A,0x39B,0x39C,0x39D,0x39E,0x39F,0x3A0,0x3A1,0x3A3,0x3A4,0x3A5,0x3A6,0x3A7,0x3A8,0x3A9,0x3AA,0x3AB,0x38C,0x38E,0x38F,0x3E2,0x3E4,0x3E6,0x3E8,0x3EA,
0x410,0x411,0x412,0x413,0x414,0x415,0x416,0x417,0x418,0x419,0x41A,0x41B,0x41C,0x41D,0x41E,0x41F,0x420,0x421,0x422,0x423,0x424,0x425,0x426,0x427,0x428,0x429,0x42A,0x42B,0x42C,0x42D,0x42E,0x42F,0x402,0x403,0x404,0x405,0x406,0x407,0x408,0x409,0x40A,0x40B,0x40C,0x40E,0x40F,0x460,0x462,0x464,0x466,0x468,0x46A,0x46C,0x46E,0x470,0x472,0x474,0x476,0x478,0x47A,0x47C,0x47E,0x480,0x490,0x492,0x494,0x496,0x498,0x49A,0x49C,0x49E,0x4A0,0x4A2,0x4A4,0x4A6,0x4A8,0x4AA,0x4AC,0x4AE,0x4B0,0x4B2,0x4B4,0x4B6,0x4B8,0x4BA,0x4BC,0x4BE,0x4C1,0x4C3,0x5C7,0x4D0,0x4D2,0x4D4,0x4D6,0x4D8,0x4DA,0x4DC,0x4DE,0x4E0,0x4E2,0x4E4,0x4E6,0x4E8,0x4EA,0x4EC,0x4EE,0x4F0,0x4F2,0x4F4,0x4F8,
0x531,0x532,0x533,0x534,0x535,0x536,0x537,0x538,0x539,0x53A,0x53B,0x53C,0x53D,0x53E,0x53F,0x540,0x541,0x542,0x543,0x544,0x545,0x546,0x547,0x548,0x549,0x54A,0x54B,0x54C,0x54D,0x54E,0x54F,0x550,0x551,0x552,0x553,0x554,0x555,0x556,
0x1E00,0x1E02,0x1E04,0x1E06,0x1E08,0x1E0A,0x1E0C,0x1E0E,0x1E10,0x1E12,0x1E14,0x1E16,0x1E18,0x1E1A,0x1E1C,0x1E1E,0x1E20,0x1E22,0x1E24,0x1E26,0x1E28,0x1E2A,0x1E2C,0x1E2E,0x1E30,0x1E32,0x1E34,0x1E36,0x1E38,0x1E3A,0x1E3C,0x1E3E,0x1E40,0x1E42,0x1E44,0x1E46,0x1E48,0x1E4A,0x1E4C,0x1E4E,0x1E50,0x1E52,0x1E54,0x1E56,0x1E58,0x1E5A,0x1E5C,0x1E5E,0x1E60,0x1E62,0x1E64,0x1E66,0x1E68,0x1E6A,0x1E6C,0x1E6E,0x1E70,0x1E72,0x1E74,0x1E76,0x1E78,0x1E7A,0x1E7C,0x1E7E,0x1E80,0x1E82,0x1E84,0x1E86,0x1E88,0x1E8A,0x1E8C,0x1E8E,0x1E90,0x1E92,0x1E94,0x1E96,0x1E98,0x1E9A,0x1E9C,0x1E9E,0x1EA0,0x1EA2,0x1EA4,0x1EA6,0x1EA8,0x1EAA,0x1EAC,0x1EAE,0x1EB0,0x1EB2,0x1EB4,0x1EB6,0x1EB8,0x1EBA,0x1EBC,0x1EBE,0x1EC0,0x1EC2,0x1EC4,0x1EC6,0x1EC8,0x1ECA,0x1ECC,0x1ECE,0x1ED0,0x1ED2,0x1ED4,0x1ED6,0x1ED8,0x1EDA,0x1EDC,0x1EDE,0x1EE0,0x1EE2,0x1EE4,0x1EE6,0x1EE8,0x1EEA,0x1EEC,0x1EEE,0x1EF0,0x1EF2,0x1EF4,0x1EF6,0x1EF8,
0x2160,0x2161,0x2162,0x2163,0x2164,0x2165,0x2166,0x2167,0x2168,0x2169,0x216A,0x216B,0x216C,0x216D,0x216E,0x216F,
0xFF21,0xFF22,0xFF23,0xFF24,0xFF25,0xFF26,0xFF27,0xFF28,0xFF29,0xFF2A,0xFF2B,0xFF2C,0xFF2D,0xFF2E,0xFF2F,0xFF30,0xFF31,0xFF32,0xFF33,0xFF34,0xFF35,0xFF36,0xFF37,0xFF38,0xFF39,0xFF3A
};
UINT i, n, hi, li;
if (chr < 0x80) { /* ASCII characters (acceleration) */
if (chr >= 0x61 && chr <= 0x7A) chr -= 0x20;
} else { /* Non ASCII characters (table search) */
n = 12; li = 0; hi = sizeof lower / sizeof lower[0];
do {
i = li + (hi - li) / 2;
if (chr == lower[i]) break;
if (chr > lower[i]) li = i; else hi = i;
} while (--n);
if (n) chr = upper[i];
}
return chr;
}

View File

@@ -2,3 +2,4 @@
#include <stdbool.h> #include <stdbool.h>
#include "../../types.h" #include "../../types.h"
#include "../../crypto.h"

View File

@@ -402,3 +402,44 @@ int sdmmc_sdcard_init()
return result | SD_Init(); return result | SD_Init();
} }
int sdmmc_get_cid(int isNand, uint32_t *info)
{
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;
}

View File

@@ -122,6 +122,7 @@ int sdmmc_sdcard_init();
u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out); u32 sdmmc_sdcard_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in); u32 sdmmc_sdcard_writesectors(u32 sector_no, u32 numsectors, vu8 *in);
mmcdevice *getMMCDevice(int drive); 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_readsectors(u32 sector_no, u32 numsectors, vu8 *out);
u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in); u32 sdmmc_nand_writesectors(u32 sector_no, u32 numsectors, vu8 *in);

View File

@@ -5,179 +5,287 @@
*/ */
#include "firm.h" #include "firm.h"
#include "config.h"
#include "utils.h"
#include "fs.h"
#include "patches.h" #include "patches.h"
#include "memory.h" #include "memory.h"
#include "fs.h"
#include "emunand.h" #include "emunand.h"
#include "crypto.h" #include "crypto.h"
#include "draw.h" #include "draw.h"
#include "screeninit.h" #include "screeninit.h"
#include "loader.h" #include "loader.h"
#include "utils.h"
#include "buttons.h" #include "buttons.h"
#include "../build/patches.h" #include "../build/patches.h"
//FIRM patches version
#define PATCH_VER 2
static firmHeader *const firm = (firmHeader *)0x24000000; static firmHeader *const firm = (firmHeader *)0x24000000;
static const firmSectionHeader *section; static const firmSectionHeader *section;
static u8 *arm9Section;
static const char *patchedFirms[] = { "/aurei/patched_firmware_sys.bin", u32 config,
"/aurei/patched_firmware_emu.bin",
"/aurei/patched_firmware_em2.bin",
"/aurei/patched_firmware90.bin" };
static u32 firmSize,
console, console,
mode, firmSource,
emuNAND, emuOffset;
a9lhSetup,
selectedFirm,
usePatchedFirm;
void setupCFW(void){ void main(void)
{
u32 bootType,
firmType,
nandType,
a9lhInstalled,
updatedSys,
needConfig,
newConfig,
emuHeader;
//Determine if booting with A9LH
u32 a9lhBoot = (PDN_SPI_CNT == 0x0) ? 1 : 0;
//Retrieve the last booted FIRM
u8 previousFirm = CFG_BOOTENV;
//Detect the console being used //Detect the console being used
console = (PDN_MPCORE_CFG == 1) ? 0 : 1; console = (PDN_MPCORE_CFG == 1) ? 0 : 1;
//Get pressed buttons
u16 pressed = HID_PAD; //Mount filesystems. CTRNAND will be mounted only if/when needed
mountFs();
//Attempt to read the configuration file //Attempt to read the configuration file
const char configPath[] = "aurei/config.bin"; const char configPath[] = "/aurei/config.bin";
u32 config = 0; if(fileRead(&config, configPath, 4)) needConfig = 1;
u32 needConfig = fileRead(&config, configPath, 3) ? 1 : 2; else
{
config = 0;
needConfig = 2;
}
//Determine if this is a firmlaunch boot
if(*(vu8 *)0x23F00005)
{
if(needConfig == 2) mcuReboot();
bootType = 1;
//'0' = NATIVE_FIRM, '1' = TWL_FIRM, '2' = AGB_FIRM
firmType = *(vu8 *)0x23F00005 - '0';
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
a9lhInstalled = BOOTCONFIG(3, 1);
updatedSys = (a9lhInstalled && CONFIG(1)) ? 1 : 0;
}
else
{
bootType = 0;
firmType = 0;
//Determine if booting with A9LH
u32 a9lhBoot = !PDN_SPI_CNT ? 1 : 0;
//Retrieve the last booted FIRM
u32 previousFirm = CFG_BOOTENV;
//Get pressed buttons
u32 pressed = HID_PAD;
//Determine if we need to autoboot sysNAND
u32 autoBootSys = CONFIG(0);
//Determine if A9LH is installed and the user has an updated sysNAND //Determine if A9LH is installed and the user has an updated sysNAND
u32 updatedSys; if(a9lhBoot || CONFIG(2))
{
if(a9lhBoot || (config >> 2) & 0x1){
if(pressed == SAFE_MODE) if(pressed == SAFE_MODE)
error("Using Safe Mode would brick you, or remove A9LH!"); error("Using Safe Mode would brick you, or remove A9LH!");
a9lhSetup = 1; a9lhInstalled = 1;
//Check setting for > 9.2 sysNAND //Check setting for > 9.2 sysNAND
updatedSys = config & 0x1; updatedSys = CONFIG(1);
} else{ }
a9lhSetup = 0; else
{
a9lhInstalled = 0;
updatedSys = 0; updatedSys = 0;
} }
newConfig = a9lhInstalled << 3;
/* If booting with A9LH, it's a MCU reboot and a previous configuration exists, /* If booting with A9LH, it's a MCU reboot and a previous configuration exists,
try to force boot options */ try to force boot options */
if(a9lhBoot && previousFirm && needConfig == 1){ if(a9lhBoot && previousFirm && needConfig == 1)
{
//Always force a sysNAND boot when quitting AGB_FIRM //Always force a sysNAND boot when quitting AGB_FIRM
if(previousFirm == 0x7){ if(previousFirm == 7)
if(!updatedSys) mode = (config >> 12) & 0x1; {
emuNAND = 0; nandType = 0;
firmSource = updatedSys ? 0 : BOOTCONFIG(2, 1);
needConfig = 0; needConfig = 0;
//Else, force the last used boot options unless A, L or R are pressed
} else if(!(pressed & OPTION_BUTTONS)){ //Flag to prevent multiple boot options-forcing
mode = (config >> 12) & 0x1; newConfig |= 1 << 4;
emuNAND = (config >> 13) & 0x3; }
/* Else, force the last used boot options unless a payload button or A/L/R are pressed
or the no-forcing flag is set */
else if(!(pressed & OVERRIDE_BUTTONS) && !BOOTCONFIG(4, 1))
{
nandType = BOOTCONFIG(0, 3);
firmSource = BOOTCONFIG(2, 1);
needConfig = 0; needConfig = 0;
} }
} }
if(needConfig){ //Boot options aren't being forced
if(needConfig)
/* If L and one of the payload buttons are pressed, and if not using A9LH {
/* If L and R/Select or one of the single payload buttons are pressed and, if not using A9LH,
the Safe Mode combo is not pressed, chainload an external payload */ the Safe Mode combo is not pressed, chainload an external payload */
if((pressed & BUTTON_L1) && (pressed & PAYLOAD_BUTTONS) && if(((pressed & SINGLE_PAYLOAD_BUTTONS) || ((pressed & BUTTON_L1) && (pressed & L_PAYLOAD_BUTTONS)))
pressed != SAFE_MODE) loadPayload(); && pressed != SAFE_MODE)
loadPayload();
//If no configuration file exists or SELECT is held, load configuration menu //If no configuration file exists or SELECT is held, load configuration menu
if(needConfig == 2 || (pressed & BUTTON_SELECT)) if(needConfig == 2 || (pressed & BUTTON_SELECT))
configureCFW(configPath, patchedFirms[3]); configureCFW(configPath);
//If screens are inited, load splash screen //If screens are inited or the corresponding option is set, load splash screen
if(PDN_GPU_CNT != 0x1) loadSplash(); if(PDN_GPU_CNT != 1 || CONFIG(8)) loadSplash();
/* If L is pressed, boot 9.0 FIRM */ //Determine if we need to boot an emuNAND or sysNAND
mode = ((config >> 3) & 0x1) ? ((!(pressed & BUTTON_L1R1)) ? 0 : 1) : nandType = (pressed & BUTTON_L1) ? autoBootSys : ((pressed & BUTTON_R1) ? updatedSys : !autoBootSys);
((pressed & BUTTON_L1) ? 0 : 1);
/* If L or R aren't pressed on a 9.0/9.2 sysNAND, or the 9.0 FIRM is selected /* If we're booting emuNAND the second emuNAND is set as default and B isn't pressed,
or R is pressed on a > 9.2 sysNAND, boot emuNAND */ or vice-versa, boot the second emuNAND */
if((updatedSys && (!mode || (pressed & BUTTON_R1))) || if(nandType && ((!(pressed & BUTTON_B)) == CONFIG(3))) nandType++;
(!updatedSys && mode && !(pressed & BUTTON_R1))){
//If not 9.0 FIRM and B is pressed, attempt booting the second emuNAND
emuNAND = (mode && ((!(pressed & BUTTON_B)) == ((config >> 4) & 0x1))) ? 2 : 1;
} else emuNAND = 0;
u32 tempConfig = (PATCH_VER << 17) | (a9lhSetup << 16) | (emuNAND << 13) | (mode << 12); //Determine the NAND we should take the FIRM from
firmSource = (pressed & BUTTON_R1) ? !nandType : (nandType != 0);
/* If tha FIRM patches version is different or user switched to/from A9LH,
delete all patched FIRMs */
if((tempConfig & 0xFF0000) != (config & 0xFF0000))
deleteFirms(patchedFirms, sizeof(patchedFirms) / sizeof(char *));
//If the boot configuration is different from previously, overwrite it
if((tempConfig & 0xFFF000) != (config & 0xFFF000)){
//Preserve user settings (first 12 bits)
tempConfig |= config & 0xFFF;
fileWrite(&tempConfig, configPath, 3);
} }
} }
/* Determine which patched FIRM we need to write or attempt to use (if any). //If we need to boot emuNAND, make sure it exists
Patched 9.0 FIRM is only needed if "Use pre-patched FIRMs" is set */ if(nandType)
selectedFirm = mode ? (emuNAND ? (emuNAND == 1 ? 2 : 3) : 1) : {
(((config >> 1) & 0x1) ? 4 : 0); getEmunandSect(&emuOffset, &emuHeader, &nandType);
if(!nandType) firmSource = 0;
}
//If "Use pre-patched FIRMs" is set and the appropriate FIRM exists, use it //Same if we're using emuNAND as the FIRM source
usePatchedFirm = (((config >> 1) & 0x1) && fileExists(patchedFirms[selectedFirm - 1])) ? 1 : 0; else if(firmSource)
getEmunandSect(&emuOffset, &emuHeader, &firmSource);
if(!bootType)
{
newConfig |= nandType | (firmSource << 2);
/* If the boot configuration is different from previously, overwrite it.
Just the no-forcing flag being set is not enough */
if((newConfig & 0x2F) != (config & 0x3F))
{
//Preserve user settings (last 26 bits)
newConfig |= config & 0xFFFFFFC0;
fileWrite(&newConfig, configPath, 4);
}
}
loadFirm(firmType, !firmType && (nandType == 2 || updatedSys == !firmSource));
if(!firmType) patchNativeFirm(nandType, emuHeader, a9lhInstalled);
else patchTwlAgbFirm(firmType);
launchFirm(bootType);
} }
//Load FIRM into FCRAM //Load FIRM into FCRAM
void loadFirm(void){ static inline void loadFirm(u32 firmType, u32 externalFirm)
{
//If not using an A9LH setup or the patched FIRM, load 9.0 FIRM from NAND
if(!usePatchedFirm && !a9lhSetup && !mode){
//Read FIRM from NAND and write to FCRAM
firmSize = console ? 0xF2000 : 0xE9000;
nandFirm0((u8 *)firm, firmSize, console);
//Check for correct decryption
if(memcmp(firm, "FIRM", 4) != 0)
error("Couldn't decrypt NAND FIRM0 (O3DS not on 9.x?)");
}
//Load FIRM from SD
else{
const char *path = usePatchedFirm ? patchedFirms[selectedFirm - 1] :
(mode ? "/aurei/firmware.bin" : "/aurei/firmware90.bin");
firmSize = fileSize(path);
if(!firmSize) error("aurei/firmware(90).bin doesn't exist");
fileRead(firm, path, firmSize);
}
section = firm->section; section = firm->section;
u32 firmSize;
if(externalFirm)
{
const char path[] = "/aurei/firmware.bin";
firmSize = fileSize(path);
if(firmSize)
{
fileRead(firm, path, firmSize);
//Check that the loaded FIRM matches the console //Check that the loaded FIRM matches the console
if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) if((((u32)section[2].address >> 8) & 0xFF) != (console ? 0x60 : 0x68)) firmSize = 0;
error("aurei/firmware(90).bin doesn't match this\nconsole, or it's encrypted"); }
}
else firmSize = 0;
arm9Section = (u8 *)firm + section[2].offset; if(!firmSize)
{
const char *firmFolders[3][2] = {{ "00000002", "20000002" },
{ "00000102", "20000102" },
{ "00000202", "20000202" }};
if(console && !usePatchedFirm) decryptArm9Bin(arm9Section, mode); firmRead(firm, firmFolders[firmType][console]);
decryptExeFs((u8 *)firm);
}
} }
//NAND redirection static inline void patchNativeFirm(u32 nandType, u32 emuHeader, u32 a9lhInstalled)
static void loadEmu(u8 *proc9Offset){ {
u8 *arm9Section = (u8 *)firm + section[2].offset;
u32 emuOffset, u32 nativeFirmType;
emuHeader = 0,
emuRead,
emuWrite;
//Look for emuNAND if(console)
getEmunandSect(&emuOffset, &emuHeader, emuNAND); {
//Determine if we're booting the 9.0 FIRM
nativeFirmType = (arm9Section[0x51] == 0xFF) ? 0 : 1;
//No emuNAND detected //Decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(!emuHeader) error("No emuNAND has been detected"); arm9Loader(arm9Section, nativeFirmType);
firm->arm9Entry = (u8 *)0x801B01C;
}
else
{
//Determine if we're booting the 9.0 FIRM
u8 firm90Hash[0x10] = {0x27, 0x2D, 0xFE, 0xEB, 0xAF, 0x3F, 0x6B, 0x3B, 0xF5, 0xDE, 0x4C, 0x41, 0xDE, 0x95, 0x27, 0x6A};
nativeFirmType = (memcmp(section[2].hash, firm90Hash, 0x10) == 0) ? 0 : 1;
}
if(nativeFirmType || nandType)
{
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(nandType) patchEmuNAND(arm9Section, proc9Offset, emuHeader);
//Apply FIRM reboot patches, not on 9.0 FIRM as it breaks firmlaunchhax
if(nativeFirmType) patchReboots(arm9Section, proc9Offset);
}
//Apply FIRM0/1 writes patches on sysNAND to protect A9LH
if(a9lhInstalled && !nandType)
{
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Apply signature checks patches
u32 sigOffset,
sigOffset2;
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2);
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
if(CONFIG(5))
{
//Apply UNITINFO patch
u8 *unitInfoOffset = getUnitInfoValueSet(arm9Section, section[2].size);
*unitInfoOffset = unitInfoPatch;
}
//Replace the FIRM loader with the injector
injectLoader();
}
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader)
{
//Copy emuNAND code //Copy emuNAND code
void *emuCodeOffset = getEmuCode(proc9Offset); void *emuCodeOffset = getEmuCode(proc9Offset);
memcpy(emuCodeOffset, emunand, emunand_size); memcpy(emuCodeOffset, emunand, emunand_size);
@@ -196,7 +304,10 @@ static void loadEmu(u8 *proc9Offset){
u32 branchOffset = (u32)emuCodeOffset - (u32)firm - u32 branchOffset = (u32)emuCodeOffset - (u32)firm -
section[2].offset + (u32)section[2].address; section[2].offset + (u32)section[2].address;
//Add emunand hooks //Add emuNAND hooks
u32 emuRead,
emuWrite;
getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite); getEmuRW(arm9Section, section[2].size, &emuRead, &emuWrite);
*(u16 *)emuRead = nandRedir[0]; *(u16 *)emuRead = nandRedir[0];
*((u16 *)emuRead + 1) = nandRedir[1]; *((u16 *)emuRead + 1) = nandRedir[1];
@@ -212,23 +323,11 @@ static void loadEmu(u8 *proc9Offset){
*(mpuOffset + 9) = mpuPatch[2]; *(mpuOffset + 9) = mpuPatch[2];
} }
//Patches static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset)
void patchFirm(void){ {
//Skip patching
if(usePatchedFirm) return;
if(mode || emuNAND){
//Find the Process9 NCCH location
u8 *proc9Offset = getProc9(arm9Section, section[2].size);
//Apply emuNAND patches
if(emuNAND) loadEmu(proc9Offset);
//Patch FIRM reboots, not on 9.0 FIRM as it breaks firmlaunchhax
if(mode){
//Calculate offset for the firmlaunch code //Calculate offset for the firmlaunch code
void *rebootOffset = getReboot(arm9Section, section[2].size); void *rebootOffset = getReboot(arm9Section, section[2].size);
//Calculate offset for the fOpen function //Calculate offset for the fOpen function
u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset); u32 fOpenOffset = getfOpen(proc9Offset, rebootOffset);
@@ -238,67 +337,89 @@ void patchFirm(void){
//Put the fOpen offset in the right location //Put the fOpen offset in the right location
u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4); u32 *pos_fopen = (u32 *)memsearch(rebootOffset, "OPEN", reboot_size, 4);
*pos_fopen = fOpenOffset; *pos_fopen = fOpenOffset;
}
//Patch path for emuNAND-patched FIRM static inline void injectLoader(void)
if(emuNAND){ {
void *pos_path = memsearch(rebootOffset, L"sy", reboot_size, 4); u32 loaderSize;
memcpy(pos_path, emuNAND == 1 ? L"emu" : L"em2", 5);
}
}
}
if(a9lhSetup && !emuNAND){ void *loaderOffset = getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderSize);
//Patch FIRM partitions writes on sysNAND to protect A9LH
u16 *writeOffset = getFirmWrite(arm9Section, section[2].size);
*writeOffset = writeBlock[0];
*(writeOffset + 1) = writeBlock[1];
}
//Disable signature checks //Check that the injector CXI isn't larger than the original
u32 sigOffset, if((u32)injector_size <= loaderSize)
sigOffset2; {
memcpy(loaderOffset, injector, injector_size);
getSigChecks(arm9Section, section[2].size, &sigOffset, &sigOffset2); //Patch content size and ExeFS size to match the repaced loader's ones
*(u16 *)sigOffset = sigPatch[0];
*(u16 *)sigOffset2 = sigPatch[0];
*((u16 *)sigOffset2 + 1) = sigPatch[1];
//Replace the FIRM loader with the injector
u32 loaderOffset,
loaderSize;
getLoader((u8 *)firm + section[0].offset, section[0].size, &loaderOffset, &loaderSize);
if(injector_size <= (int)loaderSize){
memset((void *)loaderOffset, 0, loaderSize);
memcpy((void *)loaderOffset, injector, injector_size);
*((u32 *)loaderOffset + 0x41) = loaderSize / 0x200; *((u32 *)loaderOffset + 0x41) = loaderSize / 0x200;
*((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5; *((u32 *)loaderOffset + 0x69) = loaderSize / 0x200 - 5;
} }
//Patch ARM9 entrypoint on N3DS to skip arm9loader
if(console)
firm->arm9Entry = (u8 *)0x801B01C;
//Write patched FIRM to SD if needed
if(selectedFirm)
if(!fileWrite(firm, patchedFirms[selectedFirm - 1], firmSize))
error("Couldn't write the patched FIRM (no free space?)");
} }
void launchFirm(void){ static inline void patchTwlAgbFirm(u32 firmType)
{
//On N3DS, decrypt ARM9Bin and patch ARM9 entrypoint to skip arm9loader
if(console)
{
arm9Loader((u8 *)firm + section[3].offset, 0);
firm->arm9Entry = (u8 *)0x801301C;
}
if(console && mode) setKeyXs(arm9Section); const patchData twlPatches[] = {
{{0x1650C0, 0x165D64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0x173A0E, 0x17474A}, { .type1 = 0x2001 }, 1},
{{0x174802, 0x17553E}, { .type1 = 0x2000 }, 2},
{{0x174964, 0x1756A0}, { .type1 = 0x2000 }, 2},
{{0x174D52, 0x175A8E}, { .type1 = 0x2001 }, 2},
{{0x174D5E, 0x175A9A}, { .type1 = 0x2001 }, 2},
{{0x174D6A, 0x175AA6}, { .type1 = 0x2001 }, 2},
{{0x174E56, 0x175B92}, { .type1 = 0x2001 }, 1},
{{0x174E58, 0x175B94}, { .type1 = 0x4770 }, 1}
},
agbPatches[] = {
{{0x9D2A8, 0x9DF64}, {{ 6, 0x00, 0x20, 0x4E, 0xB0, 0x70, 0xBD }}, 0},
{{0xD7A12, 0xD8B8A}, { .type1 = 0xEF26 }, 1}
};
/* Calculate the amount of patches to apply. Only count the boot screen patch for AGB_FIRM
if the matching option was enabled (keep it as last) */
u32 numPatches = firmType == 1 ? (sizeof(twlPatches) / sizeof(patchData)) : (sizeof(agbPatches) / sizeof(patchData) - !CONFIG(7));
const patchData *patches = firmType == 1 ? twlPatches : agbPatches;
//Patch
for(u32 i = 0; i < numPatches; i++)
{
switch(patches[i].type)
{
case 0:
memcpy((u8 *)firm + patches[i].offset[console], patches[i].patch.type0 + 1, patches[i].patch.type0[0]);
break;
case 2:
*(u16 *)((u8 *)firm + patches[i].offset[console] + 2) = 0;
case 1:
*(u16 *)((u8 *)firm + patches[i].offset[console]) = patches[i].patch.type1;
break;
}
}
}
static inline void launchFirm(u32 bootType)
{
//Copy firm partitions to respective memory locations //Copy firm partitions to respective memory locations
memcpy(section[0].address, (u8 *)firm + section[0].offset, section[0].size); for(u32 i = 0; i < 4 && section[i].size; i++)
memcpy(section[1].address, (u8 *)firm + section[1].offset, section[1].size); memcpy(section[i].address, (u8 *)firm + section[i].offset, section[i].size);
memcpy(section[2].address, arm9Section, section[2].size);
//Fixes N3DS 3D //Determine the ARM11 entry to use
vu32 *arm11;
if(bootType) arm11 = (u32 *)0x1FFFFFFC;
else
{
deinitScreens(); deinitScreens();
arm11 = (u32 *)0x1FFFFFF8;
}
//Set ARM11 kernel entrypoint //Set ARM11 kernel entrypoint
*(vu32 *)0x1FFFFFF8 = (u32)firm->arm11Entry; *arm11 = (u32)firm->arm11Entry;
//Final jump to arm9 kernel //Final jump to arm9 kernel
((void (*)())firm->arm9Entry)(); ((void (*)())firm->arm9Entry)();

View File

@@ -8,8 +8,8 @@
#include "types.h" #include "types.h"
#define PDN_MPCORE_CFG (*(vu8 *)0x10140FFC) #define PDN_MPCORE_CFG (*(vu32 *)0x10140FFC)
#define PDN_SPI_CNT (*(vu8 *)0x101401C0) #define PDN_SPI_CNT (*(vu32 *)0x101401C0)
//FIRM Header layout //FIRM Header layout
typedef struct firmSectionHeader { typedef struct firmSectionHeader {
@@ -29,7 +29,19 @@ typedef struct firmHeader {
firmSectionHeader section[4]; firmSectionHeader section[4];
} firmHeader; } firmHeader;
void setupCFW(void); typedef struct patchData {
void loadFirm(void); u32 offset[2];
void patchFirm(void); union {
void launchFirm(void); u8 type0[8];
u16 type1;
} patch;
u32 type;
} patchData;
static inline void loadFirm(u32 firmType, u32 externalFirm);
static inline void patchNativeFirm(u32 emuNAND, u32 emuHeader, u32 a9lhSetup);
static inline void patchEmuNAND(u8 *arm9Section, u8 *proc9Offset, u32 emuHeader);
static inline void patchReboots(u8 *arm9Section, u8 *proc9Offset);
static inline void injectLoader(void);
static inline void patchTwlAgbFirm(u32 firmType);
static inline void launchFirm(u32 bootType);

View File

@@ -5,31 +5,40 @@
*/ */
#include "fs.h" #include "fs.h"
#include "memory.h"
#include "fatfs/ff.h" #include "fatfs/ff.h"
static FATFS fs; static FATFS sdFs,
nandFs;
u32 mountFs(void)
{
if(f_mount(&sdFs, "0:", 1) != FR_OK) return 0;
f_mount(&nandFs, "1:", 0);
u32 mountSD(void){
if(f_mount(&fs, "0:", 1) != FR_OK) return 0;
return 1; return 1;
} }
u32 fileRead(void *dest, const char *path, u32 size){ u32 fileRead(void *dest, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
fr = f_open(&fp, path, FA_READ); fr = f_open(&fp, path, FA_READ);
if(fr == FR_OK){ if(fr == FR_OK)
{
if(!size) size = f_size(&fp); if(!size) size = f_size(&fp);
fr = f_read(&fp, dest, size, &br); fr = f_read(&fp, dest, size, &br);
} }
f_close(&fp); f_close(&fp);
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileWrite(const void *buffer, const char *path, u32 size){ u32 fileWrite(const void *buffer, const char *path, u32 size)
{
FRESULT fr; FRESULT fr;
FIL fp; FIL fp;
unsigned int br = 0; unsigned int br = 0;
@@ -38,10 +47,12 @@ u32 fileWrite(const void *buffer, const char *path, u32 size){
if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br); if(fr == FR_OK) fr = f_write(&fp, buffer, size, &br);
f_close(&fp); f_close(&fp);
return fr ? 0 : 1; return fr ? 0 : 1;
} }
u32 fileSize(const char *path){ u32 fileSize(const char *path)
{
FIL fp; FIL fp;
u32 size = 0; u32 size = 0;
@@ -49,19 +60,70 @@ u32 fileSize(const char *path){
size = f_size(&fp); size = f_size(&fp);
f_close(&fp); f_close(&fp);
return size; return size;
} }
u32 fileExists(const char *path){ u32 defPayloadExists(void)
FIL fp; {
u32 exists = 0; DIR dir;
FILINFO info = { .lfname = NULL };
if(f_open(&fp, path, FA_READ) == FR_OK) exists = 1; FRESULT result = f_findfirst(&dir, &info, "/aurei/payloads", "def_*.bin");
f_close(&fp); f_closedir(&dir);
return exists;
return (result == FR_OK && info.fname[0]);
} }
void fileDelete(const char *path){ void firmRead(void *dest, const char *firmFolder)
f_unlink(path); {
char path[48] = "1:/title/00040138/00000000/content";
memcpy(&path[18], firmFolder, 8);
DIR dir;
FILINFO info = { .lfname = NULL };
f_opendir(&dir, path);
u32 id = 0;
//Parse the target directory
while(f_readdir(&dir, &info) == FR_OK)
{
//We've parsed the whole folder
if(!info.fname[0]) break;
//Not a cxi
if(info.fname[9] != 'a' && info.fname[9] != 'A') continue;
//Convert the .app name to an integer
u32 tempId = 0;
for(char *tmp = info.fname; *tmp != '.'; tmp++)
{
tempId <<= 4;
tempId += *tmp > '9' ? *tmp - 'A' + 10 : *tmp - '0';
}
//Found a newer cxi
if(tempId > id) id = tempId;
}
f_closedir(&dir);
//Complete the string with the .app name
memcpy(&path[34], "/00000000.app", 14);
u32 i = 42;
//Convert back the .app name from integer to array
while(id > 0)
{
//Last digit of the .app
static const char hexDigits[] = "0123456789ABCDEF";
path[i--] = hexDigits[id & 0xF];
id >>= 4;
}
fileRead(dest, path, 0);
} }

View File

@@ -8,9 +8,9 @@
#include "types.h" #include "types.h"
u32 mountSD(void); u32 mountFs(void);
u32 fileRead(void *dest, const char *path, u32 size); u32 fileRead(void *dest, const char *path, u32 size);
u32 fileWrite(const void *buffer, const char *path, u32 size); u32 fileWrite(const void *buffer, const char *path, u32 size);
u32 fileSize(const char *path); u32 fileSize(const char *path);
u32 fileExists(const char *path); u32 defPayloadExists(void);
void fileDelete(const char *path); void firmRead(void *dest, const char *firmFolder);

View File

@@ -10,11 +10,13 @@ static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{2, 0xA4}, {2, 0x9A}, {2, 0xA0}, {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; 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; return dev_data[device_id].reg_addr;
} }
@@ -26,7 +28,8 @@ static vu8* reg_data_addrs[] = {
(vu8*)(I2C3_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]; return reg_data_addrs[bus_id];
} }
@@ -38,22 +41,27 @@ static vu8* reg_cnt_addrs[] = {
(vu8*)(I2C3_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]; 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); while (*i2cGetCntReg(bus_id) & 0x80);
} }
static inline u32 i2cGetResult(u8 bus_id) { static inline u32 i2cGetResult(u8 bus_id)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1; 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; *i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5; *i2cGetCntReg(bus_id) = 0xC5;
@@ -61,32 +69,40 @@ static void i2cStop(u8 bus_id, u8 arg0) {
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg) { static u32 i2cSelectDevice(u8 bus_id, u8 dev_reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg; *i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2; *i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
static u32 i2cSelectRegister(u8 bus_id, u8 reg) { static u32 i2cSelectRegister(u8 bus_id, u8 reg)
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg; *i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0; *i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id); return i2cGetResult(bus_id);
} }
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data) { u32 i2cWriteRegister(u8 dev_id, u8 reg, u8 data)
{
u8 bus_id = i2cGetDeviceBusId(dev_id); u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id); u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for (int i = 0; i < 8; i++) { for (u32 i = 0; i < 8; i++)
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) { {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg))
{
i2cWaitBusy(bus_id); i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data; *i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1; *i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0); i2cStop(bus_id, 0);
if (i2cGetResult(bus_id)) if (i2cGetResult(bus_id))
return 1; return 1;
} }

View File

@@ -12,8 +12,10 @@
#define PAYLOAD_ADDRESS 0x24F00000 #define PAYLOAD_ADDRESS 0x24F00000
void loadPayload(void){ void loadPayload(void)
if(fileExists("aurei/payloads/default.bin")){ {
if(defPayloadExists())
{
initScreens(); initScreens();
memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size); memcpy((void *)PAYLOAD_ADDRESS, loader, loader_size);
((void (*)())PAYLOAD_ADDRESS)(); ((void (*)())PAYLOAD_ADDRESS)();

View File

@@ -1,18 +0,0 @@
/*
* main.c
* by Reisyukaku / Aurora Wright
* Copyright (c) 2016 All Rights Reserved
*
* Minimalist CFW for (N)3DS
*/
#include "fs.h"
#include "firm.h"
void main(void){
mountSD();
setupCFW();
loadFirm();
patchFirm();
launchFirm();
}

View File

@@ -8,40 +8,43 @@
#include "memory.h" #include "memory.h"
void memcpy(void *dest, const void *src, u32 size){ void memcpy(void *dest, const void *src, u32 size)
{
u8 *destc = (u8 *)dest; u8 *destc = (u8 *)dest;
const u8 *srcc = (const u8 *)src; const u8 *srcc = (const u8 *)src;
for(u32 i = 0; i < size; i++) for(u32 i = 0; i < size; i++)
destc[i] = srcc[i]; destc[i] = srcc[i];
} }
void memset(void *dest, int filler, u32 size){ void memset32(void *dest, u32 filler, u32 size)
u8 *destc = (u8 *)dest; {
for(u32 i = 0; i < size; i++)
destc[i] = (u8)filler;
}
void memset32(void *dest, u32 filler, u32 size){
u32 *dest32 = (u32 *)dest; u32 *dest32 = (u32 *)dest;
for (u32 i = 0; i < size / 4; i++) for (u32 i = 0; i < size / 4; i++)
dest32[i] = filler; dest32[i] = filler;
} }
int memcmp(const void *buf1, const void *buf2, u32 size){ int memcmp(const void *buf1, const void *buf2, u32 size)
{
const u8 *buf1c = (const u8 *)buf1; const u8 *buf1c = (const u8 *)buf1;
const u8 *buf2c = (const u8 *)buf2; const u8 *buf2c = (const u8 *)buf2;
for(u32 i = 0; i < size; i++){
for(u32 i = 0; i < size; i++)
{
int cmp = buf1c[i] - buf2c[i]; int cmp = buf1c[i] - buf2c[i];
if(cmp) return cmp; if(cmp) return cmp;
} }
return 0; return 0;
} }
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize)
{
const u8 *patternc = (const u8 *)pattern; const u8 *patternc = (const u8 *)pattern;
//Preprocessing //Preprocessing
int table[256]; u32 table[256];
for(u32 i = 0; i < 256; ++i) for(u32 i = 0; i < 256; ++i)
table[i] = patternSize + 1; table[i] = patternSize + 1;
@@ -51,7 +54,8 @@ u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize){
//Searching //Searching
u32 j = 0; u32 j = 0;
while(j <= size - patternSize){ while(j <= size - patternSize)
{
if(memcmp(patternc, startPos + j, patternSize) == 0) if(memcmp(patternc, startPos + j, patternSize) == 0)
return startPos + j; return startPos + j;
j += table[startPos[j + patternSize]]; j += table[startPos[j + patternSize]];

View File

@@ -11,7 +11,6 @@
#include "types.h" #include "types.h"
void memcpy(void *dest, const void *src, u32 size); void memcpy(void *dest, const void *src, u32 size);
void memset(void *dest, int filler, u32 size);
void memset32(void *dest, u32 filler, u32 size); void memset32(void *dest, u32 filler, u32 size);
int memcmp(const void *buf1, const void *buf2, u32 size); int memcmp(const void *buf1, const void *buf2, u32 size);
u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize); u8 *memsearch(u8 *startPos, const void *pattern, u32 size, u32 patternSize);

View File

@@ -19,15 +19,19 @@ const u16 sigPatch[2] = {0x2000, 0x4770};
const u16 writeBlock[2] = {0x2000, 0x46C0}; const u16 writeBlock[2] = {0x2000, 0x46C0};
const u8 unitInfoPatch = 0xE3;
/************************************************** /**************************************************
* Functions * Functions
**************************************************/ **************************************************/
u8 *getProc9(u8 *pos, u32 size){ u8 *getProc9(u8 *pos, u32 size)
{
return memsearch(pos, "ess9", size, 4); return memsearch(pos, "ess9", size, 4);
} }
void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2)
{
//Look for signature checks //Look for signature checks
const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7}, const u8 pattern[] = {0xC0, 0x1C, 0x76, 0xE7},
pattern2[] = {0xB5, 0x22, 0x4D, 0x0C}; pattern2[] = {0xB5, 0x22, 0x4D, 0x0C};
@@ -36,16 +40,19 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2){
*off2 = (u32)memsearch(pos, pattern2, size, 4) - 1; *off2 = (u32)memsearch(pos, pattern2, size, 4) - 1;
} }
void *getReboot(u8 *pos, u32 size){ void *getReboot(u8 *pos, u32 size)
{
//Look for FIRM reboot code //Look for FIRM reboot code
const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2}; const u8 pattern[] = {0xDE, 0x1F, 0x8D, 0xE2};
return memsearch(pos, pattern, size, 4) - 0x10; return memsearch(pos, pattern, size, 4) - 0x10;
} }
u32 getfOpen(u8 *proc9Offset, void *rebootOffset){ u32 getfOpen(u8 *proc9Offset, void *rebootOffset)
{
//Offset Process9 code gets loaded to in memory (defined in ExHeader) //Offset Process9 code gets loaded to in memory (defined in ExHeader)
u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC); u32 p9MemAddr = *(u32 *)(proc9Offset + 0xC);
//Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size) //Process9 code offset (start of NCCH + ExeFS offset + ExeFS header size)
u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200; u32 p9CodeOff = (u32)(proc9Offset - 0x204) + (*(u32 *)(proc9Offset - 0x64) * 0x200) + 0x200;
@@ -53,7 +60,8 @@ u32 getfOpen(u8 *proc9Offset, void *rebootOffset){
return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr; return (u32)rebootOffset + 9 - (-((*(u32 *)rebootOffset & 0x00FFFFFF) << 2) & 0xFFFFF) - p9CodeOff + p9MemAddr;
} }
u16 *getFirmWrite(u8 *pos, u32 size){ u16 *getFirmWrite(u8 *pos, u32 size)
{
//Look for FIRM writing code //Look for FIRM writing code
u8 *const off = memsearch(pos, "exe:", size, 4); u8 *const off = memsearch(pos, "exe:", size, 4);
const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA}; const u8 pattern[] = {0x00, 0x28, 0x01, 0xDA};
@@ -61,9 +69,19 @@ u16 *getFirmWrite(u8 *pos, u32 size){
return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4); return (u16 *)memsearch(off - 0x100, pattern, 0x100, 4);
} }
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize){ u8 *getUnitInfoValueSet(u8 *pos, u32 size)
{
//Look for UNITINFO value being set
const u8 pattern[] = {0x01, 0x10, 0xA0, 0x13};
return memsearch(pos, pattern, size, 4) + 3;
}
void *getLoader(u8 *pos, u32 size, u32 *loaderSize)
{
u8 *const off = memsearch(pos, "loade", size, 5); u8 *const off = memsearch(pos, "loade", size, 5);
*loaderOffset = (u32)off - 0x200;
*loaderSize = *(u32 *)(off - 0xFC) * 0x200; *loaderSize = *(u32 *)(off - 0xFC) * 0x200;
return off - 0x200;
} }

View File

@@ -15,6 +15,7 @@ const u32 mpuPatch[3];
const u16 nandRedir[2]; const u16 nandRedir[2];
const u16 sigPatch[2]; const u16 sigPatch[2];
const u16 writeBlock[2]; const u16 writeBlock[2];
const u8 unitInfoPatch;
/************************************************** /**************************************************
* Functions * Functions
@@ -24,4 +25,5 @@ void getSigChecks(u8 *pos, u32 size, u32 *off, u32 *off2);
void *getReboot(u8 *pos, u32 size); void *getReboot(u8 *pos, u32 size);
u32 getfOpen(u8 *proc9Offset, void *rebootOffset); u32 getfOpen(u8 *proc9Offset, void *rebootOffset);
u16 *getFirmWrite(u8 *pos, u32 size); u16 *getFirmWrite(u8 *pos, u32 size);
void getLoader(u8 *pos, u32 size, u32 *loaderOffset, u32 *loaderSize); u8 *getUnitInfoValueSet(u8 *pos, u32 size);
void *getLoader(u8 *pos, u32 size, u32 *loaderSize);

View File

@@ -8,18 +8,25 @@
*/ */
#include "screeninit.h" #include "screeninit.h"
#include "config.h"
#include "memory.h"
#include "draw.h" #include "draw.h"
#include "i2c.h" #include "i2c.h"
#include "../build/screeninit.h"
static vu32 *const arm11 = (u32 *)0x1FFFFFF8; #define SCREENINIT_ADDRESS 0x24F03000
void deinitScreens(void){ vu32 *arm11Entry = (u32 *)0x1FFFFFF8;
void __attribute__((naked)) ARM11(void){
void deinitScreens(void)
{
void __attribute__((naked)) ARM11(void)
{
//Disable interrupts //Disable interrupts
__asm(".word 0xF10C01C0"); __asm(".word 0xF10C01C0");
//Clear ARM11 entry offset //Clear ARM11 entry offset
*arm11 = 0; *arm11Entry = 0;
//Shutdown LCDs //Shutdown LCDs
*(vu32 *)0x10202A44 = 0; *(vu32 *)0x10202A44 = 0;
@@ -27,125 +34,33 @@ void deinitScreens(void){
*(vu32 *)0x10202014 = 0; *(vu32 *)0x10202014 = 0;
//Wait for the entry to be set //Wait for the entry to be set
while(!*arm11); while(!*arm11Entry);
//Jump to it //Jump to it
((void (*)())*arm11)(); ((void (*)())*arm11Entry)();
} }
if(PDN_GPU_CNT != 0x1){ if(PDN_GPU_CNT != 1)
*arm11 = (u32)ARM11; {
while(*arm11); *arm11Entry = (u32)ARM11;
while(*arm11Entry);
} }
} }
void initScreens(void){ void initScreens(void)
void __attribute__((naked)) ARM11(void){ {
//Disable interrupts if(PDN_GPU_CNT == 1)
__asm(".word 0xF10C01C0"); {
memcpy((void *)SCREENINIT_ADDRESS, screeninit, screeninit_size);
*(vu32 *)0x10141200 = 0x1007F; //Write brightness level for the stub to pick up
*(vu32 *)0x10202014 = 0x00000001; *(vu32 *)(SCREENINIT_ADDRESS + 8) = MULTICONFIG(0);
*(vu32 *)0x1020200C &= 0xFFFEFFFE;
*(vu32 *)0x10202240 = 0x45;
*(vu32 *)0x10202A40 = 0x45;
*(vu32 *)0x10202244 = 0x1023E;
*(vu32 *)0x10202A44 = 0x1023E;
// Top screen *arm11Entry = SCREENINIT_ADDRESS;
*(vu32 *)0x10400400 = 0x000001c2; while(*arm11Entry);
*(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 //Turn on backlight
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); 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;
//Wait for the entry to be set
while(!*arm11);
//Jump to it
((void (*)())*arm11)();
}
if(PDN_GPU_CNT == 0x1){
*arm11 = (u32)ARM11;
while(*arm11);
} }
clearScreens(); clearScreens();

View File

@@ -2,6 +2,11 @@
.align 4 .align 4
.global _start .global _start
_start: _start:
b start
.word 0
start:
@ Change the stack pointer @ Change the stack pointer
mov sp, #0x27000000 mov sp, #0x27000000
@@ -28,9 +33,9 @@ _start:
mcr p15, 0, r6, c6, c6, 0 mcr p15, 0, r6, c6, c6, 0
mcr p15, 0, r7, c6, c7, 0 mcr p15, 0, r7, c6, c7, 0
mov r0, #0x25 mov r0, #0x25
mcr p15, 0, r0, c2, c0, 0 @ data cacheable mcr p15, 0, r0, c3, c0, 0 @ Write bufferable 0, 2, 5
mcr p15, 0, r0, c2, c0, 1 @ instruction cacheable mcr p15, 0, r0, c2, c0, 0 @ Data cacheable 0, 2, 5
mcr p15, 0, r0, c3, c0, 0 @ data bufferable mcr p15, 0, r0, c2, c0, 1 @ Inst cacheable 0, 2, 5
@ Enable caches @ Enable caches
mrc p15, 0, r0, c1, c0, 0 @ read control register mrc p15, 0, r0, c1, c0, 0 @ read control register
@@ -50,7 +55,4 @@ _start:
mov r1, #0x340 mov r1, #0x340
str r1, [r0] str r1, [r0]
bl main b main
.die:
b .die

View File

@@ -7,128 +7,50 @@
#include "utils.h" #include "utils.h"
#include "screeninit.h" #include "screeninit.h"
#include "draw.h" #include "draw.h"
#include "fs.h"
#include "i2c.h" #include "i2c.h"
#include "buttons.h" #include "buttons.h"
#define COLOR_TITLE 0xFF9900 u32 waitInput(void)
#define COLOR_WHITE 0xFFFFFF {
#define COLOR_RED 0x0000FF u32 pressedKey = 0,
#define COLOR_BLACK 0x000000 key;
struct option {
int posY;
u32 enabled;
};
static u16 waitInput(void){
u32 pressedKey = 0;
u16 key;
//Wait for no keys to be pressed //Wait for no keys to be pressed
while(HID_PAD); while(HID_PAD);
do { do
{
//Wait for a key to be pressed //Wait for a key to be pressed
while(!HID_PAD); while(!HID_PAD);
key = HID_PAD; key = HID_PAD;
//Make sure it's pressed //Make sure it's pressed
for(u32 i = 0x13000; i; i--){ for(u32 i = 0x13000; i; i--)
{
if(key != HID_PAD) break; if(key != HID_PAD) break;
if(i == 1) pressedKey = 1; if(i == 1) pressedKey = 1;
} }
} while(!pressedKey); }
while(!pressedKey);
return key; return key;
} }
void configureCFW(const char *configPath, const char *firm90Path){ void mcuShutDown(void)
initScreens(); {
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
while(1);
}
drawString(CONFIG_TITLE, 10, 10, COLOR_TITLE); void mcuReboot(void)
drawString("Press A to select, START to save and reboot", 10, 30, COLOR_WHITE); {
const char *optionsText[] = { "( ) Updated SysNAND mode (A9LH-only)",
"( ) Use pre-patched FIRMs",
"( ) Force A9LH detection",
"( ) Use 9.0 FIRM as default",
"( ) Use second EmuNAND as default",
"( ) Show current NAND in System Settings" };
u32 optionsAmount = sizeof(optionsText) / sizeof(char *);
struct option options[optionsAmount];
//Read and parse the existing configuration
u32 tempConfig = 0;
fileRead(&tempConfig, configPath, 3);
for(u32 i = 0; i < optionsAmount; i++)
options[i].enabled = (tempConfig >> i) & 0x1;
//Pre-select the first configuration option
u32 selectedOption = 0;
//Boring configuration menu
while(1){
u16 pressed = 0;
do{
for(u32 i = 0; i < optionsAmount; i++){
options[i].posY = drawString(optionsText[i], 10, !i ? 60 : options[i - 1].posY + SPACING_Y, selectedOption == i ? COLOR_RED : COLOR_WHITE);
drawCharacter('x', 10 + SPACING_X, options[i].posY, options[i].enabled ? (selectedOption == i ? COLOR_RED : COLOR_WHITE) : COLOR_BLACK);
}
pressed = waitInput();
} while(!(pressed & MENU_BUTTONS));
switch(pressed){
case BUTTON_UP:
selectedOption = !selectedOption ? optionsAmount - 1 : selectedOption - 1;
break;
case BUTTON_DOWN:
selectedOption = selectedOption == optionsAmount - 1 ? 0 : selectedOption + 1;
break;
case BUTTON_LEFT:
selectedOption = 0;
break;
case BUTTON_RIGHT:
selectedOption = optionsAmount - 1;
break;
case BUTTON_A:
options[selectedOption].enabled = !options[selectedOption].enabled;
break;
}
if(pressed == BUTTON_START) break;
}
//If the user has been using A9LH and the "Updated SysNAND" setting changed, delete the patched 9.0 FIRM
if(((tempConfig >> 16) & 0x1) && ((tempConfig & 0x1) != options[0].enabled))
fileDelete(firm90Path);
//Preserve the last-used boot options (last 12 bits)
tempConfig &= 0xFFF000;
//Parse and write the selected options
for(u32 i = 0; i < optionsAmount; i++)
tempConfig |= options[i].enabled << i;
fileWrite(&tempConfig, configPath, 3);
//Zero the last booted FIRM flag
CFG_BOOTENV = 0;
//Reboot
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2); i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(1); while(1);
} }
void deleteFirms(const char *firmPaths[], u32 firms){ void error(const char *message)
while(firms){ {
fileDelete(firmPaths[firms - 1]);
firms--;
}
}
void error(const char *message){
initScreens(); initScreens();
drawString("An error has occurred:", 10, 10, COLOR_RED); drawString("An error has occurred:", 10, 10, COLOR_RED);
@@ -137,7 +59,5 @@ void error(const char *message){
waitInput(); waitInput();
//Shutdown mcuShutDown();
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1);
while(1);
} }

View File

@@ -8,8 +8,7 @@
#include "types.h" #include "types.h"
#define CFG_BOOTENV (*(vu8 *)0x10010000) u32 waitInput(void);
void mcuShutDown(void);
void configureCFW(const char *configPath, const char *firm90Path); void mcuReboot(void);
void deleteFirms(const char *firmPaths[], u32 firms);
void error(const char *message); void error(const char *message);