Took over source files from Decrypt9

... this is not compilable and by no means anywhere near even a proof of
concept now.
This commit is contained in:
d0k3 2016-02-13 17:29:56 +01:00
parent 0eff8e99cf
commit 0df734a76a
54 changed files with 15784 additions and 0 deletions

6
.gitignore vendored
View File

@ -30,3 +30,9 @@
# Debug files
*.dSYM/
# Build directories
/build
/output
/release
/zzz_backup

11
.gitmodules vendored Normal file
View File

@ -0,0 +1,11 @@
[submodule "CakeHax"]
path = CakeHax
url = https://github.com/mid-kid/CakeHax
[submodule "BrahmaLoader"]
path = BrahmaLoader
url = https://github.com/d0k3/BrahmaLoader
ignore = dirty
[submodule "CakesROP"]
path = CakesROP
url = https://github.com/mid-kid/CakesROP
ignore = dirty

41
.travis.yml Normal file
View File

@ -0,0 +1,41 @@
language: c
before_install:
- wget http://sourceforge.net/projects/devkitpro/files/Automated%20Installer/devkitARMupdate.pl
- export DEVKITPRO=/home/travis/devkitPro
- export DEVKITARM=${DEVKITPRO}/devkitARM
install:
- sudo perl devkitARMupdate.pl
script:
- git submodule update --init --recursive
- make gateway
- mv output/Launcher.dat .
- make clean
- make bootstrap
- mv output/Decrypt9.bin .
env:
global:
secure: "QeQ3FDs8vOcB7+TJBPIszTPo6EuYOTcqTlC15fAXTHLLnGsY36ySSMKXKq9aV5mqJr9t92WGY169fAW35vg9wwQAx09A2EIEkaqLysozkNxaR9LralgwEEAXXJP2lD5NvJ0n13PMPloGyDCnjBRUjJ+WdDz5H6F329PbItKo5uE="
after_success:
- >
if [ "$TRAVIS_BRANCH" == "master" ]; then
GITDATE="`git show -s --date=short --format='%ad' | sed 's/-//g'`"
GITREV="`git show -s --format='%h'`"
REV_NAME_GW="decrypt9-${GITDATE}-${GITREV}-browser"
REV_NAME_BS="decrypt9-${GITDATE}-${GITREV}-bootstrap"
sudo apt-get -qq install lftp p7zip-full
mkdir "$REV_NAME_GW" "$REV_NAME_BS"
cp -R README.md Launcher.dat scripts "$REV_NAME_GW"
cp -R README.md Decrypt9.bin scripts "$REV_NAME_BS"
7z a "$REV_NAME_GW" "$REV_NAME_GW/*"
7z a "$REV_NAME_BS" "$REV_NAME_BS/*"
lftp -c "open -u builds,$BUILD_PASSWORD sftp://archshift.com; put -O '/decrypt9/nightly/browser' '${REV_NAME_GW}.7z'"
lftp -c "open -u builds,$BUILD_PASSWORD sftp://archshift.com; put -O '/decrypt9/nightly/bootstrap' '${REV_NAME_BS}.7z'"
fi

193
Makefile Normal file
View File

@ -0,0 +1,193 @@
#---------------------------------------------------------------------------------
.SUFFIXES:
#---------------------------------------------------------------------------------
ifeq ($(strip $(DEVKITARM)),)
$(error "Please set DEVKITARM in your environment. export DEVKITARM=<path to>devkitARM")
endif
include $(DEVKITARM)/ds_rules
#---------------------------------------------------------------------------------
# TARGET is the name of the output
# BUILD is the directory where object files & intermediate files will be placed
# SOURCES is a list of directories containing source code
# 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 := GodMode9
BUILD := build
SOURCES := source source/fatfs source/fatfs/crypto source/abstraction
DATA := data
INCLUDES := include source source/fatfs source/fatfs/crypto
#---------------------------------------------------------------------------------
# options for code generation
#---------------------------------------------------------------------------------
ARCH := -mthumb -mthumb-interwork
CFLAGS := -g -Wall -O2\
-march=armv5te -mtune=arm946e-s -fomit-frame-pointer\
-ffast-math -std=c99\
$(ARCH)
CFLAGS += $(INCLUDE) -DEXEC_$(EXEC_METHOD) -DARM9
CFLAGS += -DBUILD_NAME="\"$(TARGET) (`date +'%Y/%m/%d'`)\""
ifneq ($(strip $(THEME)),)
CFLAGS += -DUSE_THEME=\"\/$(THEME)\"
endif
CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions
ASFLAGS := -g $(ARCH) -DEXEC_$(EXEC_METHOD)
LDFLAGS = -nostartfiles -g $(ARCH) -Wl,-Map,$(TARGET).map
ifeq ($(EXEC_METHOD),GATEWAY)
LDFLAGS += --specs=../gateway.specs
else ifeq ($(EXEC_METHOD),BOOTSTRAP)
LDFLAGS += --specs=../bootstrap.specs
endif
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_D := $(CURDIR)/output
export OUTPUT := $(OUTPUT_D)/$(TARGET)
export RELEASE := $(CURDIR)/release
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: common clean all gateway bootstrap cakehax cakerop brahma release
#---------------------------------------------------------------------------------
all: brahma
common:
@[ -d $(OUTPUT_D) ] || mkdir -p $(OUTPUT_D)
@[ -d $(BUILD) ] || mkdir -p $(BUILD)
submodules:
@-git submodule update --init --recursive
gateway: common
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile EXEC_METHOD=GATEWAY
@cp resources/LauncherTemplate.dat $(OUTPUT_D)/Launcher.dat
@dd if=$(OUTPUT).bin of=$(OUTPUT_D)/Launcher.dat bs=1497296 seek=1 conv=notrunc
bootstrap: common
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile EXEC_METHOD=BOOTSTRAP
cakehax: submodules common
@make --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile EXEC_METHOD=GATEWAY
@make dir_out=$(OUTPUT_D) name=$(TARGET).dat -C CakeHax bigpayload
@dd if=$(OUTPUT).bin of=$(OUTPUT).dat bs=512 seek=160
cakerop: cakehax
@make DATNAME=$(TARGET).dat DISPNAME=$(TARGET) GRAPHICS=../resources/CakesROP -C CakesROP
@mv CakesROP/CakesROP.nds $(OUTPUT_D)/$(TARGET).nds
brahma: submodules bootstrap
@[ -d BrahmaLoader/data ] || mkdir -p BrahmaLoader/data
@cp $(OUTPUT).bin BrahmaLoader/data/payload.bin
@cp resources/BrahmaAppInfo BrahmaLoader/resources/AppInfo
@cp resources/BrahmaIcon.png BrahmaLoader/resources/icon.png
@make --no-print-directory -C BrahmaLoader APP_TITLE=$(TARGET)
@mv BrahmaLoader/output/*.3dsx $(OUTPUT_D)
@mv BrahmaLoader/output/*.smdh $(OUTPUT_D)
release:
@rm -fr $(BUILD) $(OUTPUT_D) $(RELEASE)
@make --no-print-directory gateway
@-make --no-print-directory cakerop
@rm -fr $(BUILD) $(OUTPUT).bin $(OUTPUT).elf $(CURDIR)/$(LOADER)/data
@-make --no-print-directory brahma
@[ -d $(RELEASE) ] || mkdir -p $(RELEASE)
@[ -d $(RELEASE)/$(TARGET) ] || mkdir -p $(RELEASE)/$(TARGET)
@cp $(OUTPUT_D)/Launcher.dat $(RELEASE)
@-cp $(OUTPUT).bin $(RELEASE)
@-cp $(OUTPUT).dat $(RELEASE)
@-cp $(OUTPUT).nds $(RELEASE)
@-cp $(OUTPUT).3dsx $(RELEASE)/$(TARGET)
@-cp $(OUTPUT).smdh $(RELEASE)/$(TARGET)
@cp $(CURDIR)/README.md $(RELEASE)
@-7z a $(RELEASE)/$(TARGET)-`date +'%Y%m%d-%H%M%S'`.zip $(RELEASE)/*
#---------------------------------------------------------------------------------
clean:
@echo clean ...
@-make clean --no-print-directory -C CakeHax
@-make clean --no-print-directory -C CakesROP
@-make clean --no-print-directory -C BrahmaLoader
@rm -fr $(BUILD) $(OUTPUT_D) $(RELEASE)
#---------------------------------------------------------------------------------
else
DEPENDS := $(OFILES:.o=.d)
#---------------------------------------------------------------------------------
# main targets
#---------------------------------------------------------------------------------
$(OUTPUT).bin : $(OUTPUT).elf
$(OUTPUT).elf : $(OFILES)
#---------------------------------------------------------------------------------
%.bin: %.elf
@$(OBJCOPY) --set-section-flags .bss=alloc,load,contents -O binary $< $@
@echo built ... $(notdir $@)
-include $(DEPENDS)
#---------------------------------------------------------------------------------------
endif
#---------------------------------------------------------------------------------------

130
bootstrap.ld Normal file
View File

@ -0,0 +1,130 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x23F00000, LENGTH = 128K
}
SECTIONS
{
.init :
{
__text_start = . ;
KEEP (*(.init))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.plt : { *(.plt) } >ram = 0xff
.text : /* ALIGN (4): */
{
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.fini :
{
KEEP (*(.fini))
} >ram =0xff
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ram
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ram
__exidx_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { KEEP (*(.preinit_array)) } >ram = 0xff
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { KEEP (*(.init_array)) } >ram = 0xff
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { KEEP (*(.fini_array)) } >ram = 0xff
PROVIDE (__fini_array_end = .);
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.jcr : { KEEP (*(.jcr)) } >ram = 0
.got : { *(.got.plt) *(.got) } >ram = 0
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >ram = 0xff
.bss ALIGN(4) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__bss_end__ = ABSOLUTE(.);
__end__ = ABSOLUTE(.);
} >ram
.stack 0x80000 : { _stack = .; *(.stack) }
}

5
bootstrap.specs Normal file
View File

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

130
gateway.ld Normal file
View File

@ -0,0 +1,130 @@
OUTPUT_FORMAT("elf32-littlearm", "elf32-bigarm", "elf32-littlearm")
OUTPUT_ARCH(arm)
ENTRY(_start)
MEMORY
{
ram : ORIGIN = 0x08000000, LENGTH = 128K
}
SECTIONS
{
.init :
{
__text_start = . ;
KEEP (*(.init))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.plt : { *(.plt) } >ram = 0xff
.text : /* ALIGN (4): */
{
*(.text .stub .text.* .gnu.linkonce.t.*)
KEEP (*(.text.*personality*))
/* .gnu.warning sections are handled specially by elf32.em. */
*(.gnu.warning)
*(.glue_7t) *(.glue_7) *(.vfp11_veneer)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.fini :
{
KEEP (*(.fini))
} >ram =0xff
__text_end = . ;
.rodata :
{
*(.rodata)
*all.rodata*(*)
*(.roda)
*(.rodata.*)
*(.gnu.linkonce.r*)
SORT(CONSTRUCTORS)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.ARM.extab : { *(.ARM.extab* .gnu.linkonce.armextab.*) } >ram
__exidx_start = .;
.ARM.exidx : { *(.ARM.exidx* .gnu.linkonce.armexidx.*) } >ram
__exidx_end = .;
/* Ensure the __preinit_array_start label is properly aligned. We
could instead move the label definition inside the section, but
the linker would then create the section even if it turns out to
be empty, which isn't pretty. */
. = ALIGN(32 / 8);
PROVIDE (__preinit_array_start = .);
.preinit_array : { KEEP (*(.preinit_array)) } >ram = 0xff
PROVIDE (__preinit_array_end = .);
PROVIDE (__init_array_start = .);
.init_array : { KEEP (*(.init_array)) } >ram = 0xff
PROVIDE (__init_array_end = .);
PROVIDE (__fini_array_start = .);
.fini_array : { KEEP (*(.fini_array)) } >ram = 0xff
PROVIDE (__fini_array_end = .);
.ctors :
{
/* gcc uses crtbegin.o to find the start of the constructors, so
we make sure it is first. Because this is a wildcard, it
doesn't matter if the user does not actually link against
crtbegin.o; the linker won't look for a file to match a
wildcard. The wildcard also means that it doesn't matter which
directory crtbegin.o is in. */
KEEP (*crtbegin.o(.ctors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .ctors))
KEEP (*(SORT(.ctors.*)))
KEEP (*(.ctors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.dtors :
{
KEEP (*crtbegin.o(.dtors))
KEEP (*(EXCLUDE_FILE (*crtend.o) .dtors))
KEEP (*(SORT(.dtors.*)))
KEEP (*(.dtors))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.eh_frame :
{
KEEP (*(.eh_frame))
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.gcc_except_table :
{
*(.gcc_except_table)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
} >ram = 0xff
.jcr : { KEEP (*(.jcr)) } >ram = 0
.got : { *(.got.plt) *(.got) } >ram = 0
.data ALIGN(4) : {
__data_start = ABSOLUTE(.);
*(.data)
*(.data.*)
*(.gnu.linkonce.d*)
CONSTRUCTORS
. = ALIGN(4);
__data_end = ABSOLUTE(.) ;
} >ram = 0xff
.bss ALIGN(4) :
{
__bss_start = ABSOLUTE(.);
__bss_start__ = ABSOLUTE(.);
*(.dynbss)
*(.gnu.linkonce.b*)
*(.bss*)
*(COMMON)
. = ALIGN(4); /* REQUIRED. LD is flaky without it. */
__bss_end__ = ABSOLUTE(.);
__end__ = ABSOLUTE(.);
} >ram
.stack 0x80000 : { _stack = .; *(.stack) }
}

5
gateway.specs Normal file
View File

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

339
license.txt Normal file
View File

@ -0,0 +1,339 @@
GNU GENERAL PUBLIC LICENSE
Version 2, June 1991
Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
Everyone is permitted to copy and distribute verbatim copies
of this license document, but changing it is not allowed.
Preamble
The licenses for most software are designed to take away your
freedom to share and change it. By contrast, the GNU General Public
License is intended to guarantee your freedom to share and change free
software--to make sure the software is free for all its users. This
General Public License applies to most of the Free Software
Foundation's software and to any other program whose authors commit to
using it. (Some other Free Software Foundation software is covered by
the GNU Lesser General Public License instead.) You can apply it to
your programs, too.
When we speak of free software, we are referring to freedom, not
price. Our General Public Licenses are designed to make sure that you
have the freedom to distribute copies of free software (and charge for
this service if you wish), that you receive source code or can get it
if you want it, that you can change the software or use pieces of it
in new free programs; and that you know you can do these things.
To protect your rights, we need to make restrictions that forbid
anyone to deny you these rights or to ask you to surrender the rights.
These restrictions translate to certain responsibilities for you if you
distribute copies of the software, or if you modify it.
For example, if you distribute copies of such a program, whether
gratis or for a fee, you must give the recipients all the rights that
you have. You must make sure that they, too, receive or can get the
source code. And you must show them these terms so they know their
rights.
We protect your rights with two steps: (1) copyright the software, and
(2) offer you this license which gives you legal permission to copy,
distribute and/or modify the software.
Also, for each author's protection and ours, we want to make certain
that everyone understands that there is no warranty for this free
software. If the software is modified by someone else and passed on, we
want its recipients to know that what they have is not the original, so
that any problems introduced by others will not reflect on the original
authors' reputations.
Finally, any free program is threatened constantly by software
patents. We wish to avoid the danger that redistributors of a free
program will individually obtain patent licenses, in effect making the
program proprietary. To prevent this, we have made it clear that any
patent must be licensed for everyone's free use or not licensed at all.
The precise terms and conditions for copying, distribution and
modification follow.
GNU GENERAL PUBLIC LICENSE
TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
0. This License applies to any program or other work which contains
a notice placed by the copyright holder saying it may be distributed
under the terms of this General Public License. The "Program", below,
refers to any such program or work, and a "work based on the Program"
means either the Program or any derivative work under copyright law:
that is to say, a work containing the Program or a portion of it,
either verbatim or with modifications and/or translated into another
language. (Hereinafter, translation is included without limitation in
the term "modification".) Each licensee is addressed as "you".
Activities other than copying, distribution and modification are not
covered by this License; they are outside its scope. The act of
running the Program is not restricted, and the output from the Program
is covered only if its contents constitute a work based on the
Program (independent of having been made by running the Program).
Whether that is true depends on what the Program does.
1. You may copy and distribute verbatim copies of the Program's
source code as you receive it, in any medium, provided that you
conspicuously and appropriately publish on each copy an appropriate
copyright notice and disclaimer of warranty; keep intact all the
notices that refer to this License and to the absence of any warranty;
and give any other recipients of the Program a copy of this License
along with the Program.
You may charge a fee for the physical act of transferring a copy, and
you may at your option offer warranty protection in exchange for a fee.
2. You may modify your copy or copies of the Program or any portion
of it, thus forming a work based on the Program, and copy and
distribute such modifications or work under the terms of Section 1
above, provided that you also meet all of these conditions:
a) You must cause the modified files to carry prominent notices
stating that you changed the files and the date of any change.
b) You must cause any work that you distribute or publish, that in
whole or in part contains or is derived from the Program or any
part thereof, to be licensed as a whole at no charge to all third
parties under the terms of this License.
c) If the modified program normally reads commands interactively
when run, you must cause it, when started running for such
interactive use in the most ordinary way, to print or display an
announcement including an appropriate copyright notice and a
notice that there is no warranty (or else, saying that you provide
a warranty) and that users may redistribute the program under
these conditions, and telling the user how to view a copy of this
License. (Exception: if the Program itself is interactive but
does not normally print such an announcement, your work based on
the Program is not required to print an announcement.)
These requirements apply to the modified work as a whole. If
identifiable sections of that work are not derived from the Program,
and can be reasonably considered independent and separate works in
themselves, then this License, and its terms, do not apply to those
sections when you distribute them as separate works. But when you
distribute the same sections as part of a whole which is a work based
on the Program, the distribution of the whole must be on the terms of
this License, whose permissions for other licensees extend to the
entire whole, and thus to each and every part regardless of who wrote it.
Thus, it is not the intent of this section to claim rights or contest
your rights to work written entirely by you; rather, the intent is to
exercise the right to control the distribution of derivative or
collective works based on the Program.
In addition, mere aggregation of another work not based on the Program
with the Program (or with a work based on the Program) on a volume of
a storage or distribution medium does not bring the other work under
the scope of this License.
3. You may copy and distribute the Program (or a work based on it,
under Section 2) in object code or executable form under the terms of
Sections 1 and 2 above provided that you also do one of the following:
a) Accompany it with the complete corresponding machine-readable
source code, which must be distributed under the terms of Sections
1 and 2 above on a medium customarily used for software interchange; or,
b) Accompany it with a written offer, valid for at least three
years, to give any third party, for a charge no more than your
cost of physically performing source distribution, a complete
machine-readable copy of the corresponding source code, to be
distributed under the terms of Sections 1 and 2 above on a medium
customarily used for software interchange; or,
c) Accompany it with the information you received as to the offer
to distribute corresponding source code. (This alternative is
allowed only for noncommercial distribution and only if you
received the program in object code or executable form with such
an offer, in accord with Subsection b above.)
The source code for a work means the preferred form of the work for
making modifications to it. For an executable work, complete source
code means all the source code for all modules it contains, plus any
associated interface definition files, plus the scripts used to
control compilation and installation of the executable. However, as a
special exception, the source code distributed need not include
anything that is normally distributed (in either source or binary
form) with the major components (compiler, kernel, and so on) of the
operating system on which the executable runs, unless that component
itself accompanies the executable.
If distribution of executable or object code is made by offering
access to copy from a designated place, then offering equivalent
access to copy the source code from the same place counts as
distribution of the source code, even though third parties are not
compelled to copy the source along with the object code.
4. You may not copy, modify, sublicense, or distribute the Program
except as expressly provided under this License. Any attempt
otherwise to copy, modify, sublicense or distribute the Program is
void, and will automatically terminate your rights under this License.
However, parties who have received copies, or rights, from you under
this License will not have their licenses terminated so long as such
parties remain in full compliance.
5. You are not required to accept this License, since you have not
signed it. However, nothing else grants you permission to modify or
distribute the Program or its derivative works. These actions are
prohibited by law if you do not accept this License. Therefore, by
modifying or distributing the Program (or any work based on the
Program), you indicate your acceptance of this License to do so, and
all its terms and conditions for copying, distributing or modifying
the Program or works based on it.
6. Each time you redistribute the Program (or any work based on the
Program), the recipient automatically receives a license from the
original licensor to copy, distribute or modify the Program subject to
these terms and conditions. You may not impose any further
restrictions on the recipients' exercise of the rights granted herein.
You are not responsible for enforcing compliance by third parties to
this License.
7. If, as a consequence of a court judgment or allegation of patent
infringement or for any other reason (not limited to patent issues),
conditions are imposed on you (whether by court order, agreement or
otherwise) that contradict the conditions of this License, they do not
excuse you from the conditions of this License. If you cannot
distribute so as to satisfy simultaneously your obligations under this
License and any other pertinent obligations, then as a consequence you
may not distribute the Program at all. For example, if a patent
license would not permit royalty-free redistribution of the Program by
all those who receive copies directly or indirectly through you, then
the only way you could satisfy both it and this License would be to
refrain entirely from distribution of the Program.
If any portion of this section is held invalid or unenforceable under
any particular circumstance, the balance of the section is intended to
apply and the section as a whole is intended to apply in other
circumstances.
It is not the purpose of this section to induce you to infringe any
patents or other property right claims or to contest validity of any
such claims; this section has the sole purpose of protecting the
integrity of the free software distribution system, which is
implemented by public license practices. Many people have made
generous contributions to the wide range of software distributed
through that system in reliance on consistent application of that
system; it is up to the author/donor to decide if he or she is willing
to distribute software through any other system and a licensee cannot
impose that choice.
This section is intended to make thoroughly clear what is believed to
be a consequence of the rest of this License.
8. If the distribution and/or use of the Program is restricted in
certain countries either by patents or by copyrighted interfaces, the
original copyright holder who places the Program under this License
may add an explicit geographical distribution limitation excluding
those countries, so that distribution is permitted only in or among
countries not thus excluded. In such case, this License incorporates
the limitation as if written in the body of this License.
9. The Free Software Foundation may publish revised and/or new versions
of the General Public License from time to time. Such new versions will
be similar in spirit to the present version, but may differ in detail to
address new problems or concerns.
Each version is given a distinguishing version number. If the Program
specifies a version number of this License which applies to it and "any
later version", you have the option of following the terms and conditions
either of that version or of any later version published by the Free
Software Foundation. If the Program does not specify a version number of
this License, you may choose any version ever published by the Free Software
Foundation.
10. If you wish to incorporate parts of the Program into other free
programs whose distribution conditions are different, write to the author
to ask for permission. For software which is copyrighted by the Free
Software Foundation, write to the Free Software Foundation; we sometimes
make exceptions for this. Our decision will be guided by the two goals
of preserving the free status of all derivatives of our free software and
of promoting the sharing and reuse of software generally.
NO WARRANTY
11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
REPAIR OR CORRECTION.
12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
POSSIBILITY OF SUCH DAMAGES.
END OF TERMS AND CONDITIONS
How to Apply These Terms to Your New Programs
If you develop a new program, and you want it to be of the greatest
possible use to the public, the best way to achieve this is to make it
free software which everyone can redistribute and change under these terms.
To do so, attach the following notices to the program. It is safest
to attach them to the start of each source file to most effectively
convey the exclusion of warranty; and each file should have at least
the "copyright" line and a pointer to where the full notice is found.
<one line to give the program's name and a brief idea of what it does.>
Copyright (C) <year> <name of author>
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc.,
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
Also add information on how to contact you by electronic and paper mail.
If the program is interactive, make it output a short notice like this
when it starts in an interactive mode:
Gnomovision version 69, Copyright (C) year name of author
Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
This is free software, and you are welcome to redistribute it
under certain conditions; type `show c' for details.
The hypothetical commands `show w' and `show c' should show the appropriate
parts of the General Public License. Of course, the commands you use may
be called something other than `show w' and `show c'; they could even be
mouse-clicks or menu items--whatever suits your program.
You should also get your employer (if you work as a programmer) or your
school, if any, to sign a "copyright disclaimer" for the program, if
necessary. Here is a sample; alter the names:
Yoyodyne, Inc., hereby disclaims all copyright interest in the program
`Gnomovision' (which makes passes at compilers) written by James Hacker.
<signature of Ty Coon>, 1 April 1989
Ty Coon, President of Vice
This General Public License does not permit incorporating your program into
proprietary programs. If your program is a subroutine library, you may
consider it more useful to permit linking proprietary applications with the
library. If this is what you want to do, use the GNU Lesser General
Public License instead of this License.

6
resources/BrahmaAppInfo Normal file
View File

@ -0,0 +1,6 @@
APP_TITLE = GodMode9
APP_DESCRIPTION = Open source 3DS all access file browser
APP_AUTHOR = d0k3
PAYLOAD_MEM = 1
VOODOO = 0xF

BIN
resources/BrahmaIcon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.0 KiB

View File

@ -0,0 +1,11 @@
-W3
# disable alpha and set opaque bit for all pixels
-gT!
# use lz77 compression
-gzl
# 16 bit bitmap
-gB16
-gb

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

View File

@ -0,0 +1,106 @@
#ifdef EXEC_BOOTSTRAP
.section ".init"
.global _start
.extern main
.align 4
.arm
#define SIZE_32KB 0b01110
#define SIZE_128KB 0b10000
#define SIZE_512KB 0b10010
#define SIZE_2MB 0b10100
#define SIZE_128MB 0b11010
#define SIZE_256MB 0b11011
#define SIZE_4GB 0b11111
@ Makes a MPU partition value
#define MAKE_PARTITION(offset, size_enum) \
(((offset) >> 12 << 12) | ((size_enum) << 1) | 1)
_start:
b _init
@ required, don't move :)
@ will be set to FIRM ARM9 entry point by BRAHMA
arm9ep_backup: .long 0xFFFF0000
_mpu_partition_table:
.word MAKE_PARTITION(0x00000000, SIZE_4GB) @ 0: Background region
.word MAKE_PARTITION(0x00000000, SIZE_128MB) @ 1: Instruction TCM (mirrored every 32KB)
.word MAKE_PARTITION(0x08000000, SIZE_2MB) @ 2: ARM9 internal memory
.word MAKE_PARTITION(0x10000000, SIZE_128MB) @ 3: IO region
.word MAKE_PARTITION(0x18000000, SIZE_128MB) @ 4: external device memory
.word MAKE_PARTITION(0x1FF80000, SIZE_512KB) @ 5: AXI WRAM
.word MAKE_PARTITION(0x20000000, SIZE_256MB) @ 6: FCRAM
.word 0 @ 7: Unused
_populate_mpu:
push {r4-r5, lr}
ldr r4, =_mpu_partition_table
ldr r5, [r4, #0x0] @ mmu_partition_table[0] load
mcr p15, 0, r5, c6, c0, 0 @ mmu_partition_table[0] write
ldr r5, [r4, #0x4]
mcr p15, 0, r5, c6, c1, 0
ldr r5, [r4, #0x8]
mcr p15, 0, r5, c6, c2, 0
ldr r5, [r4, #0xC]
mcr p15, 0, r5, c6, c3, 0
ldr r5, [r4, #0x10]
mcr p15, 0, r5, c6, c4, 0
ldr r5, [r4, #0x14]
mcr p15, 0, r5, c6, c5, 0
ldr r5, [r4, #0x18]
mcr p15, 0, r5, c6, c6, 0
ldr r5, [r4, #0x1C]
mcr p15, 0, r5, c6, c7, 0
@ Give read/write access to all the memory regions
ldr r5, =0x03333333
mcr p15, 0, r5, c5, c0, 2 @ data access
ldr r5, =0x03300330
mcr p15, 0, r5, c5, c0, 3 @ instruction access
mov r5, #0x66
mcr p15, 0, r5, c2, c0, 0 @ data cachable
mcr p15, 0, r5, c2, c0, 1 @ instruction cachable
mov r5, #0x10
mcr p15, 0, r5, c3, c0, 0 @ data bufferable
pop {r4-r5, pc}
_enable_caches:
push {r4-r5, lr}
bl _populate_mpu
mov r5, #0
mcr p15, 0, r5, c7, c5, 0 @ flush I-cache
mcr p15, 0, r5, c7, c6, 0 @ flush D-cache
mrc p15, 0, r4, c1, c0, 0
orr r4, r4, #(1<<12) @ instruction cache enable
orr r4, r4, #(1<<2) @ data cache enable
orr r4, r4, #(1<<0) @ mpu enable
mcr p15, 0, r4, c1, c0, 0
pop {r4-r5, pc}
_init:
push {r0-r12, lr}
bl _enable_caches
bl main
mrc p15, 0, r4, c1, c0, 0
bic r4, r4, #(1<<0) @ mpu disable
mcr p15, 0, r4, c1, c0, 0
pop {r0-r12, lr}
@ return control to FIRM
ldr pc, arm9ep_backup
#endif // EXEC_BOOTSTRAP

View File

@ -0,0 +1,51 @@
#ifdef EXEC_GATEWAY
.section ".init"
.global _start
.extern main
.align 4
.arm
_vectors:
ldr pc, =InfiniteLoop
.pool
ldr pc, =InfiniteLoop
.pool
ldr pc, =InfiniteLoop
.pool
ldr pc, =InfiniteLoop
.pool
ldr pc, =InfiniteLoop
.pool
ldr pc, =InfiniteLoop
.pool
_start:
ldr sp,=0x22140000
@@wait for the arm11 kernel threads to be ready
ldr r1, =0x10000
waitLoop9:
sub r1, #1
cmp r1, #0
bgt waitLoop9
ldr r1, =0x10000
waitLoop92:
sub r1, #1
cmp r1, #0
bgt waitLoop92
ldr sp,=0x22160000
ldr r3, =main
blx r3
.pool
InfiniteLoop:
b InfiniteLoop
#endif // EXEC_GATEWAY

53
source/common.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include <inttypes.h>
#include <stddef.h>
#include <stdbool.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <stdio.h>
#define u8 uint8_t
#define u16 uint16_t
#define u32 uint32_t
#define u64 uint64_t
#define vu8 volatile u8
#define vu16 volatile u16
#define vu32 volatile u32
#define vu64 volatile u64
#define max(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a > _b ? _a : _b; })
#define min(a,b) \
({ __typeof__ (a) _a = (a); \
__typeof__ (b) _b = (b); \
_a < _b ? _a : _b; })
#define getbe16(d) \
(((d)[0]<<8) | (d)[1])
#define getbe32(d) \
((((u32) getbe16(d))<<16) | ((u32) getbe16(d+2)))
#define getbe64(d) \
((((u64) getbe32(d))<<32) | ((u64) getbe32(d+4)))
#define getle16(d) (*((u16*) (d)))
#define getle32(d) (*((u32*) (d)))
#define getle64(d) (*((u64*) (d)))
#define align(v,a) \
(((v) % (a)) ? ((v) + (a) - ((v) % (a))) : (v))
// work files / directories
#define GAME_DIR "/D9Game"
#define WORK_DIR "/Decrypt9"
#define LOG_FILE "Decrypt9.log"
inline u32 strchrcount(const char* str, char symbol) {
u32 count = 0;
for (u32 i = 0; str[i] != '\0'; i++) {
if (str[i] == symbol)
count++;
}
return count;
}

202
source/draw.c Normal file
View File

@ -0,0 +1,202 @@
// Copyright 2013 Normmatt
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#include <stdlib.h>
#include <string.h>
#include <stdarg.h>
#include <stdio.h>
#include "font.h"
#include "draw.h"
#include "fs.h"
#ifdef USE_THEME
#include "theme.h"
#endif
static char debugstr[DBG_N_CHARS_X * DBG_N_CHARS_Y] = { 0 };
void ClearScreen(u8* screen, int width, int color)
{
if (color == COLOR_TRANSPARENT) color = COLOR_BLACK;
for (int i = 0; i < (width * SCREEN_HEIGHT); i++) {
*(screen++) = color >> 16; // B
*(screen++) = color >> 8; // G
*(screen++) = color & 0xFF; // R
}
}
void ClearScreenFull(bool clear_top, bool clear_bottom)
{
if (clear_top) {
ClearScreen(TOP_SCREEN0, SCREEN_WIDTH_TOP, STD_COLOR_BG);
ClearScreen(TOP_SCREEN1, SCREEN_WIDTH_TOP, STD_COLOR_BG);
}
if (clear_bottom) {
ClearScreen(BOT_SCREEN0, SCREEN_WIDTH_BOT, STD_COLOR_BG);
ClearScreen(BOT_SCREEN1, SCREEN_WIDTH_BOT, STD_COLOR_BG);
}
}
void DrawCharacter(u8* screen, int character, int x, int y, int color, int bgcolor)
{
for (int yy = 0; yy < 8; yy++) {
int xDisplacement = (x * BYTES_PER_PIXEL * SCREEN_HEIGHT);
int yDisplacement = ((SCREEN_HEIGHT - (y + yy) - 1) * BYTES_PER_PIXEL);
u8* screenPos = screen + xDisplacement + yDisplacement;
u8 charPos = font[character * 8 + yy];
for (int xx = 7; xx >= 0; xx--) {
if ((charPos >> xx) & 1) {
*(screenPos + 0) = color >> 16; // B
*(screenPos + 1) = color >> 8; // G
*(screenPos + 2) = color & 0xFF; // R
} else if (bgcolor != COLOR_TRANSPARENT) {
*(screenPos + 0) = bgcolor >> 16; // B
*(screenPos + 1) = bgcolor >> 8; // G
*(screenPos + 2) = bgcolor & 0xFF; // R
}
screenPos += BYTES_PER_PIXEL * SCREEN_HEIGHT;
}
}
}
void DrawString(u8* screen, const char *str, int x, int y, int color, int bgcolor)
{
for (int i = 0; i < strlen(str); i++)
DrawCharacter(screen, str[i], x + i * 8, y, color, bgcolor);
}
void DrawStringF(int x, int y, bool use_top, const char *format, ...)
{
char str[512] = {}; // 512 should be more than enough
va_list va;
va_start(va, format);
vsnprintf(str, 512, format, va);
va_end(va);
for (char* text = strtok(str, "\n"); text != NULL; text = strtok(NULL, "\n"), y += 10) {
if (use_top) {
DrawString(TOP_SCREEN0, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
DrawString(TOP_SCREEN1, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
} else {
DrawString(BOT_SCREEN0, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
DrawString(BOT_SCREEN1, text, x, y, STD_COLOR_FONT, STD_COLOR_BG);
}
}
}
void Screenshot(const char* path)
{
u8* buffer = (u8*) 0x21000000; // careful, this area is used by other functions in Decrypt9
u8* buffer_t = buffer + (400 * 240 * 3);
u8 bmp_header[54] = {
0x42, 0x4D, 0x36, 0xCA, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x36, 0x00, 0x00, 0x00, 0x28, 0x00,
0x00, 0x00, 0x90, 0x01, 0x00, 0x00, 0xE0, 0x01, 0x00, 0x00, 0x01, 0x00, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0xCA, 0x08, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x12, 0x0B, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
static u32 n = 0;
if (path == NULL) {
for (; n < 1000; n++) {
char filename[16];
snprintf(filename, 16, "snap%03i.bmp", (int) n);
if (!FileOpen(filename)) {
FileCreate(filename, true);
break;
}
FileClose();
}
if (n >= 1000)
return;
} else {
FileCreate(path, true);
}
memset(buffer, 0x1F, 400 * 240 * 3 * 2);
for (u32 x = 0; x < 400; x++)
for (u32 y = 0; y < 240; y++)
memcpy(buffer_t + (y*400 + x) * 3, TOP_SCREEN0 + (x*240 + y) * 3, 3);
for (u32 x = 0; x < 320; x++)
for (u32 y = 0; y < 240; y++)
memcpy(buffer + (y*400 + x + 40) * 3, BOT_SCREEN0 + (x*240 + y) * 3, 3);
FileWrite(bmp_header, 54, 0);
FileWrite(buffer, 400 * 240 * 3 * 2, 54);
FileClose();
}
void DebugClear()
{
memset(debugstr, 0x00, DBG_N_CHARS_X * DBG_N_CHARS_Y);
ClearScreen(TOP_SCREEN0, SCREEN_WIDTH_TOP, DBG_COLOR_BG);
ClearScreen(TOP_SCREEN1, SCREEN_WIDTH_TOP, DBG_COLOR_BG);
#if defined USE_THEME && defined GFX_DEBUG_BG
LoadThemeGfx(GFX_DEBUG_BG, true);
#endif
LogWrite("");
LogWrite(NULL);
}
void DebugSet(const char **strs)
{
if (strs != NULL) for (int y = 0; y < DBG_N_CHARS_Y; y++) {
int pos_dbgstr = DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1 - y);
snprintf(debugstr + pos_dbgstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, strs[y]);
}
int pos_y = DBG_START_Y;
for (char* str = debugstr + (DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1)); str >= debugstr; str -= DBG_N_CHARS_X) {
if (str[0] != '\0') {
DrawString(TOP_SCREEN0, str, DBG_START_X, pos_y, DBG_COLOR_FONT, DBG_COLOR_BG);
DrawString(TOP_SCREEN1, str, DBG_START_X, pos_y, DBG_COLOR_FONT, DBG_COLOR_BG);
pos_y += DBG_STEP_Y;
}
}
}
void Debug(const char *format, ...)
{
static bool adv_output = true;
char tempstr[128] = { 0 }; // 128 instead of DBG_N_CHARS_X for log file
va_list va;
va_start(va, format);
vsnprintf(tempstr, 128, format, va);
va_end(va);
if (adv_output) {
memmove(debugstr + DBG_N_CHARS_X, debugstr, DBG_N_CHARS_X * (DBG_N_CHARS_Y - 1));
} else {
adv_output = true;
}
if (*tempstr != '\r') { // not a good way of doing this - improve this later
snprintf(debugstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, tempstr);
LogWrite(tempstr);
} else {
snprintf(debugstr, DBG_N_CHARS_X, "%-*.*s", DBG_N_CHARS_X - 1, DBG_N_CHARS_X - 1, tempstr + 1);
adv_output = false;
}
DebugSet(NULL);
}
#if !defined(USE_THEME) || !defined(ALT_PROGRESS)
void ShowProgress(u64 current, u64 total)
{
const u32 progX = SCREEN_WIDTH_TOP - 40;
const u32 progY = SCREEN_HEIGHT - 20;
if (total > 0) {
char progStr[8];
snprintf(progStr, 8, "%3llu%%", (current * 100) / total);
DrawString(TOP_SCREEN0, progStr, progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
DrawString(TOP_SCREEN1, progStr, progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
} else {
DrawString(TOP_SCREEN0, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
DrawString(TOP_SCREEN1, " ", progX, progY, DBG_COLOR_FONT, DBG_COLOR_BG);
}
}
#endif

63
source/draw.h Normal file
View File

@ -0,0 +1,63 @@
// Copyright 2013 Normmatt
// Licensed under GPLv2 or any later version
// Refer to the license.txt file included.
#pragma once
#include "common.h"
#define BYTES_PER_PIXEL 3
#define SCREEN_HEIGHT 240
#define SCREEN_WIDTH_TOP 400
#define SCREEN_WIDTH_BOT 320
#define RGB(r,g,b) (r<<24|b<<16|g<<8|r)
#define COLOR_BLACK RGB(0x00, 0x00, 0x00)
#define COLOR_WHITE RGB(0xFF, 0xFF, 0xFF)
#define COLOR_TRANSPARENT RGB(0xFF, 0x00, 0xEF) // otherwise known as 'super fuchsia'
#ifndef USE_THEME
#define STD_COLOR_BG COLOR_BLACK
#define STD_COLOR_FONT COLOR_WHITE
#define DBG_COLOR_BG COLOR_BLACK
#define DBG_COLOR_FONT COLOR_WHITE
#define DBG_START_Y 10
#define DBG_END_Y (SCREEN_HEIGHT - 10)
#define DBG_START_X 10
#define DBG_END_X (SCREEN_WIDTH_TOP - 10)
#define DBG_STEP_Y 10
#endif
#define DBG_N_CHARS_Y ((DBG_END_Y - DBG_START_Y) / DBG_STEP_Y)
#define DBG_N_CHARS_X (((DBG_END_X - DBG_START_X) / 8) + 1)
#ifdef EXEC_GATEWAY
#define TOP_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFC0 + 4 * (*(u32*)0x080FFFD8 & 1)))
#define BOT_SCREEN0 (u8*)(*(u32*)((uint32_t)0x080FFFD0 + 4 * (*(u32*)0x080FFFDC & 1)))
#define TOP_SCREEN1 TOP_SCREEN0
#define BOT_SCREEN1 BOT_SCREEN0
#elif defined(EXEC_BOOTSTRAP)
#define TOP_SCREEN0 (u8*)(0x20000000)
#define TOP_SCREEN1 (u8*)(0x20046500)
#define BOT_SCREEN0 (u8*)(0x2008CA00)
#define BOT_SCREEN1 (u8*)(0x200C4E00)
#else
#error "Unknown execution method"
#endif
void ClearScreen(unsigned char *screen, int width, int color);
void ClearScreenFull(bool clear_top, bool clear_bottom);
void DrawCharacter(unsigned char *screen, int character, int x, int y, int color, int bgcolor);
void DrawString(unsigned char *screen, const char *str, int x, int y, int color, int bgcolor);
void DrawStringF(int x, int y, bool use_top, const char *format, ...);
void Screenshot(const char* path);
void DebugClear();
void DebugSet(const char **strs);
void Debug(const char *format, ...);
void ShowProgress(u64 current, u64 total);

21
source/fatfs/00readme.txt Normal file
View File

@ -0,0 +1,21 @@
FatFs Module Source Files R0.11
FILES
00readme.txt This file.
history.txt Revision history.
ffconf.h Configuration file for FatFs module.
ff.h Common include file for FatFs and application module.
ff.c FatFs module.
diskio.h Common include file for FatFs and disk I/O module.
diskio.c An example of glue function to attach existing disk I/O module to FatFs.
integer.h Integer type definitions for FatFs.
option Optional external functions.
Low level disk I/O module is not included in this archive because the FatFs
module is only a generic file system layer and not depend on any specific
storage device. You have to provide a low level disk I/O module that written
to control the target storage device.

164
source/fatfs/crypto/aes.c Normal file
View File

@ -0,0 +1,164 @@
/* original version by megazig */
#include "aes.h"
void setup_aeskeyX(u8 keyslot, void* keyx)
{
u32 * _keyx = (u32*)keyx;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80;
*REG_AESKEYXFIFO = _keyx[0];
*REG_AESKEYXFIFO = _keyx[1];
*REG_AESKEYXFIFO = _keyx[2];
*REG_AESKEYXFIFO = _keyx[3];
}
void setup_aeskeyY(u8 keyslot, void* keyy)
{
u32 * _keyy = (u32*)keyy;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80;
*REG_AESKEYYFIFO = _keyy[0];
*REG_AESKEYYFIFO = _keyy[1];
*REG_AESKEYYFIFO = _keyy[2];
*REG_AESKEYYFIFO = _keyy[3];
}
void setup_aeskey(u8 keyslot, void* key)
{
u32 * _key = (u32*)key;
*REG_AESKEYCNT = (*REG_AESKEYCNT >> 6 << 6) | keyslot | 0x80;
*REG_AESKEYFIFO = _key[0];
*REG_AESKEYFIFO = _key[1];
*REG_AESKEYFIFO = _key[2];
*REG_AESKEYFIFO = _key[3];
}
void use_aeskey(u32 keyno)
{
if (keyno > 0x3F)
return;
*REG_AESKEYSEL = keyno;
*REG_AESCNT = *REG_AESCNT | 0x04000000; /* mystery bit */
}
void set_ctr(void* iv)
{
u32 * _iv = (u32*)iv;
*REG_AESCNT = (*REG_AESCNT) | AES_CNT_INPUT_ENDIAN | AES_CNT_INPUT_ORDER;
*(REG_AESCTR + 0) = _iv[3];
*(REG_AESCTR + 1) = _iv[2];
*(REG_AESCTR + 2) = _iv[1];
*(REG_AESCTR + 3) = _iv[0];
}
void add_ctr(void* ctr, u32 carry)
{
u32 counter[4];
u8 *outctr = (u8 *) ctr;
u32 sum;
int32_t i;
for(i=0; i<4; i++) {
counter[i] = (outctr[i*4+0]<<24) | (outctr[i*4+1]<<16) | (outctr[i*4+2]<<8) | (outctr[i*4+3]<<0);
}
for(i=3; i>=0; i--)
{
sum = counter[i] + carry;
if (sum < counter[i]) {
carry = 1;
}
else {
carry = 0;
}
counter[i] = sum;
}
for(i=0; i<4; i++)
{
outctr[i*4+0] = counter[i]>>24;
outctr[i*4+1] = counter[i]>>16;
outctr[i*4+2] = counter[i]>>8;
outctr[i*4+3] = counter[i]>>0;
}
}
void aes_decrypt(void* inbuf, void* outbuf, size_t size, u32 mode)
{
u32 in = (u32)inbuf;
u32 out = (u32)outbuf;
size_t block_count = size;
size_t blocks;
while (block_count != 0)
{
blocks = (block_count >= 0xFFFF) ? 0xFFFF : block_count;
*REG_AESCNT = 0;
*REG_AESBLKCNT = blocks << 16;
*REG_AESCNT = mode |
AES_CNT_START |
AES_CNT_FLUSH_READ |
AES_CNT_FLUSH_WRITE;
aes_fifos((void*)in, (void*)out, blocks);
in += blocks * AES_BLOCK_SIZE;
out += blocks * AES_BLOCK_SIZE;
block_count -= blocks;
}
}
void aes_fifos(void* inbuf, void* outbuf, size_t blocks)
{
u32 in = (u32)inbuf;
if (!in) return;
u32 out = (u32)outbuf;
size_t curblock = 0;
while (curblock != blocks)
{
while (aescnt_checkwrite());
int ii = 0;
for (ii = in; ii != in + AES_BLOCK_SIZE; ii += 4)
{
set_aeswrfifo( *(u32*)(ii) );
}
if (out)
{
while (aescnt_checkread()) ;
for (ii = out; ii != out + AES_BLOCK_SIZE; ii += 4)
{
*(u32*)ii = read_aesrdfifo();
}
}
curblock++;
}
}
void set_aeswrfifo(u32 value)
{
*REG_AESWRFIFO = value;
}
u32 read_aesrdfifo(void)
{
return *REG_AESRDFIFO;
}
u32 aes_getwritecount()
{
return *REG_AESCNT & 0x1F;
}
u32 aes_getreadcount()
{
return (*REG_AESCNT >> 5) & 0x1F;
}
u32 aescnt_checkwrite()
{
size_t ret = aes_getwritecount();
return (ret > 0xF);
}
u32 aescnt_checkread()
{
size_t ret = aes_getreadcount();
return (ret <= 3);
}

53
source/fatfs/crypto/aes.h Normal file
View File

@ -0,0 +1,53 @@
#pragma once
#include "common.h"
#define AES_BLOCK_SIZE 0x10
#define AES_CCM_DECRYPT_MODE (0 << 27)
#define AES_CCM_ENCRYPT_MODE (1 << 27)
#define AES_CTR_MODE (2 << 27)
#define AES_CBC_DECRYPT_MODE (4 << 27)
#define AES_CBC_ENCRYPT_MODE (5 << 27)
#define AES_ECB_DECRYPT_MODE (6 << 27)
#define AES_ECB_ENCRYPT_MODE (7 << 27)
#define REG_AESCNT ((volatile u32*)0x10009000)
#define REG_AESBLKCNT ((volatile u32*)0x10009004)
#define REG_AESWRFIFO ((volatile u32*)0x10009008)
#define REG_AESRDFIFO ((volatile u32*)0x1000900C)
#define REG_AESKEYSEL ((volatile u8 *)0x10009010)
#define REG_AESKEYCNT ((volatile u8 *)0x10009011)
#define REG_AESCTR ((volatile u32*)0x10009020)
#define REG_AESKEYFIFO ((volatile u32*)0x10009100)
#define REG_AESKEYXFIFO ((volatile u32*)0x10009104)
#define REG_AESKEYYFIFO ((volatile u32*)0x10009108)
#define AES_CNT_START 0x80000000
#define AES_CNT_INPUT_ORDER 0x02000000
#define AES_CNT_OUTPUT_ORDER 0x01000000
#define AES_CNT_INPUT_ENDIAN 0x00800000
#define AES_CNT_OUTPUT_ENDIAN 0x00400000
#define AES_CNT_FLUSH_READ 0x00000800
#define AES_CNT_FLUSH_WRITE 0x00000400
#define AES_CNT_CTRNAND_MODE (AES_CTR_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN)
#define AES_CNT_TWLNAND_MODE AES_CTR_MODE
#define AES_CNT_TITLEKEY_DECRYPT_MODE (AES_CBC_DECRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN)
#define AES_CNT_TITLEKEY_ENCRYPT_MODE (AES_CBC_ENCRYPT_MODE | AES_CNT_INPUT_ORDER | AES_CNT_OUTPUT_ORDER | AES_CNT_INPUT_ENDIAN | AES_CNT_OUTPUT_ENDIAN)
void setup_aeskeyX(u8 keyslot, void* keyx);
void setup_aeskeyY(u8 keyslot, void* keyy);
void setup_aeskey(u8 keyslot, void* keyy);
void use_aeskey(u32 keyno);
void set_ctr(void* iv);
void add_ctr(void* ctr, u32 carry);
void aes_decrypt(void* inbuf, void* outbuf, size_t size, u32 mode);
void aes_fifos(void* inbuf, void* outbuf, size_t blocks);
void set_aeswrfifo(u32 value);
u32 read_aesrdfifo(void);
u32 aes_getwritecount();
u32 aes_getreadcount();
u32 aescnt_checkwrite();
u32 aescnt_checkread();

View File

@ -0,0 +1,68 @@
#include "fs.h"
#include "draw.h"
#include "decryptor/decryptor.h"
#include "decryptor/aes.h"
u32 CryptBuffer(CryptBufferInfo *info)
{
u8 ctr[16] __attribute__((aligned(32)));
memcpy(ctr, info->ctr, 16);
u8* buffer = info->buffer;
u32 size = info->size;
u32 mode = info->mode;
if (info->setKeyY) {
u8 keyY[16] __attribute__((aligned(32)));
memcpy(keyY, info->keyY, 16);
setup_aeskeyY(info->keyslot, keyY);
info->setKeyY = 0;
}
use_aeskey(info->keyslot);
for (u32 i = 0; i < size; i += 0x10, buffer += 0x10) {
set_ctr(ctr);
if ((mode & (0x7 << 27)) == AES_CBC_DECRYPT_MODE)
memcpy(ctr, buffer, 0x10);
aes_decrypt((void*) buffer, (void*) buffer, 1, mode);
if ((mode & (0x7 << 27)) == AES_CBC_ENCRYPT_MODE)
memcpy(ctr, buffer, 0x10);
else if ((mode & (0x7 << 27)) == AES_CTR_MODE)
add_ctr(ctr, 0x1);
}
memcpy(info->ctr, ctr, 16);
return 0;
}
u32 CreatePad(PadInfo *info)
{
u8* buffer = BUFFER_ADDRESS;
u32 result = 0;
if (!FileCreate(info->filename, true)) // No DebugFileCreate() here - messages are already given
return 1;
CryptBufferInfo decryptInfo = {.keyslot = info->keyslot, .setKeyY = info->setKeyY, .mode = info->mode, .buffer = buffer};
memcpy(decryptInfo.ctr, info->ctr, 16);
memcpy(decryptInfo.keyY, info->keyY, 16);
u32 size_bytes = info->size_mb * 1024*1024;
for (u32 i = 0; i < size_bytes; i += BUFFER_MAX_SIZE) {
u32 curr_block_size = min(BUFFER_MAX_SIZE, size_bytes - i);
decryptInfo.size = curr_block_size;
memset(buffer, 0x00, curr_block_size);
ShowProgress(i, size_bytes);
CryptBuffer(&decryptInfo);
if (!DebugFileWrite((void*)buffer, curr_block_size, i)) {
result = 1;
break;
}
}
ShowProgress(0, 0);
FileClose();
return result;
}

View File

@ -0,0 +1,30 @@
#pragma once
#include "common.h"
#define BUFFER_ADDRESS ((u8*) 0x21000000)
#define BUFFER_MAX_SIZE (1 * 1024 * 1024) // must be a multiple of 0x40 (64)
typedef struct {
u32 keyslot;
u32 setKeyY;
u8 ctr[16];
u8 keyY[16];
u32 size;
u32 mode;
u8* buffer;
} __attribute__((packed)) CryptBufferInfo;
typedef struct {
u32 keyslot;
u32 setKeyY;
u8 ctr[16];
u8 keyY[16];
u32 size_mb;
u32 mode;
char filename[180];
} __attribute__((packed, aligned(16))) PadInfo;
u32 CryptBuffer(CryptBufferInfo *info);
u32 CreatePad(PadInfo *info);

1313
source/fatfs/crypto/game.c Normal file

File diff suppressed because it is too large Load Diff

107
source/fatfs/crypto/game.h Normal file
View File

@ -0,0 +1,107 @@
#pragma once
#include "common.h"
#include "decryptor/decryptor.h"
#define GC_NCCH_PROCESS (1<<0)
#define GC_CIA_PROCESS (1<<1)
#define GC_CIA_DEEP (1<<2)
#define GC_NCCH_ENCRYPT (1<<3)
#define GC_CIA_ENCRYPT (1<<4)
#define GC_CXI_ONLY (1<<5)
#define MAX_ENTRIES 1024
typedef struct {
u64 titleId;
u8 external_seed[16];
u8 reserved[8];
} __attribute__((packed)) SeedInfoEntry;
typedef struct {
u32 n_entries;
u8 padding[12];
SeedInfoEntry entries[MAX_ENTRIES];
} __attribute__((packed)) SeedInfo;
typedef struct {
u8 ctr[16];
u32 size_mb;
char filename[180];
} __attribute__((packed)) SdInfoEntry;
typedef struct {
u32 n_entries;
SdInfoEntry entries[MAX_ENTRIES];
} __attribute__((packed, aligned(16))) SdInfo;
typedef struct {
u8 ctr[16];
u8 keyY[16];
u32 size_mb;
u8 reserved[4];
u32 usesSeedCrypto;
u32 uses7xCrypto;
u64 titleId;
char filename[112];
} __attribute__((packed)) NcchInfoEntry;
typedef struct {
u32 padding;
u32 ncch_info_version;
u32 n_entries;
u8 reserved[4];
NcchInfoEntry entries[MAX_ENTRIES];
} __attribute__((packed, aligned(16))) NcchInfo;
typedef struct {
u8 signature[0x100];
u8 magic[0x4];
u32 size;
u64 partitionId;
u16 makercode;
u16 version;
u8 reserved0[0x4];
u64 programId;
u8 reserved1[0x10];
u8 hash_logo[0x20];
char productCode[0x10];
u8 hash_exthdr[0x20];
u32 size_exthdr;
u8 reserved2[0x4];
u8 flags[0x8];
u32 offset_plain;
u32 size_plain;
u32 offset_logo;
u32 size_logo;
u32 offset_exefs;
u32 size_exefs;
u32 size_exefs_hash;
u8 reserved3[0x4];
u32 offset_romfs;
u32 size_romfs;
u32 size_romfs_hash;
u8 reserved4[0x4];
u8 hash_exefs[0x20];
u8 hash_romfs[0x20];
} __attribute__((packed, aligned(16))) NcchHeader;
u32 GetSdCtr(u8* ctr, const char* path);
u32 GetSd0x34KeyY(u8* movable_keyY, bool from_nand);
u32 SdFolderSelector(char* path, u8* keyY);
u32 SdInfoGen(SdInfo* info, const char* base_path);
u32 CryptSdToSd(const char* filename, u32 offset, u32 size, CryptBufferInfo* info);
u32 GetHashFromFile(const char* filename, u32 offset, u32 size, u8* hash);
u32 CheckHashFromFile(const char* filename, u32 offset, u32 size, u8* hash);
u32 CryptNcch(const char* filename, u32 offset, u32 size, u64 seedId, u8* encrypt_flags);
u32 CryptCia(const char* filename, u8* ncch_crypt, bool cia_encrypt, bool cxi_only);
// --> FEATURE FUNCTIONS <--
u32 NcchPadgen(u32 param);
u32 SdPadgen(u32 param);
u32 SdPadgenDirect(u32 param);
u32 UpdateSeedDb(u32 param);
u32 CryptGameFiles(u32 param);
u32 CryptSdFiles(u32 param);
u32 DecryptSdFilesDirect(u32 param);

682
source/fatfs/crypto/nand.c Normal file
View File

@ -0,0 +1,682 @@
#include "fs.h"
#include "draw.h"
#include "hid.h"
#include "platform.h"
#include "decryptor/aes.h"
#include "decryptor/decryptor.h"
#include "decryptor/nand.h"
#include "fatfs/sdmmc.h"
// see: http://3dbrew.org/wiki/Flash_Filesystem
static PartitionInfo partitions[] = {
{ "TWLN", {0xE9, 0x00, 0x00, 0x54, 0x57, 0x4C, 0x20, 0x20}, 0x00012E00, 0x08FB5200, 0x3, AES_CNT_TWLNAND_MODE },
{ "TWLP", {0xE9, 0x00, 0x00, 0x54, 0x57, 0x4C, 0x20, 0x20}, 0x09011A00, 0x020B6600, 0x3, AES_CNT_TWLNAND_MODE },
{ "AGBSAVE", {0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF}, 0x0B100000, 0x00030000, 0x7, AES_CNT_CTRNAND_MODE },
{ "FIRM0", {0x46, 0x49, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00}, 0x0B130000, 0x00400000, 0x6, AES_CNT_CTRNAND_MODE },
{ "FIRM1", {0x46, 0x49, 0x52, 0x4D, 0x00, 0x00, 0x00, 0x00}, 0x0B530000, 0x00400000, 0x6, AES_CNT_CTRNAND_MODE },
{ "CTRNAND", {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}, 0x0B95CA00, 0x2F3E3600, 0x4, AES_CNT_CTRNAND_MODE }, // O3DS
{ "CTRNAND", {0xE9, 0x00, 0x00, 0x43, 0x54, 0x52, 0x20, 0x20}, 0x0B95AE00, 0x41D2D200, 0x5, AES_CNT_CTRNAND_MODE } // N3DS
};
static u32 emunand_header = 0;
static u32 emunand_offset = 0;
u32 CheckEmuNand(void)
{
u8* buffer = BUFFER_ADDRESS;
u32 nand_size_sectors = getMMCDevice(0)->total_size;
u32 multi_sectors = (GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS;
u32 ret = EMUNAND_NOT_READY;
// check the MBR for presence of a hidden partition
sdmmc_sdcard_readsectors(0, 1, buffer);
u32 hidden_sectors = getle32(buffer + 0x1BE + 0x8);
for (u32 offset_sector = 0; offset_sector + nand_size_sectors < hidden_sectors; offset_sector += multi_sectors) {
// check for Gateway type EmuNAND
sdmmc_sdcard_readsectors(offset_sector + nand_size_sectors, 1, buffer);
if (memcmp(buffer + 0x100, "NCSD", 4) == 0) {
ret |= EMUNAND_GATEWAY << (2 * (offset_sector / multi_sectors));
continue;
}
// check for RedNAND type EmuNAND
sdmmc_sdcard_readsectors(offset_sector + 1, 1, buffer);
if (memcmp(buffer + 0x100, "NCSD", 4) == 0) {
ret |= EMUNAND_REDNAND << (2 * (offset_sector / multi_sectors));
continue;
}
// EmuNAND ready but not set up
ret |= EMUNAND_READY << (2 * (offset_sector / multi_sectors));
}
return ret;
}
u32 SetNand(bool set_emunand, bool force_emunand)
{
if (set_emunand) {
u32 emunand_state = CheckEmuNand();
u32 emunand_count = 0;
u32 offset_sector = 0;
for (emunand_count = 0; (emunand_state >> (2 * emunand_count)) & 0x3; emunand_count++);
if (emunand_count > 1) { // multiple EmuNANDs -> use selector
u32 multi_sectors = (GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS;
u32 emunand_no = 0;
Debug("Use arrow keys and <A> to choose EmuNAND");
while (true) {
u32 emunandn_state = (emunand_state >> (2 * emunand_no)) & 0x3;
offset_sector = emunand_no * multi_sectors;
Debug("\rEmuNAND #%u: %s", emunand_no, (emunandn_state == EMUNAND_READY) ? "EmuNAND ready" : (emunandn_state == EMUNAND_GATEWAY) ? "GW EmuNAND" : "RedNAND");
// user input routine
u32 pad_state = InputWait();
if (pad_state & BUTTON_DOWN) {
emunand_no = (emunand_no + 1) % emunand_count;
} else if (pad_state & BUTTON_UP) {
emunand_no = (emunand_no) ? emunand_no - 1 : emunand_count - 1;
} else if (pad_state & BUTTON_A) {
Debug("EmuNAND #%u", emunand_no);
emunand_state = emunandn_state;
break;
} else if (pad_state & BUTTON_B) {
Debug("(cancelled by user)");
return 2;
}
}
}
if ((emunand_state == EMUNAND_READY) && force_emunand)
emunand_state = EMUNAND_GATEWAY;
switch (emunand_state) {
case EMUNAND_NOT_READY:
Debug("SD is not formatted for EmuNAND");
return 1;
case EMUNAND_GATEWAY:
emunand_header = offset_sector + getMMCDevice(0)->total_size;
emunand_offset = offset_sector;
Debug("Using EmuNAND @ %06X/%06X", emunand_header, emunand_offset);
return 0;
case EMUNAND_REDNAND:
emunand_header = offset_sector + 1;
emunand_offset = offset_sector + 1;
Debug("Using RedNAND @ %06X/%06X", emunand_header, emunand_offset);
return 0;
default:
Debug("EmuNAND is not available");
return 1;
}
} else {
emunand_header = 0;
emunand_offset = 0;
return 0;
}
}
static inline int ReadNandSectors(u32 sector_no, u32 numsectors, u8 *out)
{
if (emunand_header) {
if (sector_no == 0) {
int errorcode = sdmmc_sdcard_readsectors(emunand_header, 1, out);
if (errorcode) return errorcode;
sector_no = 1;
numsectors--;
out += 0x200;
}
return sdmmc_sdcard_readsectors(sector_no + emunand_offset, numsectors, out);
} else return sdmmc_nand_readsectors(sector_no, numsectors, out);
}
static inline int WriteNandSectors(u32 sector_no, u32 numsectors, u8 *in)
{
if (emunand_header) {
if (sector_no == 0) {
int errorcode = sdmmc_sdcard_writesectors(emunand_header, 1, in);
if (errorcode) return errorcode;
sector_no = 1;
numsectors--;
in += 0x200;
}
return sdmmc_sdcard_writesectors(sector_no + emunand_offset, numsectors, in);
} else return sdmmc_nand_writesectors(sector_no, numsectors, in);
}
u32 OutputFileNameSelector(char* filename, const char* basename, char* extension) {
char bases[3][64] = { 0 };
char* dotpos = NULL;
// build first base name and extension
strncpy(bases[0], basename, 63);
dotpos = strrchr(bases[0], '.');
if (dotpos) {
*dotpos = '\0';
if (!extension)
extension = dotpos + 1;
}
// build other two base names
snprintf(bases[1], 63, "%s_%s", bases[0], (emunand_header) ? "emu" : "sys");
snprintf(bases[2], 63, "%s%s" , (emunand_header) ? "emu" : "sys", bases[0]);
u32 fn_id = (emunand_header) ? 1 : 0;
u32 fn_num = (emunand_header) ? (emunand_offset / ((GetUnitPlatform() == PLATFORM_3DS) ? EMUNAND_MULTI_OFFSET_O3DS : EMUNAND_MULTI_OFFSET_N3DS)) : 0;
bool exists = false;
char extstr[16] = { 0 };
if (extension)
snprintf(extstr, 15, ".%s", extension);
Debug("Use arrow keys and <A> to choose a name");
while (true) {
char numstr[2] = { 0 };
// build and output file name (plus "(!)" if existing)
numstr[0] = (fn_num > 0) ? '0' + fn_num : '\0';
snprintf(filename, 63, "%s%s%s", bases[fn_id], numstr, extstr);
if ((exists = FileOpen(filename)))
FileClose();
Debug("\r%s%s", filename, (exists) ? " (!)" : "");
// user input routine
u32 pad_state = InputWait();
if (pad_state & BUTTON_DOWN) { // increment filename id
fn_id = (fn_id + 1) % 3;
} else if (pad_state & BUTTON_UP) { // decrement filename id
fn_id = (fn_id > 0) ? fn_id - 1 : 2;
} else if ((pad_state & BUTTON_RIGHT) && (fn_num < 9)) { // increment number
fn_num++;
} else if ((pad_state & BUTTON_LEFT) && (fn_num > 0)) { // decrement number
fn_num--;
} else if (pad_state & BUTTON_A) {
Debug("%s%s", filename, (exists) ? " (!)" : "");
break;
} else if (pad_state & BUTTON_B) {
Debug("(cancelled by user)");
return 2;
}
}
// overwrite confirmation
if (exists) {
Debug("Press <A> to overwrite existing file");
while (true) {
u32 pad_state = InputWait();
if (pad_state & BUTTON_A) {
break;
} else if (pad_state & BUTTON_B) {
Debug("(cancelled by user)");
return 2;
}
}
}
return 0;
}
u32 InputFileNameSelector(char* filename, const char* basename, char* extension, u8* magic, u32 msize, u32 fsize) {
char** fnptr = (char**) 0x20400000; // allow using 0x8000 byte
char* fnlist = (char*) 0x20408000; // allow using 0x80000 byte
u32 n_names = 0;
// get the file list - try work directory first
if (!GetFileList(WORK_DIR, fnlist, 0x80000, false, true, false) && !GetFileList("/", fnlist, 0x800000, false, true, false)) {
Debug("Failed retrieving the file names list");
return 1;
}
// get base name, extension
char base[64] = { 0 };
if (basename != NULL) {
// build base name and extension
strncpy(base, basename, 63);
char* dotpos = strrchr(base, '.');
if (dotpos) {
*dotpos = '\0';
if (!extension)
extension = dotpos + 1;
}
}
// limit magic number size
if (msize > 0x200)
msize = 0x200;
// parse the file names list for usable entries
for (char* fn = strtok(fnlist, "\n"); fn != NULL; fn = strtok(NULL, "\n")) {
u8 data[0x200];
char* dotpos = strrchr(fn, '.');
if (strrchr(fn, '/'))
fn = strrchr(fn, '/') + 1;
if (strnlen(fn, 128) > 63)
continue; // file name too long
if ((basename != NULL) && !strstr(fn, base))
continue; // basename check failed
if ((extension != NULL) && (dotpos != NULL) && (strncmp(dotpos + 1, extension, strnlen(extension, 16))))
continue; // extension check failed
else if ((extension == NULL) != (dotpos == NULL))
continue; // extension check failed
if (!FileOpen(fn))
continue; // file can't be opened
if (fsize && (FileGetSize() != fsize)) {
FileClose();
continue; // file size check failed
}
if (msize) {
if (FileRead(data, msize, 0) != msize) {
FileClose();
continue; // can't be read
}
if (memcmp(data, magic, msize) != 0) {
FileClose();
continue; // magic number does not match
}
}
FileClose();
// this is a match - keep it
fnptr[n_names++] = fn;
if (n_names * sizeof(char**) >= 0x8000)
return 1;
}
if (n_names == 0) {
Debug("No usable file found");
return 1;
}
u32 index = 0;
Debug("Use arrow keys and <A> to choose a file");
while (true) {
snprintf(filename, 63, "%s", fnptr[index]);
Debug("\r%s", filename);
u32 pad_state = InputWait();
if (pad_state & BUTTON_DOWN) { // next filename
index = (index + 1) % n_names;
} else if (pad_state & BUTTON_UP) { // previous filename
index = (index > 0) ? index - 1 : n_names - 1;
} else if (pad_state & BUTTON_A) {
Debug("%s", filename);
break;
} else if (pad_state & BUTTON_B) {
Debug("(cancelled by user)");
return 2;
}
}
return 0;
}
PartitionInfo* GetPartitionInfo(u32 partition_id)
{
u32 partition_num = 0;
if (partition_id == P_CTRNAND) {
partition_num = (GetUnitPlatform() == PLATFORM_3DS) ? 5 : 6;
} else {
for(; !(partition_id & (1<<partition_num)) && (partition_num < 32); partition_num++);
}
return (partition_num >= 32) ? NULL : &(partitions[partition_num]);
}
u32 CtrNandPadgen(u32 param)
{
u32 keyslot;
u32 nand_size;
// legacy sizes & offset, to work with 3DSFAT16Tool
if (GetUnitPlatform() == PLATFORM_3DS) {
keyslot = 0x4;
nand_size = 758;
} else {
keyslot = 0x5;
nand_size = 1055;
}
Debug("Creating NAND FAT16 xorpad. Size (MB): %u", nand_size);
Debug("Filename: nand.fat16.xorpad");
PadInfo padInfo = {
.keyslot = keyslot,
.setKeyY = 0,
.size_mb = nand_size,
.filename = "nand.fat16.xorpad",
.mode = AES_CNT_CTRNAND_MODE
};
if(GetNandCtr(padInfo.ctr, 0xB930000) != 0)
return 1;
return CreatePad(&padInfo);
}
u32 TwlNandPadgen(u32 param)
{
u32 size_mb = (partitions[0].size + (1024 * 1024) - 1) / (1024 * 1024);
Debug("Creating TWLN FAT16 xorpad. Size (MB): %u", size_mb);
Debug("Filename: twlnand.fat16.xorpad");
PadInfo padInfo = {
.keyslot = partitions[0].keyslot,
.setKeyY = 0,
.size_mb = size_mb,
.filename = "twlnand.fat16.xorpad",
.mode = AES_CNT_TWLNAND_MODE
};
if(GetNandCtr(padInfo.ctr, partitions[0].offset) != 0)
return 1;
return CreatePad(&padInfo);
}
u32 Firm0Firm1Padgen(u32 param)
{
u32 size_mb = (partitions[3].size + partitions[4].size + (1024 * 1024) - 1) / (1024 * 1024);
Debug("Creating FIRM0FIRM1 xorpad. Size (MB): %u", size_mb);
Debug("Filename: firm0firm1.xorpad");
PadInfo padInfo = {
.keyslot = partitions[3].keyslot,
.setKeyY = 0,
.size_mb = size_mb,
.filename = "firm0firm1.xorpad",
.mode = AES_CNT_CTRNAND_MODE
};
if(GetNandCtr(padInfo.ctr, partitions[3].offset) != 0)
return 1;
return CreatePad(&padInfo);
}
u32 GetNandCtr(u8* ctr, u32 offset)
{
static const char* versions[] = {"4.x", "5.x", "6.x", "7.x", "8.x", "9.x"};
static const u8* version_ctrs[] = {
(u8*)0x080D7CAC,
(u8*)0x080D858C,
(u8*)0x080D748C,
(u8*)0x080D740C,
(u8*)0x080D74CC,
(u8*)0x080D794C
};
static const u32 version_ctrs_len = sizeof(version_ctrs) / sizeof(u32);
static u8* ctr_start = NULL;
if (ctr_start == NULL) {
for (u32 i = 0; i < version_ctrs_len; i++) {
if (*(u32*)version_ctrs[i] == 0x5C980) {
Debug("System version %s", versions[i]);
ctr_start = (u8*) version_ctrs[i] + 0x30;
}
}
// If value not in previous list start memory scanning (test range)
if (ctr_start == NULL) {
for (u8* c = (u8*) 0x080D8FFF; c > (u8*) 0x08000000; c--) {
if (*(u32*)c == 0x5C980 && *(u32*)(c + 1) == 0x800005C9) {
ctr_start = c + 0x30;
Debug("CTR start 0x%08X", ctr_start);
break;
}
}
}
if (ctr_start == NULL) {
Debug("CTR start not found!");
return 1;
}
}
// the ctr is stored backwards in memory
if (offset >= 0x0B100000) { // CTRNAND/AGBSAVE region
for (u32 i = 0; i < 16; i++)
ctr[i] = *(ctr_start + (0xF - i));
} else { // TWL region
for (u32 i = 0; i < 16; i++)
ctr[i] = *(ctr_start + 0x88 + (0xF - i));
}
// increment counter
add_ctr(ctr, offset / 0x10);
return 0;
}
u32 DecryptNandToMem(u8* buffer, u32 offset, u32 size, PartitionInfo* partition)
{
CryptBufferInfo info = {.keyslot = partition->keyslot, .setKeyY = 0, .size = size, .buffer = buffer, .mode = partition->mode};
if(GetNandCtr(info.ctr, offset) != 0)
return 1;
u32 n_sectors = (size + NAND_SECTOR_SIZE - 1) / NAND_SECTOR_SIZE;
u32 start_sector = offset / NAND_SECTOR_SIZE;
ReadNandSectors(start_sector, n_sectors, buffer);
CryptBuffer(&info);
return 0;
}
u32 DecryptNandToFile(const char* filename, u32 offset, u32 size, PartitionInfo* partition)
{
u8* buffer = BUFFER_ADDRESS;
u32 result = 0;
if (!DebugFileCreate(filename, true))
return 1;
for (u32 i = 0; i < size; i += NAND_SECTOR_SIZE * SECTORS_PER_READ) {
u32 read_bytes = min(NAND_SECTOR_SIZE * SECTORS_PER_READ, (size - i));
ShowProgress(i, size);
DecryptNandToMem(buffer, offset + i, read_bytes, partition);
if(!DebugFileWrite(buffer, read_bytes, i)) {
result = 1;
break;
}
}
ShowProgress(0, 0);
FileClose();
return result;
}
u32 DumpNand(u32 param)
{
char filename[64];
u8* buffer = BUFFER_ADDRESS;
u32 nand_size = getMMCDevice(0)->total_size * NAND_SECTOR_SIZE;
u32 result = 0;
Debug("Dumping %sNAND. Size (MB): %u", (param & N_EMUNAND) ? "Emu" : "Sys", nand_size / (1024 * 1024));
if (OutputFileNameSelector(filename, "NAND.bin", NULL) != 0)
return 1;
if (!DebugFileCreate(filename, true))
return 1;
u32 n_sectors = nand_size / NAND_SECTOR_SIZE;
for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
u32 read_sectors = min(SECTORS_PER_READ, (n_sectors - i));
ShowProgress(i, n_sectors);
ReadNandSectors(i, read_sectors, buffer);
if(!DebugFileWrite(buffer, NAND_SECTOR_SIZE * read_sectors, i * NAND_SECTOR_SIZE)) {
result = 1;
break;
}
}
ShowProgress(0, 0);
FileClose();
return result;
}
u32 DecryptNandPartition(u32 param)
{
PartitionInfo* p_info = NULL;
char filename[64];
u8 magic[NAND_SECTOR_SIZE];
for (u32 partition_id = P_TWLN; partition_id <= P_CTRNAND; partition_id = partition_id << 1) {
if (param & partition_id) {
p_info = GetPartitionInfo(partition_id);
break;
}
}
if (p_info == NULL) {
Debug("No partition to dump");
return 1;
}
Debug("Dumping & Decrypting %s, size (MB): %u", p_info->name, p_info->size / (1024 * 1024));
if (DecryptNandToMem(magic, p_info->offset, 16, p_info) != 0)
return 1;
if ((p_info->magic[0] != 0xFF) && (memcmp(p_info->magic, magic, 8) != 0)) {
Debug("Decryption error, please contact us");
return 1;
}
if (OutputFileNameSelector(filename, p_info->name, "bin") != 0)
return 1;
return DecryptNandToFile(filename, p_info->offset, p_info->size, p_info);
}
u32 EncryptMemToNand(u8* buffer, u32 offset, u32 size, PartitionInfo* partition)
{
CryptBufferInfo info = {.keyslot = partition->keyslot, .setKeyY = 0, .size = size, .buffer = buffer, .mode = partition->mode};
if(GetNandCtr(info.ctr, offset) != 0)
return 1;
u32 n_sectors = (size + NAND_SECTOR_SIZE - 1) / NAND_SECTOR_SIZE;
u32 start_sector = offset / NAND_SECTOR_SIZE;
CryptBuffer(&info);
WriteNandSectors(start_sector, n_sectors, buffer);
return 0;
}
u32 EncryptFileToNand(const char* filename, u32 offset, u32 size, PartitionInfo* partition)
{
u8* buffer = BUFFER_ADDRESS;
u32 result = 0;
if (!DebugFileOpen(filename))
return 1;
if (FileGetSize() != size) {
Debug("%s has wrong size", filename);
FileClose();
return 1;
}
for (u32 i = 0; i < size; i += NAND_SECTOR_SIZE * SECTORS_PER_READ) {
u32 read_bytes = min(NAND_SECTOR_SIZE * SECTORS_PER_READ, (size - i));
ShowProgress(i, size);
if(!DebugFileRead(buffer, read_bytes, i)) {
result = 1;
break;
}
EncryptMemToNand(buffer, offset + i, read_bytes, partition);
}
ShowProgress(0, 0);
FileClose();
return result;
}
u32 RestoreNand(u32 param)
{
char filename[64];
u8* buffer = BUFFER_ADDRESS;
u32 nand_size = getMMCDevice(0)->total_size * NAND_SECTOR_SIZE;
u32 result = 0;
u8 magic[4];
if (!(param & N_NANDWRITE)) // developer screwup protection
return 1;
// User file select
if (InputFileNameSelector(filename, "NAND.bin", NULL, NULL, 0, nand_size) != 0)
return 1;
if (!DebugFileOpen(filename))
return 1;
if (nand_size != FileGetSize()) {
FileClose();
Debug("NAND backup has the wrong size!");
return 1;
};
if(!DebugFileRead(magic, 4, 0x100)) {
FileClose();
return 1;
}
if (memcmp(magic, "NCSD", 4) != 0) {
FileClose();
Debug("Not a proper NAND backup!");
return 1;
}
Debug("Restoring %sNAND. Size (MB): %u", (param & N_EMUNAND) ? "Emu" : "Sys", nand_size / (1024 * 1024));
u32 n_sectors = nand_size / NAND_SECTOR_SIZE;
for (u32 i = 0; i < n_sectors; i += SECTORS_PER_READ) {
u32 read_sectors = min(SECTORS_PER_READ, (n_sectors - i));
ShowProgress(i, n_sectors);
if(!DebugFileRead(buffer, NAND_SECTOR_SIZE * read_sectors, i * NAND_SECTOR_SIZE)) {
result = 1;
break;
}
WriteNandSectors(i, read_sectors, buffer);
}
ShowProgress(0, 0);
FileClose();
return result;
}
u32 InjectNandPartition(u32 param)
{
PartitionInfo* p_info = NULL;
char filename[64];
u8 magic[NAND_SECTOR_SIZE];
if (!(param & N_NANDWRITE)) // developer screwup protection
return 1;
for (u32 partition_id = P_TWLN; partition_id <= P_CTRNAND; partition_id = partition_id << 1) {
if (param & partition_id) {
p_info = GetPartitionInfo(partition_id);
break;
}
}
if (p_info == NULL) {
Debug("No partition to inject to");
return 1;
}
Debug("Encrypting & Injecting %s, size (MB): %u", p_info->name, p_info->size / (1024 * 1024));
// User file select
if (InputFileNameSelector(filename, p_info->name, "bin",
p_info->magic, (p_info->magic[0] != 0xFF) ? 8 : 0, p_info->size) != 0)
return 1;
// Encryption check
if (DecryptNandToMem(magic, p_info->offset, 16, p_info) != 0)
return 1;
if ((p_info->magic[0] != 0xFF) && (memcmp(p_info->magic, magic, 8) != 0)) {
Debug("Decryption error, please contact us");
return 1;
}
// File check
if (FileOpen(filename)) {
if(!DebugFileRead(magic, 8, 0)) {
FileClose();
return 1;
}
if ((p_info->magic[0] != 0xFF) && (memcmp(p_info->magic, magic, 8) != 0)) {
Debug("Bad file content, won't inject");
FileClose();
return 1;
}
FileClose();
}
return EncryptFileToNand(filename, p_info->offset, p_info->size, p_info);
}

View File

@ -0,0 +1,62 @@
#pragma once
#include "common.h"
#define NAND_SECTOR_SIZE 0x200
#define SECTORS_PER_READ (BUFFER_MAX_SIZE / NAND_SECTOR_SIZE)
#define P_TWLN (1<<0)
#define P_TWLP (1<<1)
#define P_AGBSAVE (1<<2)
#define P_FIRM0 (1<<3)
#define P_FIRM1 (1<<4)
#define P_CTRNAND (1<<5)
// these three are not handled by the feature functions
// they have to be handled by the menu system
#define N_EMUNAND (1<<29)
#define N_FORCENAND (1<<30)
#define N_NANDWRITE (1<<31)
// return values for the CheckEmuNAND() function
#define EMUNAND_NOT_READY 0 // must be zero
#define EMUNAND_READY 1
#define EMUNAND_GATEWAY 2
#define EMUNAND_REDNAND 3
// these offsets are used by Multi EmuNAND Creator
#define EMUNAND_MULTI_OFFSET_O3DS 0x00200000
#define EMUNAND_MULTI_OFFSET_N3DS 0x00400000
typedef struct {
char name[16];
u8 magic[8];
u32 offset;
u32 size;
u32 keyslot;
u32 mode;
} __attribute__((packed)) PartitionInfo;
PartitionInfo* GetPartitionInfo(u32 partition_id);
u32 GetNandCtr(u8* ctr, u32 offset);
u32 OutputFileNameSelector(char* filename, const char* basename, char* extension);
u32 InputFileNameSelector(char* filename, const char* basename, char* extension, u8* magic, u32 msize, u32 fsize);
u32 DecryptNandToMem(u8* buffer, u32 offset, u32 size, PartitionInfo* partition);
u32 DecryptNandToFile(const char* filename, u32 offset, u32 size, PartitionInfo* partition);
u32 EncryptMemToNand(u8* buffer, u32 offset, u32 size, PartitionInfo* partition);
u32 EncryptFileToNand(const char* filename, u32 offset, u32 size, PartitionInfo* partition);
// --> FEATURE FUNCTIONS <--
u32 CheckEmuNand(void);
u32 SetNand(bool set_emunand, bool force_emunand);
u32 CtrNandPadgen(u32 param);
u32 TwlNandPadgen(u32 param);
u32 Firm0Firm1Padgen(u32 param);
u32 DumpNand(u32 param);
u32 RestoreNand(u32 param);
u32 DecryptNandPartition(u32 param);
u32 InjectNandPartition(u32 param);

32
source/fatfs/crypto/sha.c Normal file
View File

@ -0,0 +1,32 @@
#include "sha.h"
void sha_init(u32 mode)
{
while(*REG_SHACNT & 1);
*REG_SHACNT = mode | SHA_CNT_OUTPUT_ENDIAN | SHA_NORMAL_ROUND;
}
void sha_update(const void* src, u32 size)
{
const u32* src32 = (const u32*)src;
while(size >= 0x40) {
while(*REG_SHACNT & 1);
for(u32 i = 0; i < 4; i++) {
*REG_SHAINFIFO = *src32++;
*REG_SHAINFIFO = *src32++;
*REG_SHAINFIFO = *src32++;
*REG_SHAINFIFO = *src32++;
}
size -= 0x40;
}
while(*REG_SHACNT & 1);
memcpy((void*)REG_SHAINFIFO, src32, size);
}
void sha_get(void* res) {
*REG_SHACNT = (*REG_SHACNT & ~SHA_NORMAL_ROUND) | SHA_FINAL_ROUND;
while(*REG_SHACNT & SHA_FINAL_ROUND);
while(*REG_SHACNT & 1);
memcpy(res, (void*)REG_SHAHASH, (256 / 8));
}

27
source/fatfs/crypto/sha.h Normal file
View File

@ -0,0 +1,27 @@
#pragma once
#include "common.h"
#define REG_SHACNT ((volatile uint32_t*)0x1000A000)
#define REG_SHABLKCNT ((volatile uint32_t*)0x1000A004)
#define REG_SHAHASH ((volatile uint32_t*)0x1000A040)
#define REG_SHAINFIFO ((volatile uint32_t*)0x1000A080)
#define SHA_CNT_STATE 0x00000003
#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 SHA256_MODE 0
#define SHA224_MODE 0x00000010
#define SHA1_MODE 0x00000020
void sha_init(u32 mode);
void sha_update(const void* src, u32 size);
void sha_get(void* res);

15
source/fatfs/delay.s Normal file
View File

@ -0,0 +1,15 @@
.arm
.global waitcycles
.type waitcycles STT_FUNC
@waitcycles ( u32 us )
waitcycles:
PUSH {R0-R2,LR}
STR R0, [SP,#4]
waitcycles_loop:
LDR R3, [SP,#4]
SUBS R2, R3, #1
STR R2, [SP,#4]
CMP R3, #0
BNE waitcycles_loop
POP {R0-R2,PC}

117
source/fatfs/diskio.c Normal file
View File

@ -0,0 +1,117 @@
/*-----------------------------------------------------------------------*/
/* Low level disk I/O module skeleton for FatFs (C)ChaN, 2014 */
/*-----------------------------------------------------------------------*/
/* If a working storage control module is available, it should be */
/* attached to the FatFs via a glue function rather than modifying it. */
/* This is an example of glue functions to attach various exsisting */
/* storage control modules to the FatFs module with a defined API. */
/*-----------------------------------------------------------------------*/
#include "diskio.h" /* FatFs lower layer API */
#include "sdmmc.h"
/*-----------------------------------------------------------------------*/
/* Get Drive Status */
/*-----------------------------------------------------------------------*/
DSTATUS disk_status (
__attribute__((unused))
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Inidialize a Drive */
/*-----------------------------------------------------------------------*/
DSTATUS disk_initialize (
__attribute__((unused))
BYTE pdrv /* Physical drive nmuber to identify the drive */
)
{
sdmmc_sdcard_init();
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Read Sector(s) */
/*-----------------------------------------------------------------------*/
DRESULT disk_read (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */
BYTE *buff, /* Data buffer to store read data */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to read */
)
{
if (sdmmc_sdcard_readsectors(sector, count, buff)) {
return RES_PARERR;
}
return RES_OK;
}
/*-----------------------------------------------------------------------*/
/* Write Sector(s) */
/*-----------------------------------------------------------------------*/
#if _USE_WRITE
DRESULT disk_write (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber to identify the drive */
const BYTE *buff, /* Data to be written */
DWORD sector, /* Sector address in LBA */
UINT count /* Number of sectors to write */
)
{
if (sdmmc_sdcard_writesectors(sector, count, (BYTE *)buff)) {
return RES_PARERR;
}
return RES_OK;
}
#endif
/*-----------------------------------------------------------------------*/
/* Miscellaneous Functions */
/*-----------------------------------------------------------------------*/
#if _USE_IOCTL
DRESULT disk_ioctl (
__attribute__((unused))
BYTE pdrv, /* Physical drive nmuber (0..) */
__attribute__((unused))
BYTE cmd, /* Control code */
__attribute__((unused))
void *buff /* Buffer to send/receive control data */
)
{
switch (cmd) {
case GET_SECTOR_SIZE:
*((DWORD*) buff) = 0x200;
return RES_OK;
case GET_SECTOR_COUNT:
*((DWORD*) buff) = getMMCDevice(1)->total_size;
return RES_OK;
case GET_BLOCK_SIZE:
*((DWORD*) buff) = 0x2000;
return RES_OK;
case CTRL_SYNC:
// nothing to do here - the disk_write function handles that
return RES_OK;
}
return RES_PARERR;
}
#endif

80
source/fatfs/diskio.h Normal file
View File

@ -0,0 +1,80 @@
/*-----------------------------------------------------------------------/
/ Low level disk interface modlue include file (C)ChaN, 2014 /
/-----------------------------------------------------------------------*/
#ifndef _DISKIO_DEFINED
#define _DISKIO_DEFINED
#ifdef __cplusplus
extern "C" {
#endif
#define _USE_WRITE 1 /* 1: Enable disk_write function */
#define _USE_IOCTL 1 /* 1: Enable disk_ioctl fucntion */
#include "integer.h"
/* Status of Disk Functions */
typedef BYTE DSTATUS;
/* Results of Disk Functions */
typedef enum {
RES_OK = 0, /* 0: Successful */
RES_ERROR, /* 1: R/W Error */
RES_WRPRT, /* 2: Write Protected */
RES_NOTRDY, /* 3: Not Ready */
RES_PARERR /* 4: Invalid Parameter */
} DRESULT;
/*---------------------------------------*/
/* Prototypes for disk control functions */
DSTATUS disk_initialize (BYTE pdrv);
DSTATUS disk_status (BYTE pdrv);
DRESULT disk_read (BYTE pdrv, BYTE* buff, DWORD sector, UINT count);
DRESULT disk_write (BYTE pdrv, const BYTE* buff, DWORD sector, UINT count);
DRESULT disk_ioctl (BYTE pdrv, BYTE cmd, void* buff);
/* Disk Status Bits (DSTATUS) */
#define STA_NOINIT 0x01 /* Drive not initialized */
#define STA_NODISK 0x02 /* No medium in the drive */
#define STA_PROTECT 0x04 /* Write protected */
/* Command code for disk_ioctrl fucntion */
/* Generic command (Used by FatFs) */
#define CTRL_SYNC 0 /* Complete pending write process (needed at _FS_READONLY == 0) */
#define GET_SECTOR_COUNT 1 /* Get media size (needed at _USE_MKFS == 1) */
#define GET_SECTOR_SIZE 2 /* Get sector size (needed at _MAX_SS != _MIN_SS) */
#define GET_BLOCK_SIZE 3 /* Get erase block size (needed at _USE_MKFS == 1) */
#define CTRL_TRIM 4 /* Inform device that the data on the block of sectors is no longer used (needed at _USE_TRIM == 1) */
/* Generic command (Not used by FatFs) */
#define CTRL_POWER 5 /* Get/Set power status */
#define CTRL_LOCK 6 /* Lock/Unlock media removal */
#define CTRL_EJECT 7 /* Eject media */
#define CTRL_FORMAT 8 /* Create physical format on the media */
/* MMC/SDC specific ioctl command */
#define MMC_GET_TYPE 10 /* Get card type */
#define MMC_GET_CSD 11 /* Get CSD */
#define MMC_GET_CID 12 /* Get CID */
#define MMC_GET_OCR 13 /* Get OCR */
#define MMC_GET_SDSTAT 14 /* Get SD status */
/* ATA/CF specific ioctl command */
#define ATA_GET_REV 20 /* Get F/W revision */
#define ATA_GET_MODEL 21 /* Get model name */
#define ATA_GET_SN 22 /* Get serial number */
#ifdef __cplusplus
}
#endif
#endif

4694
source/fatfs/ff.c Normal file

File diff suppressed because it is too large Load Diff

350
source/fatfs/ff.h Normal file
View File

@ -0,0 +1,350 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module include R0.11 (C)ChaN, 2015
/----------------------------------------------------------------------------/
/ FatFs module is a free software that opened under license policy of
/ following conditions.
/
/ Copyright (C) 2015, ChaN, all right reserved.
/
/ 1. Redistributions of source code must retain the above copyright notice,
/ this condition and the following disclaimer.
/
/ This software is provided by the copyright holder and contributors "AS IS"
/ and any warranties related to this software are DISCLAIMED.
/ The copyright owner or contributors be NOT LIABLE for any damages caused
/ by use of this software.
/---------------------------------------------------------------------------*/
#ifndef _FATFS
#define _FATFS 32020 /* Revision ID */
#ifdef __cplusplus
extern "C" {
#endif
#include "integer.h" /* Basic integer types */
#include "ffconf.h" /* FatFs configuration options */
#if _FATFS != _FFCONF
#error Wrong configuration file (ffconf.h).
#endif
/* Definitions of volume management */
#if _MULTI_PARTITION /* Multiple partition configuration */
typedef struct {
BYTE pd; /* Physical drive number */
BYTE pt; /* Partition: 0:Auto detect, 1-4:Forced partition) */
} PARTITION;
extern PARTITION VolToPart[]; /* Volume - Partition resolution table */
#define LD2PD(vol) (VolToPart[vol].pd) /* Get physical drive number */
#define LD2PT(vol) (VolToPart[vol].pt) /* Get partition index */
#else /* Single partition configuration */
#define LD2PD(vol) (BYTE)(vol) /* Each logical drive is bound to the same physical drive number */
#define LD2PT(vol) 0 /* Find first valid partition or in SFD */
#endif
/* Type of path name strings on FatFs API */
#if _LFN_UNICODE /* Unicode string */
#if !_USE_LFN
#error _LFN_UNICODE must be 0 at non-LFN cfg.
#endif
#ifndef _INC_TCHAR
typedef WCHAR TCHAR;
#define _T(x) L ## x
#define _TEXT(x) L ## x
#endif
#else /* ANSI/OEM string */
#ifndef _INC_TCHAR
typedef char TCHAR;
#define _T(x) x
#define _TEXT(x) x
#endif
#endif
/* File system object structure (FATFS) */
typedef struct {
BYTE fs_type; /* FAT sub-type (0:Not mounted) */
BYTE drv; /* Physical drive number */
BYTE csize; /* Sectors per cluster (1,2,4...128) */
BYTE n_fats; /* Number of FAT copies (1 or 2) */
BYTE wflag; /* win[] flag (b0:dirty) */
BYTE fsi_flag; /* FSINFO flags (b7:disabled, b0:dirty) */
WORD id; /* File system mount ID */
WORD n_rootdir; /* Number of root directory entries (FAT12/16) */
#if _MAX_SS != _MIN_SS
WORD ssize; /* Bytes per sector (512, 1024, 2048 or 4096) */
#endif
#if _FS_REENTRANT
_SYNC_t sobj; /* Identifier of sync object */
#endif
#if !_FS_READONLY
DWORD last_clust; /* Last allocated cluster */
DWORD free_clust; /* Number of free clusters */
#endif
#if _FS_RPATH
DWORD cdir; /* Current directory start cluster (0:root) */
#endif
DWORD n_fatent; /* Number of FAT entries, = number of clusters + 2 */
DWORD fsize; /* Sectors per FAT */
DWORD volbase; /* Volume start sector */
DWORD fatbase; /* FAT start sector */
DWORD dirbase; /* Root directory start sector (FAT32:Cluster#) */
DWORD database; /* Data start sector */
DWORD winsect; /* Current sector appearing in the win[] */
BYTE win[_MAX_SS]; /* Disk access window for Directory, FAT (and file data at tiny cfg) */
} FATFS;
/* File object structure (FIL) */
typedef struct {
FATFS* fs; /* Pointer to the related file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
BYTE flag; /* Status flags */
BYTE err; /* Abort flag (error code) */
DWORD fptr; /* File read/write pointer (Zeroed on file open) */
DWORD fsize; /* File size */
DWORD sclust; /* File start cluster (0:no cluster chain, always 0 when fsize is 0) */
DWORD clust; /* Current cluster of fpter (not valid when fprt is 0) */
DWORD dsect; /* Sector number appearing in buf[] (0:invalid) */
#if !_FS_READONLY
DWORD dir_sect; /* Sector number containing the directory entry */
BYTE* dir_ptr; /* Pointer to the directory entry in the win[] */
#endif
#if _USE_FASTSEEK
DWORD* cltbl; /* Pointer to the cluster link map table (Nulled on file open) */
#endif
#if _FS_LOCK
UINT lockid; /* File lock ID origin from 1 (index of file semaphore table Files[]) */
#endif
#if !_FS_TINY
BYTE buf[_MAX_SS]; /* File private data read/write window */
#endif
} FIL;
/* Directory object structure (DIR) */
typedef struct {
FATFS* fs; /* Pointer to the owner file system object (**do not change order**) */
WORD id; /* Owner file system mount ID (**do not change order**) */
WORD index; /* Current read/write index number */
DWORD sclust; /* Table start cluster (0:Root dir) */
DWORD clust; /* Current cluster */
DWORD sect; /* Current sector */
BYTE* dir; /* Pointer to the current SFN entry in the win[] */
BYTE* fn; /* Pointer to the SFN (in/out) {file[8],ext[3],status[1]} */
#if _FS_LOCK
UINT lockid; /* File lock ID (index of file semaphore table Files[]) */
#endif
#if _USE_LFN
WCHAR* lfn; /* Pointer to the LFN working buffer */
WORD lfn_idx; /* Last matched LFN index number (0xFFFF:No LFN) */
#endif
#if _USE_FIND
const TCHAR* pat; /* Pointer to the name matching pattern */
#endif
} DIR;
/* File information structure (FILINFO) */
typedef struct {
DWORD fsize; /* File size */
WORD fdate; /* Last modified date */
WORD ftime; /* Last modified time */
BYTE fattrib; /* Attribute */
TCHAR fname[13]; /* Short file name (8.3 format) */
#if _USE_LFN
TCHAR* lfname; /* Pointer to the LFN buffer */
UINT lfsize; /* Size of LFN buffer in TCHAR */
#endif
} FILINFO;
/* File function return code (FRESULT) */
typedef enum {
FR_OK = 0, /* (0) Succeeded */
FR_DISK_ERR, /* (1) A hard error occurred in the low level disk I/O layer */
FR_INT_ERR, /* (2) Assertion failed */
FR_NOT_READY, /* (3) The physical drive cannot work */
FR_NO_FILE, /* (4) Could not find the file */
FR_NO_PATH, /* (5) Could not find the path */
FR_INVALID_NAME, /* (6) The path name format is invalid */
FR_DENIED, /* (7) Access denied due to prohibited access or directory full */
FR_EXIST, /* (8) Access denied due to prohibited access */
FR_INVALID_OBJECT, /* (9) The file/directory object is invalid */
FR_WRITE_PROTECTED, /* (10) The physical drive is write protected */
FR_INVALID_DRIVE, /* (11) The logical drive number is invalid */
FR_NOT_ENABLED, /* (12) The volume has no work area */
FR_NO_FILESYSTEM, /* (13) There is no valid FAT volume */
FR_MKFS_ABORTED, /* (14) The f_mkfs() aborted due to any parameter error */
FR_TIMEOUT, /* (15) Could not get a grant to access the volume within defined period */
FR_LOCKED, /* (16) The operation is rejected according to the file sharing policy */
FR_NOT_ENOUGH_CORE, /* (17) LFN working buffer could not be allocated */
FR_TOO_MANY_OPEN_FILES, /* (18) Number of open files > _FS_SHARE */
FR_INVALID_PARAMETER /* (19) Given parameter is invalid */
} FRESULT;
/*--------------------------------------------------------------*/
/* FatFs module application interface */
FRESULT f_open (FIL* fp, const TCHAR* path, BYTE mode); /* Open or create a file */
FRESULT f_close (FIL* fp); /* Close an open file object */
FRESULT f_read (FIL* fp, void* buff, UINT btr, UINT* br); /* Read data from a file */
FRESULT f_write (FIL* fp, const void* buff, UINT btw, UINT* bw); /* Write data to a file */
FRESULT f_forward (FIL* fp, UINT(*func)(const BYTE*,UINT), UINT btf, UINT* bf); /* Forward data to the stream */
FRESULT f_lseek (FIL* fp, DWORD ofs); /* Move file pointer of a file object */
FRESULT f_truncate (FIL* fp); /* Truncate file */
FRESULT f_sync (FIL* fp); /* Flush cached data of a writing file */
FRESULT f_opendir (DIR* dp, const TCHAR* path); /* Open a directory */
FRESULT f_closedir (DIR* dp); /* Close an open directory */
FRESULT f_readdir (DIR* dp, FILINFO* fno); /* Read a directory item */
FRESULT f_findfirst (DIR* dp, FILINFO* fno, const TCHAR* path, const TCHAR* pattern); /* Find first file */
FRESULT f_findnext (DIR* dp, FILINFO* fno); /* Find next file */
FRESULT f_mkdir (const TCHAR* path); /* Create a sub directory */
FRESULT f_unlink (const TCHAR* path); /* Delete an existing file or directory */
FRESULT f_rename (const TCHAR* path_old, const TCHAR* path_new); /* Rename/Move a file or directory */
FRESULT f_stat (const TCHAR* path, FILINFO* fno); /* Get file status */
FRESULT f_chmod (const TCHAR* path, BYTE attr, BYTE mask); /* Change attribute of the file/dir */
FRESULT f_utime (const TCHAR* path, const FILINFO* fno); /* Change times-tamp of the file/dir */
FRESULT f_chdir (const TCHAR* path); /* Change current directory */
FRESULT f_chdrive (const TCHAR* path); /* Change current drive */
FRESULT f_getcwd (TCHAR* buff, UINT len); /* Get current directory */
FRESULT f_getfree (const TCHAR* path, DWORD* nclst, FATFS** fatfs); /* Get number of free clusters on the drive */
FRESULT f_getlabel (const TCHAR* path, TCHAR* label, DWORD* vsn); /* Get volume label */
FRESULT f_setlabel (const TCHAR* label); /* Set volume label */
FRESULT f_mount (FATFS* fs, const TCHAR* path, BYTE opt); /* Mount/Unmount a logical drive */
FRESULT f_mkfs (const TCHAR* path, BYTE sfd, UINT au); /* Create a file system on the volume */
FRESULT f_fdisk (BYTE pdrv, const DWORD szt[], void* work); /* Divide a physical drive into some partitions */
int f_putc (TCHAR c, FIL* fp); /* Put a character to the file */
int f_puts (const TCHAR* str, FIL* cp); /* Put a string to the file */
int f_printf (FIL* fp, const TCHAR* str, ...); /* Put a formatted string to the file */
TCHAR* f_gets (TCHAR* buff, int len, FIL* fp); /* Get a string from the file */
#define f_eof(fp) ((int)((fp)->fptr == (fp)->fsize))
#define f_error(fp) ((fp)->err)
#define f_tell(fp) ((fp)->fptr)
#define f_size(fp) ((fp)->fsize)
#define f_rewind(fp) f_lseek((fp), 0)
#define f_rewinddir(dp) f_readdir((dp), 0)
#ifndef EOF
#define EOF (-1)
#endif
/*--------------------------------------------------------------*/
/* Additional user defined functions */
/* RTC function */
#if !_FS_READONLY && !_FS_NORTC
DWORD get_fattime (void);
#endif
/* Unicode support functions */
#if _USE_LFN /* Unicode - OEM code conversion */
WCHAR ff_convert (WCHAR chr, UINT dir); /* OEM-Unicode bidirectional conversion */
WCHAR ff_wtoupper (WCHAR chr); /* Unicode upper-case conversion */
#if _USE_LFN == 3 /* Memory functions */
void* ff_memalloc (UINT msize); /* Allocate memory block */
void ff_memfree (void* mblock); /* Free memory block */
#endif
#endif
/* Sync functions */
#if _FS_REENTRANT
int ff_cre_syncobj (BYTE vol, _SYNC_t* sobj); /* Create a sync object */
int ff_req_grant (_SYNC_t sobj); /* Lock sync object */
void ff_rel_grant (_SYNC_t sobj); /* Unlock sync object */
int ff_del_syncobj (_SYNC_t sobj); /* Delete a sync object */
#endif
/*--------------------------------------------------------------*/
/* Flags and offset address */
/* File access control and file status flags (FIL.flag) */
#define FA_READ 0x01
#define FA_OPEN_EXISTING 0x00
#if !_FS_READONLY
#define FA_WRITE 0x02
#define FA_CREATE_NEW 0x04
#define FA_CREATE_ALWAYS 0x08
#define FA_OPEN_ALWAYS 0x10
#define FA__WRITTEN 0x20
#define FA__DIRTY 0x40
#endif
/* FAT sub type (FATFS.fs_type) */
#define FS_FAT12 1
#define FS_FAT16 2
#define FS_FAT32 3
/* File attribute bits for directory entry */
#define AM_RDO 0x01 /* Read only */
#define AM_HID 0x02 /* Hidden */
#define AM_SYS 0x04 /* System */
#define AM_VOL 0x08 /* Volume label */
#define AM_LFN 0x0F /* LFN entry */
#define AM_DIR 0x10 /* Directory */
#define AM_ARC 0x20 /* Archive */
#define AM_MASK 0x3F /* Mask of defined bits */
/* Fast seek feature */
#define CREATE_LINKMAP 0xFFFFFFFF
/*--------------------------------*/
/* Multi-byte word access macros */
#if _WORD_ACCESS == 1 /* Enable word access to the FAT structure */
#define LD_WORD(ptr) (WORD)(*(WORD*)(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(*(DWORD*)(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(WORD*)(BYTE*)(ptr)=(WORD)(val)
#define ST_DWORD(ptr,val) *(DWORD*)(BYTE*)(ptr)=(DWORD)(val)
#else /* Use byte-by-byte access to the FAT structure */
#define LD_WORD(ptr) (WORD)(((WORD)*((BYTE*)(ptr)+1)<<8)|(WORD)*(BYTE*)(ptr))
#define LD_DWORD(ptr) (DWORD)(((DWORD)*((BYTE*)(ptr)+3)<<24)|((DWORD)*((BYTE*)(ptr)+2)<<16)|((WORD)*((BYTE*)(ptr)+1)<<8)|*(BYTE*)(ptr))
#define ST_WORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8)
#define ST_DWORD(ptr,val) *(BYTE*)(ptr)=(BYTE)(val); *((BYTE*)(ptr)+1)=(BYTE)((WORD)(val)>>8); *((BYTE*)(ptr)+2)=(BYTE)((DWORD)(val)>>16); *((BYTE*)(ptr)+3)=(BYTE)((DWORD)(val)>>24)
#endif
#ifdef __cplusplus
}
#endif
#endif /* _FATFS */

271
source/fatfs/ffconf.h Normal file
View File

@ -0,0 +1,271 @@
/*---------------------------------------------------------------------------/
/ FatFs - FAT file system module configuration file R0.11 (C)ChaN, 2015
/---------------------------------------------------------------------------*/
#define _FFCONF 32020 /* Revision ID */
/*---------------------------------------------------------------------------/
/ Functions and Buffer Configurations
/---------------------------------------------------------------------------*/
#define _FS_TINY 0
/* This option switches tiny buffer configuration. (0:Normal or 1:Tiny)
/ At the tiny configuration, size of the file object (FIL) is reduced _MAX_SS
/ bytes. Instead of private sector buffer eliminated from the file object,
/ common sector buffer in the file system object (FATFS) is used for the file
/ data transfer. */
#define _FS_READONLY 0
/* This option switches read-only configuration. (0:Read/Write or 1:Read-only)
/ Read-only configuration removes writing API functions, f_write(), f_sync(),
/ f_unlink(), f_mkdir(), f_chmod(), f_rename(), f_truncate(), f_getfree()
/ and optional writing functions as well. */
#define _FS_MINIMIZE 0
/* This option defines minimization level to remove some basic API functions.
/
/ 0: All basic functions are enabled.
/ 1: f_stat(), f_getfree(), f_unlink(), f_mkdir(), f_chmod(), f_utime(),
/ f_truncate() and f_rename() function are removed.
/ 2: f_opendir(), f_readdir() and f_closedir() are removed in addition to 1.
/ 3: f_lseek() function is removed in addition to 2. */
#define _USE_STRFUNC 0
/* This option switches string functions, f_gets(), f_putc(), f_puts() and
/ f_printf().
/
/ 0: Disable string functions.
/ 1: Enable without LF-CRLF conversion.
/ 2: Enable with LF-CRLF conversion. */
#define _USE_FIND 0
/* This option switches filtered directory read feature and related functions,
/ f_findfirst() and f_findnext(). (0:Disable or 1:Enable) */
#define _USE_MKFS 0
/* This option switches f_mkfs() function. (0:Disable or 1:Enable) */
#define _USE_FASTSEEK 0
/* This option switches fast seek feature. (0:Disable or 1:Enable) */
#define _USE_LABEL 0
/* This option switches volume label functions, f_getlabel() and f_setlabel().
/ (0:Disable or 1:Enable) */
#define _USE_FORWARD 0
/* This option switches f_forward() function. (0:Disable or 1:Enable)
/ To enable it, also _FS_TINY need to be set to 1. */
/*---------------------------------------------------------------------------/
/ Locale and Namespace Configurations
/---------------------------------------------------------------------------*/
#define _CODE_PAGE 437
/* This option specifies the OEM code page to be used on the target system.
/ Incorrect setting of the code page can cause a file open failure.
/
/ 1 - ASCII (No extended character. Non-LFN cfg. only)
/ 437 - U.S.
/ 720 - Arabic
/ 737 - Greek
/ 775 - Baltic
/ 850 - Multilingual Latin 1
/ 852 - Latin 2
/ 855 - Cyrillic
/ 857 - Turkish
/ 858 - Multilingual Latin 1 + Euro
/ 862 - Hebrew
/ 866 - Russian
/ 874 - Thai
/ 932 - Japanese Shift_JIS (DBCS)
/ 936 - Simplified Chinese GBK (DBCS)
/ 949 - Korean (DBCS)
/ 950 - Traditional Chinese Big5 (DBCS)
*/
#define _USE_LFN 2
#define _MAX_LFN 255
/* The _USE_LFN option switches the LFN feature.
/
/ 0: Disable LFN feature. _MAX_LFN has no effect.
/ 1: Enable LFN with static working buffer on the BSS. Always NOT thread-safe.
/ 2: Enable LFN with dynamic working buffer on the STACK.
/ 3: Enable LFN with dynamic working buffer on the HEAP.
/
/ When enable the LFN feature, Unicode handling functions (option/unicode.c) must
/ be added to the project. The LFN working buffer occupies (_MAX_LFN + 1) * 2 bytes.
/ When use stack for the working buffer, take care on stack overflow. When use heap
/ memory for the working buffer, memory management functions, ff_memalloc() and
/ ff_memfree(), must be added to the project. */
#define _LFN_UNICODE 0
/* This option switches character encoding on the API. (0:ANSI/OEM or 1:Unicode)
/ To use Unicode string for the path name, enable LFN feature and set _LFN_UNICODE
/ to 1. This option also affects behavior of string I/O functions. */
#define _STRF_ENCODE 0
/* When _LFN_UNICODE is 1, this option selects the character encoding on the file to
/ be read/written via string I/O functions, f_gets(), f_putc(), f_puts and f_printf().
/
/ 0: ANSI/OEM
/ 1: UTF-16LE
/ 2: UTF-16BE
/ 3: UTF-8
/
/ When _LFN_UNICODE is 0, this option has no effect. */
#define _FS_RPATH 1
/* This option configures relative path feature.
/
/ 0: Disable relative path feature and remove related functions.
/ 1: Enable relative path feature. f_chdir() and f_chdrive() are available.
/ 2: f_getcwd() function is available in addition to 1.
/
/ Note that directory items read via f_readdir() are affected by this option. */
/*---------------------------------------------------------------------------/
/ Drive/Volume Configurations
/---------------------------------------------------------------------------*/
#define _VOLUMES 1
/* Number of volumes (logical drives) to be used. */
#define _STR_VOLUME_ID 0
#define _VOLUME_STRS "RAM","NAND","CF","SD1","SD2","USB1","USB2","USB3"
/* _STR_VOLUME_ID option switches string volume ID feature.
/ When _STR_VOLUME_ID is set to 1, also pre-defined strings can be used as drive
/ number in the path name. _VOLUME_STRS defines the drive ID strings for each
/ logical drives. Number of items must be equal to _VOLUMES. Valid characters for
/ the drive ID strings are: A-Z and 0-9. */
#define _MULTI_PARTITION 0
/* This option switches multi-partition feature. By default (0), each logical drive
/ number is bound to the same physical drive number and only an FAT volume found on
/ the physical drive will be mounted. When multi-partition feature is enabled (1),
/ each logical drive number is bound to arbitrary physical drive and partition
/ listed in the VolToPart[]. Also f_fdisk() funciton will be available. */
#define _MIN_SS 512
#define _MAX_SS 512
/* These options configure the range of sector size to be supported. (512, 1024,
/ 2048 or 4096) Always set both 512 for most systems, all type of memory cards and
/ harddisk. But a larger value may be required for on-board flash memory and some
/ type of optical media. When _MAX_SS is larger than _MIN_SS, FatFs is configured
/ to variable sector size and GET_SECTOR_SIZE command must be implemented to the
/ disk_ioctl() function. */
#define _USE_TRIM 0
/* This option switches ATA-TRIM feature. (0:Disable or 1:Enable)
/ To enable Trim feature, also CTRL_TRIM command should be implemented to the
/ disk_ioctl() function. */
#define _FS_NOFSINFO 0
/* If you need to know correct free space on the FAT32 volume, set bit 0 of this
/ option, and f_getfree() function at first time after volume mount will force
/ a full FAT scan. Bit 1 controls the use of last allocated cluster number.
/
/ bit0=0: Use free cluster count in the FSINFO if available.
/ bit0=1: Do not trust free cluster count in the FSINFO.
/ bit1=0: Use last allocated cluster number in the FSINFO if available.
/ bit1=1: Do not trust last allocated cluster number in the FSINFO.
*/
/*---------------------------------------------------------------------------/
/ System Configurations
/---------------------------------------------------------------------------*/
#define _FS_NORTC 1
#define _NORTC_MON 2
#define _NORTC_MDAY 1
#define _NORTC_YEAR 2015
/* The _FS_NORTC option switches timestamp feature. If the system does not have
/ an RTC function or valid timestamp is not needed, set _FS_NORTC to 1 to disable
/ the timestamp feature. All objects modified by FatFs will have a fixed timestamp
/ defined by _NORTC_MON, _NORTC_MDAY and _NORTC_YEAR.
/ When timestamp feature is enabled (_FS_NORTC == 0), get_fattime() function need
/ to be added to the project to read current time form RTC. _NORTC_MON,
/ _NORTC_MDAY and _NORTC_YEAR have no effect.
/ These options have no effect at read-only configuration (_FS_READONLY == 1). */
#define _FS_LOCK 0
/* The _FS_LOCK option switches file lock feature to control duplicated file open
/ and illegal operation to open objects. This option must be 0 when _FS_READONLY
/ is 1.
/
/ 0: Disable file lock feature. To avoid volume corruption, application program
/ should avoid illegal open, remove and rename to the open objects.
/ >0: Enable file lock feature. The value defines how many files/sub-directories
/ can be opened simultaneously under file lock control. Note that the file
/ lock feature is independent of re-entrancy. */
#define _FS_REENTRANT 0
#define _FS_TIMEOUT 1000
#define _SYNC_t HANDLE
/* The _FS_REENTRANT option switches the re-entrancy (thread safe) of the FatFs
/ module itself. Note that regardless of this option, file access to different
/ volume is always re-entrant and volume control functions, f_mount(), f_mkfs()
/ and f_fdisk() function, are always not re-entrant. Only file/directory access
/ to the same volume is under control of this feature.
/
/ 0: Disable re-entrancy. _FS_TIMEOUT and _SYNC_t have no effect.
/ 1: Enable re-entrancy. Also user provided synchronization handlers,
/ ff_req_grant(), ff_rel_grant(), ff_del_syncobj() and ff_cre_syncobj()
/ function, must be added to the project. Samples are available in
/ option/syscall.c.
/
/ The _FS_TIMEOUT defines timeout period in unit of time tick.
/ The _SYNC_t defines O/S dependent sync object type. e.g. HANDLE, ID, OS_EVENT*,
/ SemaphoreHandle_t and etc.. A header file for O/S definitions needs to be
/ included somewhere in the scope of ff.c. */
#define _WORD_ACCESS 0
/* The _WORD_ACCESS option is an only platform dependent option. It defines
/ which access method is used to the word data on the FAT volume.
/
/ 0: Byte-by-byte access. Always compatible with all platforms.
/ 1: Word access. Do not choose this unless under both the following conditions.
/
/ * Address misaligned memory access is always allowed to ALL instructions.
/ * Byte order on the memory is little-endian.
/
/ If it is the case, _WORD_ACCESS can also be set to 1 to reduce code size.
/ Following table shows allowable settings of some processor types.
/
/ ARM7TDMI 0 *2 ColdFire 0 *1 V850E 0 *2
/ Cortex-M3 0 *3 Z80 0/1 V850ES 0/1
/ Cortex-M0 0 *2 x86 0/1 TLCS-870 0/1
/ AVR 0/1 RX600(LE) 0/1 TLCS-900 0/1
/ AVR32 0 *1 RL78 0 *2 R32C 0 *2
/ PIC18 0/1 SH-2 0 *1 M16C 0/1
/ PIC24 0 *2 H8S 0 *1 MSP430 0 *2
/ PIC32 0 *1 H8/300H 0 *1 8051 0/1
/
/ *1:Big-endian.
/ *2:Unaligned memory access is not supported.
/ *3:Some compilers generate LDM/STM for mem_cpy function.
*/

180
source/fatfs/history.txt Normal file
View File

@ -0,0 +1,180 @@
----------------------------------------------------------------------------
Revision history of FatFs module
----------------------------------------------------------------------------
R0.00 (February 26, 2006)
Prototype.
R0.01 (April 29, 2006)
First stable version.
R0.02 (June 01, 2006)
Added FAT12 support.
Removed unbuffered mode.
Fixed a problem on small (<32M) partition.
R0.02a (June 10, 2006)
Added a configuration option (_FS_MINIMUM).
R0.03 (September 22, 2006)
Added f_rename().
Changed option _FS_MINIMUM to _FS_MINIMIZE.
R0.03a (December 11, 2006)
Improved cluster scan algorithm to write files fast.
Fixed f_mkdir() creates incorrect directory on FAT32.
R0.04 (February 04, 2007)
Added f_mkfs().
Supported multiple drive system.
Changed some interfaces for multiple drive system.
Changed f_mountdrv() to f_mount().
R0.04a (April 01, 2007)
Supported multiple partitions on a physical drive.
Added a capability of extending file size to f_lseek().
Added minimization level 3.
Fixed an endian sensitive code in f_mkfs().
R0.04b (May 05, 2007)
Added a configuration option _USE_NTFLAG.
Added FSINFO support.
Fixed DBCS name can result FR_INVALID_NAME.
Fixed short seek (<= csize) collapses the file object.
R0.05 (August 25, 2007)
Changed arguments of f_read(), f_write() and f_mkfs().
Fixed f_mkfs() on FAT32 creates incorrect FSINFO.
Fixed f_mkdir() on FAT32 creates incorrect directory.
R0.05a (February 03, 2008)
Added f_truncate() and f_utime().
Fixed off by one error at FAT sub-type determination.
Fixed btr in f_read() can be mistruncated.
Fixed cached sector is not flushed when create and close without write.
R0.06 (April 01, 2008)
Added fputc(), fputs(), fprintf() and fgets().
Improved performance of f_lseek() on moving to the same or following cluster.
R0.07 (April 01, 2009)
Merged Tiny-FatFs as a configuration option. (_FS_TINY)
Added long file name feature. (_USE_LFN)
Added multiple code page feature. (_CODE_PAGE)
Added re-entrancy for multitask operation. (_FS_REENTRANT)
Added auto cluster size selection to f_mkfs().
Added rewind option to f_readdir().
Changed result code of critical errors.
Renamed string functions to avoid name collision.
R0.07a (April 14, 2009)
Septemberarated out OS dependent code on reentrant cfg.
Added multiple sector size feature.
R0.07c (June 21, 2009)
Fixed f_unlink() can return FR_OK on error.
Fixed wrong cache control in f_lseek().
Added relative path feature.
Added f_chdir() and f_chdrive().
Added proper case conversion to extended character.
R0.07e (November 03, 2009)
Septemberarated out configuration options from ff.h to ffconf.h.
Fixed f_unlink() fails to remove a sub-directory on _FS_RPATH.
Fixed name matching error on the 13 character boundary.
Added a configuration option, _LFN_UNICODE.
Changed f_readdir() to return the SFN with always upper case on non-LFN cfg.
R0.08 (May 15, 2010)
Added a memory configuration option. (_USE_LFN = 3)
Added file lock feature. (_FS_SHARE)
Added fast seek feature. (_USE_FASTSEEK)
Changed some types on the API, XCHAR->TCHAR.
Changed .fname in the FILINFO structure on Unicode cfg.
String functions support UTF-8 encoding files on Unicode cfg.
R0.08a (August 16, 2010)
Added f_getcwd(). (_FS_RPATH = 2)
Added sector erase feature. (_USE_ERASE)
Moved file lock semaphore table from fs object to the bss.
Fixed f_mkfs() creates wrong FAT32 volume.
R0.08b (January 15, 2011)
Fast seek feature is also applied to f_read() and f_write().
f_lseek() reports required table size on creating CLMP.
Extended format syntax of f_printf().
Ignores duplicated directory separators in given path name.
R0.09 (September 06, 2011)
f_mkfs() supports multiple partition to complete the multiple partition feature.
Added f_fdisk().
R0.09a (August 27, 2012)
Changed f_open() and f_opendir() reject null object pointer to avoid crash.
Changed option name _FS_SHARE to _FS_LOCK.
Fixed assertion failure due to OS/2 EA on FAT12/16 volume.
R0.09b (January 24, 2013)
Added f_setlabel() and f_getlabel().
R0.10 (October 02, 2013)
Added selection of character encoding on the file. (_STRF_ENCODE)
Added f_closedir().
Added forced full FAT scan for f_getfree(). (_FS_NOFSINFO)
Added forced mount feature with changes of f_mount().
Improved behavior of volume auto detection.
Improved write throughput of f_puts() and f_printf().
Changed argument of f_chdrive(), f_mkfs(), disk_read() and disk_write().
Fixed f_write() can be truncated when the file size is close to 4GB.
Fixed f_open(), f_mkdir() and f_setlabel() can return incorrect error code.
R0.10a (January 15, 2014)
Added arbitrary strings as drive number in the path name. (_STR_VOLUME_ID)
Added a configuration option of minimum sector size. (_MIN_SS)
2nd argument of f_rename() can have a drive number and it will be ignored.
Fixed f_mount() with forced mount fails when drive number is >= 1. (appeared at R0.10)
Fixed f_close() invalidates the file object without volume lock.
Fixed f_closedir() returns but the volume lock is left acquired. (appeared at R0.10)
Fixed creation of an entry with LFN fails on too many SFN collisions. (appeared at R0.07)
R0.10b (May 19, 2014)
Fixed a hard error in the disk I/O layer can collapse the directory entry.
Fixed LFN entry is not deleted on delete/rename an object with lossy converted SFN. (appeared at R0.07)
R0.10c (November 09, 2014)
Added a configuration option for the platforms without RTC. (_FS_NORTC)
Changed option name _USE_ERASE to _USE_TRIM.
Fixed volume label created by Mac OS X cannot be retrieved with f_getlabel(). (appeared at R0.09b)
Fixed a potential problem of FAT access that can appear on disk error.
Fixed null pointer dereference on attempting to delete the root direcotry. (appeared at R0.08)
R0.11 (February 09, 2015)
Added f_findfirst(), f_findnext() and f_findclose(). (_USE_FIND)
Fixed f_unlink() does not remove cluster chain of the file. (appeared at R0.10c)
Fixed _FS_NORTC option does not work properly. (appeared at R0.10c)

33
source/fatfs/integer.h Normal file
View File

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

3829
source/fatfs/option/cc932.c Normal file

File diff suppressed because it is too large Load Diff

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

@ -0,0 +1,151 @@
/*------------------------------------------------------------------------*/
/* Sample code of OS dependent controls for FatFs */
/* (C)ChaN, 2014 */
/*------------------------------------------------------------------------*/
#include "../ff.h"
#if _FS_REENTRANT
/*------------------------------------------------------------------------*/
/* Create a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to create a new
/ synchronization object, such as semaphore and mutex. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_cre_syncobj ( /* !=0:Function succeeded, ==0:Could not create due to any error */
BYTE vol, /* Corresponding logical drive being processed */
_SYNC_t *sobj /* Pointer to return the created sync object */
)
{
int ret;
*sobj = CreateMutex(NULL, FALSE, NULL); /* Win32 */
ret = (int)(*sobj != INVALID_HANDLE_VALUE);
// *sobj = SyncObjects[vol]; /* uITRON (give a static created sync object) */
// ret = 1; /* The initial value of the semaphore must be 1. */
// *sobj = OSMutexCreate(0, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// *sobj = xSemaphoreCreateMutex(); /* FreeRTOS */
// ret = (int)(*sobj != NULL);
return ret;
}
/*------------------------------------------------------------------------*/
/* Delete a Synchronization Object */
/*------------------------------------------------------------------------*/
/* This function is called in f_mount() function to delete a synchronization
/ object that created with ff_cre_syncobj function. When a 0 is returned,
/ the f_mount() function fails with FR_INT_ERR.
*/
int ff_del_syncobj ( /* !=0:Function succeeded, ==0:Could not delete due to any error */
_SYNC_t sobj /* Sync object tied to the logical drive to be deleted */
)
{
int ret;
ret = CloseHandle(sobj); /* Win32 */
// ret = 1; /* uITRON (nothing to do) */
// OSMutexDel(sobj, OS_DEL_ALWAYS, &err); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// vSemaphoreDelete(sobj); /* FreeRTOS */
// ret = 1;
return ret;
}
/*------------------------------------------------------------------------*/
/* Request Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on entering file functions to lock the volume.
/ When a 0 is returned, the file function fails with FR_TIMEOUT.
*/
int ff_req_grant ( /* 1:Got a grant to access the volume, 0:Could not get a grant */
_SYNC_t sobj /* Sync object to wait */
)
{
int ret;
ret = (int)(WaitForSingleObject(sobj, _FS_TIMEOUT) == WAIT_OBJECT_0); /* Win32 */
// ret = (int)(wai_sem(sobj) == E_OK); /* uITRON */
// OSMutexPend(sobj, _FS_TIMEOUT, &err)); /* uC/OS-II */
// ret = (int)(err == OS_NO_ERR);
// ret = (int)(xSemaphoreTake(sobj, _FS_TIMEOUT) == pdTRUE); /* FreeRTOS */
return ret;
}
/*------------------------------------------------------------------------*/
/* Release Grant to Access the Volume */
/*------------------------------------------------------------------------*/
/* This function is called on leaving file functions to unlock the volume.
*/
void ff_rel_grant (
_SYNC_t sobj /* Sync object to be signaled */
)
{
ReleaseMutex(sobj); /* Win32 */
// sig_sem(sobj); /* uITRON */
// OSMutexPost(sobj); /* uC/OS-II */
// xSemaphoreGive(sobj); /* FreeRTOS */
}
#endif
#if _USE_LFN == 3 /* LFN with a working buffer on the heap */
/*------------------------------------------------------------------------*/
/* Allocate a memory block */
/*------------------------------------------------------------------------*/
/* If a NULL is returned, the file function fails with FR_NOT_ENOUGH_CORE.
*/
void* ff_memalloc ( /* Returns pointer to the allocated memory block */
UINT msize /* Number of bytes to allocate */
)
{
return malloc(msize); /* Allocate a new memory block with POSIX API */
}
/*------------------------------------------------------------------------*/
/* Free a memory block */
/*------------------------------------------------------------------------*/
void ff_memfree (
void* mblock /* Pointer to the memory block to free */
)
{
free(mblock); /* Discard the memory block with POSIX API */
}
#endif

View File

@ -0,0 +1,17 @@
#include "../ff.h"
#if _USE_LFN != 0
#if _CODE_PAGE == 932 /* Japanese Shift_JIS */
#include "cc932.c"
#elif _CODE_PAGE == 936 /* Simplified Chinese GBK */
#include "cc936.c"
#elif _CODE_PAGE == 949 /* Korean */
#include "cc949.c"
#elif _CODE_PAGE == 950 /* Traditional Chinese Big5 */
#include "cc950.c"
#else /* Single Byte Character-Set */
#include "ccsbcs.c"
#endif
#endif

620
source/fatfs/sdmmc.c Normal file
View File

@ -0,0 +1,620 @@
/*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/.
*
* Copyright (c) 2014, Normmatt
*
* Alternatively, the contents of this file may be used under the terms
* of the GNU General Public License Version 2, as described below:
*
* This file is free software: you may copy, redistribute and/or modify
* it under the terms of the GNU General Public License as published by the
* Free Software Foundation, either version 2 of the License, or (at your
* option) any later version.
*
* This file is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
* Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see http://www.gnu.org/licenses/.
*/
#include <stdint.h>
#include <string.h>
#include <stdlib.h>
#include <inttypes.h>
#include <malloc.h>
#include <stdio.h>
#include <unistd.h>
#include <dirent.h>
#include <errno.h>
#include "sdmmc.h"
//#include "DrawCharacter.h"
//Uncomment to enable 32bit fifo support?
//not currently working
//#define DATA32_SUPPORT
#define TRUE 1
#define FALSE 0
#define bool int
#define NO_INLINE __attribute__ ((noinline))
#define RGB(r,g,b) (r<<24|b<<16|g<<8|r)
#ifdef __cplusplus
extern "C" {
#endif
void waitcycles(uint32_t val);
#ifdef __cplusplus
};
#endif
//#define DEBUG_SDMMC
#ifdef DEBUG_SDMMC
extern uint8_t* topScreen;
extern void DrawHexWithName(unsigned char *screen, const char *str, unsigned int hex, int x, int y, int color, int bgcolor);
#define DEBUGPRINT(scr,str,hex,x,y,color,bg) DrawHexWithName(scr,str,hex,x,y,color,bg)
#else
#define DEBUGPRINT(...)
#endif
//extern "C" void sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args);
//extern "C" void inittarget(struct mmcdevice *ctx);
//extern "C" int SD_Init();
//extern "C" int SD_Init2();
//extern "C" int Nand_Init2();
//extern "C" void InitSD();
struct mmcdevice handelNAND;
struct mmcdevice handelSD;
mmcdevice *getMMCDevice(int drive)
{
if(drive==0) return &handelNAND;
return &handelSD;
}
int geterror(struct mmcdevice *ctx)
{
return (ctx->error << 29) >> 31;
}
void inittarget(struct mmcdevice *ctx)
{
sdmmc_mask16(REG_SDPORTSEL,0x3,(uint16_t)ctx->devicenumber);
setckl(ctx->clk);
if(ctx->SDOPT == 0)
{
sdmmc_mask16(REG_SDOPT,0,0x8000);
}
else
{
sdmmc_mask16(REG_SDOPT,0x8000,0);
}
}
void NO_INLINE sdmmc_send_command(struct mmcdevice *ctx, uint32_t cmd, uint32_t args)
{
bool getSDRESP = (cmd << 15) >> 31;
uint16_t flags = (cmd << 15) >> 31;
const bool readdata = cmd & 0x20000;
const bool writedata = cmd & 0x40000;
if(readdata || writedata)
{
flags |= TMIO_STAT0_DATAEND;
}
ctx->error = 0;
while((sdmmc_read16(REG_SDSTATUS1) & TMIO_STAT1_CMD_BUSY)); //mmc working?
sdmmc_write16(REG_SDIRMASK0,0);
sdmmc_write16(REG_SDIRMASK1,0);
sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1,0);
#ifdef DATA32_SUPPORT
// if(readdata)sdmmc_mask16(REG_DATACTL32, 0x1000, 0x800);
// if(writedata)sdmmc_mask16(REG_DATACTL32, 0x800, 0x1000);
// sdmmc_mask16(REG_DATACTL32,0x1800,2);
#else
sdmmc_mask16(REG_DATACTL32,0x1800,0);
#endif
sdmmc_write16(REG_SDCMDARG0,args &0xFFFF);
sdmmc_write16(REG_SDCMDARG1,args >> 16);
sdmmc_write16(REG_SDCMD,cmd &0xFFFF);
uint32_t size = ctx->size;
uint16_t *dataPtr = (uint16_t*)ctx->data;
#ifdef DATA32_SUPPORT
uint32_t *dataPtr32 = (uint32_t*)ctx->data;
#endif
bool useBuf = ( NULL != dataPtr );
#ifdef DATA32_SUPPORT
bool useBuf32 = (useBuf && (0 == (3 & ((uint32_t)dataPtr))));
#endif
uint16_t status0 = 0;
while(1)
{
volatile uint16_t status1 = sdmmc_read16(REG_SDSTATUS1);
#ifdef DATA32_SUPPORT
volatile uint16_t ctl32 = sdmmc_read16(REG_DATACTL32);
if((ctl32 & 0x100))
#else
if((status1 & TMIO_STAT1_RXRDY))
#endif
{
if(readdata)
{
if(useBuf)
{
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_RXRDY, 0);
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_RXRDY);
if(size > 0x1FF)
{
#ifdef DATA32_SUPPORT
if(useBuf32)
{
for(int i = 0; i<0x200; i+=4)
{
*dataPtr32++ = sdmmc_read32(REG_SDFIFO32);
}
}
else
{
#endif
for(int i = 0; i<0x200; i+=2)
{
*dataPtr++ = sdmmc_read16(REG_SDFIFO);
}
#ifdef DATA32_SUPPORT
}
#endif
size -= 0x200;
}
}
sdmmc_mask16(REG_DATACTL32, 0x800, 0);
}
}
#ifdef DATA32_SUPPORT
if(!(ctl32 & 0x200))
#else
if((status1 & TMIO_STAT1_TXRQ))
#endif
{
if(writedata)
{
if(useBuf)
{
sdmmc_mask16(REG_SDSTATUS1, TMIO_STAT1_TXRQ, 0);
//sdmmc_write16(REG_SDSTATUS1,~TMIO_STAT1_TXRQ);
if(size > 0x1FF)
{
#ifdef DATA32_SUPPORT
for(int i = 0; i<0x200; i+=4)
{
sdmmc_write32(REG_SDFIFO32,*dataPtr32++);
}
#else
for(int i = 0; i<0x200; i+=2)
{
sdmmc_write16(REG_SDFIFO,*dataPtr++);
}
#endif
size -= 0x200;
}
}
sdmmc_mask16(REG_DATACTL32, 0x1000, 0);
}
}
if(status1 & TMIO_MASK_GW)
{
ctx->error |= 4;
break;
}
if(!(status1 & TMIO_STAT1_CMD_BUSY))
{
status0 = sdmmc_read16(REG_SDSTATUS0);
if(sdmmc_read16(REG_SDSTATUS0) & TMIO_STAT0_CMDRESPEND)
{
ctx->error |= 0x1;
}
if(status0 & TMIO_STAT0_DATAEND)
{
ctx->error |= 0x2;
}
if((status0 & flags) == flags)
break;
}
}
ctx->stat0 = sdmmc_read16(REG_SDSTATUS0);
ctx->stat1 = sdmmc_read16(REG_SDSTATUS1);
sdmmc_write16(REG_SDSTATUS0,0);
sdmmc_write16(REG_SDSTATUS1,0);
if(getSDRESP != 0)
{
ctx->ret[0] = sdmmc_read16(REG_SDRESP0) | (sdmmc_read16(REG_SDRESP1) << 16);
ctx->ret[1] = sdmmc_read16(REG_SDRESP2) | (sdmmc_read16(REG_SDRESP3) << 16);
ctx->ret[2] = sdmmc_read16(REG_SDRESP4) | (sdmmc_read16(REG_SDRESP5) << 16);
ctx->ret[3] = sdmmc_read16(REG_SDRESP6) | (sdmmc_read16(REG_SDRESP7) << 16);
}
}
int NO_INLINE sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in)
{
if(handelSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handelSD);
sdmmc_write16(REG_SDSTOP,0x100);
#ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handelSD.data = in;
handelSD.size = numsectors << 9;
sdmmc_send_command(&handelSD,0x52C19,sector_no);
return geterror(&handelSD);
}
int NO_INLINE sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
{
if(handelSD.isSDHC == 0) sector_no <<= 9;
inittarget(&handelSD);
sdmmc_write16(REG_SDSTOP,0x100);
#ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handelSD.data = out;
handelSD.size = numsectors << 9;
sdmmc_send_command(&handelSD,0x33C12,sector_no);
return geterror(&handelSD);
}
int NO_INLINE sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out)
{
if(handelNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handelNAND);
sdmmc_write16(REG_SDSTOP,0x100);
#ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handelNAND.data = out;
handelNAND.size = numsectors << 9;
sdmmc_send_command(&handelNAND,0x33C12,sector_no);
inittarget(&handelSD);
return geterror(&handelNAND);
}
int NO_INLINE sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in) //experimental
{
if(handelNAND.isSDHC == 0) sector_no <<= 9;
inittarget(&handelNAND);
sdmmc_write16(REG_SDSTOP,0x100);
#ifdef DATA32_SUPPORT
sdmmc_write16(REG_SDBLKCOUNT32,numsectors);
sdmmc_write16(REG_SDBLKLEN32,0x200);
#endif
sdmmc_write16(REG_SDBLKCOUNT,numsectors);
handelNAND.data = in;
handelNAND.size = numsectors << 9;
sdmmc_send_command(&handelNAND,0x52C19,sector_no);
inittarget(&handelSD);
return geterror(&handelNAND);
}
static uint32_t calcSDSize(uint8_t* csd, int type)
{
uint32_t result=0;
if(type == -1) type = csd[14] >> 6;
switch(type)
{
case 0:
{
uint32_t block_len=csd[9]&0xf;
block_len=1<<block_len;
uint32_t mult=(csd[4]>>7)|((csd[5]&3)<<1);
mult=1<<(mult+2);
result=csd[8]&3;
result=(result<<8)|csd[7];
result=(result<<2)|(csd[6]>>6);
result=(result+1)*mult*block_len/512;
}
break;
case 1:
result=csd[7]&0x3f;
result=(result<<8)|csd[6];
result=(result<<8)|csd[5];
result=(result+1)*1024;
break;
}
return result;
}
void InitSD()
{
//NAND
handelNAND.isSDHC = 0;
handelNAND.SDOPT = 0;
handelNAND.res = 0;
handelNAND.initarg = 1;
handelNAND.clk = 0x80;
handelNAND.devicenumber = 1;
//SD
handelSD.isSDHC = 0;
handelSD.SDOPT = 0;
handelSD.res = 0;
handelSD.initarg = 0;
handelSD.clk = 0x80;
handelSD.devicenumber = 0;
//sdmmc_mask16(0x100,0x800,0);
//sdmmc_mask16(0x100,0x1000,0);
//sdmmc_mask16(0x100,0x0,0x402);
//sdmmc_mask16(0xD8,0x22,0x2);
//sdmmc_mask16(0x100,0x2,0);
//sdmmc_mask16(0xD8,0x22,0);
//sdmmc_write16(0x104,0);
//sdmmc_write16(0x108,1);
//sdmmc_mask16(REG_SDRESET,1,0); //not in new Version -- nintendo's code does this
//sdmmc_mask16(REG_SDRESET,0,1); //not in new Version -- nintendo's code does this
//sdmmc_mask16(0x20,0,0x31D);
//sdmmc_mask16(0x22,0,0x837F);
//sdmmc_mask16(0xFC,0,0xDB);
//sdmmc_mask16(0xFE,0,0xDB);
////sdmmc_write16(REG_SDCLKCTL,0x20);
////sdmmc_write16(REG_SDOPT,0x40EE);
////sdmmc_mask16(0x02,0x3,0);
//sdmmc_write16(REG_SDCLKCTL,0x40);
//sdmmc_write16(REG_SDOPT,0x40EB);
//sdmmc_mask16(0x02,0x3,0);
//sdmmc_write16(REG_SDBLKLEN,0x200);
//sdmmc_write16(REG_SDSTOP,0);
*(volatile uint16_t*)0x10006100 &= 0xF7FFu; //SDDATACTL32
*(volatile uint16_t*)0x10006100 &= 0xEFFFu; //SDDATACTL32
#ifdef DATA32_SUPPORT
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
#else
*(volatile uint16_t*)0x10006100 |= 0x402u; //SDDATACTL32
#endif
*(volatile uint16_t*)0x100060D8 = (*(volatile uint16_t*)0x100060D8 & 0xFFDD) | 2;
#ifdef DATA32_SUPPORT
*(volatile uint16_t*)0x10006100 &= 0xFFFFu; //SDDATACTL32
*(volatile uint16_t*)0x100060D8 &= 0xFFDFu; //SDDATACTL
*(volatile uint16_t*)0x10006104 = 512; //SDBLKLEN32
#else
*(volatile uint16_t*)0x10006100 &= 0xFFFDu; //SDDATACTL32
*(volatile uint16_t*)0x100060D8 &= 0xFFDDu; //SDDATACTL
*(volatile uint16_t*)0x10006104 = 0; //SDBLKLEN32
#endif
*(volatile uint16_t*)0x10006108 = 1; //SDBLKCOUNT32
*(volatile uint16_t*)0x100060E0 &= 0xFFFEu; //SDRESET
*(volatile uint16_t*)0x100060E0 |= 1u; //SDRESET
*(volatile uint16_t*)0x10006020 |= TMIO_MASK_ALL; //SDIR_MASK0
*(volatile uint16_t*)0x10006022 |= TMIO_MASK_ALL>>16; //SDIR_MASK1
*(volatile uint16_t*)0x100060FC |= 0xDBu; //SDCTL_RESERVED7
*(volatile uint16_t*)0x100060FE |= 0xDBu; //SDCTL_RESERVED8
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; //SDPORTSEL
#ifdef DATA32_SUPPORT
*(volatile uint16_t*)0x10006024 = 0x20;
*(volatile uint16_t*)0x10006028 = 0x40EE;
#else
*(volatile uint16_t*)0x10006024 = 0x40; //Nintendo sets this to 0x20
*(volatile uint16_t*)0x10006028 = 0x40EB; //Nintendo sets this to 0x40EE
#endif
*(volatile uint16_t*)0x10006002 &= 0xFFFCu; ////SDPORTSEL
*(volatile uint16_t*)0x10006026 = 512; //SDBLKLEN
*(volatile uint16_t*)0x10006008 = 0; //SDSTOP
inittarget(&handelSD);
}
int Nand_Init()
{
inittarget(&handelNAND);
waitcycles(0xF000);
DEBUGPRINT(topScreen, "0x00000 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0,0);
DEBUGPRINT(topScreen, "0x10701 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
do
{
do
{
sdmmc_send_command(&handelNAND,0x10701,0x100000);
DEBUGPRINT(topScreen, "error ", handelNAND.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "ret: ", handelNAND.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "test ", 3, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
} while ( !(handelNAND.error & 1) );
}
while((handelNAND.ret[0] & 0x80000000) == 0);
DEBUGPRINT(topScreen, "0x10602 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10602,0x0);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10403 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10403,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10609 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10609,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10407 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
handelNAND.total_size = calcSDSize((uint8_t*)&handelNAND.ret[0],0);
handelNAND.clk = 1;
setckl(1);
sdmmc_send_command(&handelNAND,0x10407,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
handelNAND.SDOPT = 1;
sdmmc_send_command(&handelNAND,0x10506,0x3B70100);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10506 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10506,0x3B90100);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x1040D ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x1040D,handelNAND.initarg << 0x10);
if((handelNAND.error & 0x4))return -1;
DEBUGPRINT(topScreen, "0x10410 ", handelNAND.error, 10, 20 + 13*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelNAND,0x10410,0x200);
if((handelNAND.error & 0x4))return -1;
handelNAND.clk |= 0x200;
inittarget(&handelSD);
return 0;
}
int SD_Init()
{
inittarget(&handelSD);
//waitcycles(0x3E8);
waitcycles(0xF000);
DEBUGPRINT(topScreen, "0x00000 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0,0);
DEBUGPRINT(topScreen, "0x10408 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10408,0x1AA);
//uint32_t temp = (handelSD.ret[0] == 0x1AA) << 0x1E;
uint32_t temp = (handelSD.error & 0x1) << 0x1E;
DEBUGPRINT(topScreen, "0x10769 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 15*8, RGB(40, 40, 40), RGB(208, 208, 208));
DEBUGPRINT(topScreen, "temp: ", temp, 10, 20 + 16*8, RGB(40, 40, 40), RGB(208, 208, 208));
//int count = 0;
uint32_t temp2 = 0;
do
{
do
{
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
temp2 = 1;
} while ( !(handelSD.error & 1) );
//DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
//DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
//DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
}
while((handelSD.ret[0] & 0x80000000) == 0);
//do
//{
// sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
// sdmmc_send_command(&handelSD,0x10769,0x00FF8000 | temp);
//
// DEBUGPRINT(topScreen, "sd error ", handelSD.error, 10, 20 + 17*8, RGB(40, 40, 40), RGB(208, 208, 208));
// DEBUGPRINT(topScreen, "sd ret: ", handelSD.ret[0], 10, 20 + 18*8, RGB(40, 40, 40), RGB(208, 208, 208));
// DEBUGPRINT(topScreen, "count: ", count++, 10, 20 + 19*8, RGB(40, 40, 40), RGB(208, 208, 208));
//}
//while(!(handelSD.ret[0] & 0x80000000));
if(!((handelSD.ret[0] >> 30) & 1) || !temp)
temp2 = 0;
handelSD.isSDHC = temp2;
//handelSD.isSDHC = (handelSD.ret[0] & 0x40000000);
DEBUGPRINT(topScreen, "0x10602 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10602,0);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10403 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10403,0);
if((handelSD.error & 0x4)) return -1;
handelSD.initarg = handelSD.ret[0] >> 0x10;
DEBUGPRINT(topScreen, "0x10609 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10609,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
handelSD.total_size = calcSDSize((uint8_t*)&handelSD.ret[0],-1);
handelSD.clk = 1;
setckl(1);
DEBUGPRINT(topScreen, "0x10507 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10507,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10437 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10437,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10446 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
handelSD.SDOPT = 1;
sdmmc_send_command(&handelSD,0x10446,0x2);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x1040D ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x1040D,handelSD.initarg << 0x10);
if((handelSD.error & 0x4)) return -1;
DEBUGPRINT(topScreen, "0x10410 ", handelSD.error, 10, 20 + 14*8, RGB(40, 40, 40), RGB(208, 208, 208));
sdmmc_send_command(&handelSD,0x10410,0x200);
if((handelSD.error & 0x4)) return -1;
handelSD.clk |= 0x200;
return 0;
}
void sdmmc_sdcard_init()
{
DEBUGPRINT(topScreen, "sdmmc_sdcard_init ", handelSD.error, 10, 20 + 2*8, RGB(40, 40, 40), RGB(208, 208, 208));
InitSD();
//SD_Init2();
//Nand_Init();
Nand_Init();
DEBUGPRINT(topScreen, "nand_res ", nand_res, 10, 20 + 3*8, RGB(40, 40, 40), RGB(208, 208, 208));
SD_Init();
DEBUGPRINT(topScreen, "sd_res ", sd_res, 10, 20 + 4*8, RGB(40, 40, 40), RGB(208, 208, 208));
}

184
source/fatfs/sdmmc.h Normal file
View File

@ -0,0 +1,184 @@
#ifndef __SDMMC_H__
#define __SDMMC_H__
#define TRUE 1
#define FALSE 0
#include <stdint.h>
#define SDMMC_BASE 0x10006000
#define REG_SDCMD 0x00
#define REG_SDPORTSEL 0x02
#define REG_SDCMDARG 0x04
#define REG_SDCMDARG0 0x04
#define REG_SDCMDARG1 0x06
#define REG_SDSTOP 0x08
#define REG_SDBLKCOUNT 0x0a
#define REG_SDRESP0 0x0c
#define REG_SDRESP1 0x0e
#define REG_SDRESP2 0x10
#define REG_SDRESP3 0x12
#define REG_SDRESP4 0x14
#define REG_SDRESP5 0x16
#define REG_SDRESP6 0x18
#define REG_SDRESP7 0x1a
#define REG_SDSTATUS0 0x1c
#define REG_SDSTATUS1 0x1e
#define REG_SDIRMASK0 0x20
#define REG_SDIRMASK1 0x22
#define REG_SDCLKCTL 0x24
#define REG_SDBLKLEN 0x26
#define REG_SDOPT 0x28
#define REG_SDFIFO 0x30
#define REG_DATACTL 0xd8
#define REG_SDRESET 0xe0
#define REG_SDPROTECTED 0xf6 //bit 0 determines if sd is protected or not?
#define REG_DATACTL32 0x100
#define REG_SDBLKLEN32 0x104
#define REG_SDBLKCOUNT32 0x108
#define REG_SDFIFO32 0x10C
#define REG_CLK_AND_WAIT_CTL 0x138
#define REG_RESET_SDIO 0x1e0
#define TMIO_STAT0_CMDRESPEND 0x0001
#define TMIO_STAT0_DATAEND 0x0004
#define TMIO_STAT0_CARD_REMOVE 0x0008
#define TMIO_STAT0_CARD_INSERT 0x0010
#define TMIO_STAT0_SIGSTATE 0x0020
#define TMIO_STAT0_WRPROTECT 0x0080
#define TMIO_STAT0_CARD_REMOVE_A 0x0100
#define TMIO_STAT0_CARD_INSERT_A 0x0200
#define TMIO_STAT0_SIGSTATE_A 0x0400
#define TMIO_STAT1_CMD_IDX_ERR 0x0001
#define TMIO_STAT1_CRCFAIL 0x0002
#define TMIO_STAT1_STOPBIT_ERR 0x0004
#define TMIO_STAT1_DATATIMEOUT 0x0008
#define TMIO_STAT1_RXOVERFLOW 0x0010
#define TMIO_STAT1_TXUNDERRUN 0x0020
#define TMIO_STAT1_CMDTIMEOUT 0x0040
#define TMIO_STAT1_RXRDY 0x0100
#define TMIO_STAT1_TXRQ 0x0200
#define TMIO_STAT1_ILL_FUNC 0x2000
#define TMIO_STAT1_CMD_BUSY 0x4000
#define TMIO_STAT1_ILL_ACCESS 0x8000
//Comes from TWLSDK mongoose.tef DWARF info
#define SDMC_NORMAL 0x00000000
#define SDMC_ERR_COMMAND 0x00000001
#define SDMC_ERR_CRC 0x00000002
#define SDMC_ERR_END 0x00000004
#define SDMC_ERR_TIMEOUT 0x00000008
#define SDMC_ERR_FIFO_OVF 0x00000010
#define SDMC_ERR_FIFO_UDF 0x00000020
#define SDMC_ERR_WP 0x00000040
#define SDMC_ERR_ABORT 0x00000080
#define SDMC_ERR_FPGA_TIMEOUT 0x00000100
#define SDMC_ERR_PARAM 0x00000200
#define SDMC_ERR_R1_STATUS 0x00000800
#define SDMC_ERR_NUM_WR_SECTORS 0x00001000
#define SDMC_ERR_RESET 0x00002000
#define SDMC_ERR_ILA 0x00004000
#define SDMC_ERR_INFO_DETECT 0x00008000
#define SDMC_STAT_ERR_UNKNOWN 0x00080000
#define SDMC_STAT_ERR_CC 0x00100000
#define SDMC_STAT_ERR_ECC_FAILED 0x00200000
#define SDMC_STAT_ERR_CRC 0x00800000
#define SDMC_STAT_ERR_OTHER 0xf9c70008
#define TMIO_MASK_ALL 0x837f031d
#define TMIO_MASK_GW (TMIO_STAT1_ILL_ACCESS | TMIO_STAT1_CMDTIMEOUT | TMIO_STAT1_TXUNDERRUN | TMIO_STAT1_RXOVERFLOW | \
TMIO_STAT1_DATATIMEOUT | TMIO_STAT1_STOPBIT_ERR | TMIO_STAT1_CRCFAIL | TMIO_STAT1_CMD_IDX_ERR)
#define TMIO_MASK_READOP (TMIO_STAT1_RXRDY | TMIO_STAT1_DATAEND)
#define TMIO_MASK_WRITEOP (TMIO_STAT1_TXRQ | TMIO_STAT1_DATAEND)
#ifdef __cplusplus
extern "C" {
#endif
typedef struct mmcdevice {
uint8_t* data;
uint32_t size;
uint32_t error;
uint16_t stat0;
uint16_t stat1;
uint32_t ret[4];
uint32_t initarg;
uint32_t isSDHC;
uint32_t clk;
uint32_t SDOPT;
uint32_t devicenumber;
uint32_t total_size; //size in sectors of the device
uint32_t res;
} mmcdevice;
void sdmmc_sdcard_init();
int sdmmc_sdcard_readsector(uint32_t sector_no, uint8_t *out);
int sdmmc_sdcard_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
int sdmmc_sdcard_writesector(uint32_t sector_no, uint8_t *in);
int sdmmc_sdcard_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
int sdmmc_nand_readsectors(uint32_t sector_no, uint32_t numsectors, uint8_t *out);
int sdmmc_nand_writesectors(uint32_t sector_no, uint32_t numsectors, uint8_t *in);
mmcdevice *getMMCDevice(int drive);
void InitSD();
int Nand_Init();
int SD_Init();
#ifdef __cplusplus
};
#endif
//---------------------------------------------------------------------------------
static inline uint16_t sdmmc_read16(uint16_t reg) {
//---------------------------------------------------------------------------------
return *(volatile uint16_t*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write16(uint16_t reg, uint16_t val) {
//---------------------------------------------------------------------------------
*(volatile uint16_t*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline uint32_t sdmmc_read32(uint16_t reg) {
//---------------------------------------------------------------------------------
return *(volatile uint32_t*)(SDMMC_BASE + reg);
}
//---------------------------------------------------------------------------------
static inline void sdmmc_write32(uint16_t reg, uint32_t val) {
//---------------------------------------------------------------------------------
*(volatile uint32_t*)(SDMMC_BASE + reg) = val;
}
//---------------------------------------------------------------------------------
static inline void sdmmc_mask16(uint16_t reg, const uint16_t clear, const uint16_t set) {
//---------------------------------------------------------------------------------
uint16_t val = sdmmc_read16(reg);
val &= ~clear;
val |= set;
sdmmc_write16(reg, val);
}
static inline void setckl(uint32_t data)
{
sdmmc_mask16(REG_SDCLKCTL,0x100,0);
sdmmc_mask16(REG_SDCLKCTL,0x2FF,data&0x2FF);
sdmmc_mask16(REG_SDCLKCTL,0x0,0x100);
}
#endif

144
source/font.h Normal file
View File

@ -0,0 +1,144 @@
/*
This file was autogenerated by raw2c.
Visit http://www.devkitpro.org
*/
//---------------------------------------------------------------------------------
#ifndef _font_h_
#define _font_h_
//---------------------------------------------------------------------------------
static const unsigned char font[] = {
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x7e, 0x81, 0xa5, 0x81, 0xbd, 0x99, 0x81, 0x7e,
0x7e, 0xff, 0xdb, 0xff, 0xc3, 0xe7, 0xff, 0x7e, 0x6c, 0xfe, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00,
0x10, 0x38, 0x7c, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x3c, 0x3c, 0x18, 0xff, 0xe7, 0x18, 0x3c, 0x00,
0x10, 0x38, 0x7c, 0xfe, 0xee, 0x10, 0x38, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x00, 0x00,
0xff, 0xff, 0xe7, 0xc3, 0xc3, 0xe7, 0xff, 0xff, 0x00, 0x3c, 0x66, 0x42, 0x42, 0x66, 0x3c, 0x00,
0xff, 0xc3, 0x99, 0xbd, 0xbd, 0x99, 0xc3, 0xff, 0x0f, 0x07, 0x0f, 0x7d, 0xcc, 0xcc, 0xcc, 0x78,
0x3c, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x08, 0x0c, 0x0a, 0x0a, 0x08, 0x78, 0xf0, 0x00,
0x18, 0x14, 0x1a, 0x16, 0x72, 0xe2, 0x0e, 0x1c, 0x10, 0x54, 0x38, 0xee, 0x38, 0x54, 0x10, 0x00,
0x80, 0xe0, 0xf8, 0xfe, 0xf8, 0xe0, 0x80, 0x00, 0x02, 0x0e, 0x3e, 0xfe, 0x3e, 0x0e, 0x02, 0x00,
0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x00, 0x66, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x00,
0x7f, 0xdb, 0xdb, 0xdb, 0x7b, 0x1b, 0x1b, 0x00, 0x1c, 0x22, 0x38, 0x44, 0x44, 0x38, 0x88, 0x70,
0x00, 0x00, 0x00, 0x00, 0x7e, 0x7e, 0x7e, 0x00, 0x18, 0x3c, 0x5a, 0x18, 0x5a, 0x3c, 0x18, 0x7e,
0x18, 0x3c, 0x5a, 0x18, 0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x18, 0x5a, 0x3c, 0x18, 0x00,
0x00, 0x18, 0x0c, 0xfe, 0x0c, 0x18, 0x00, 0x00, 0x00, 0x30, 0x60, 0xfe, 0x60, 0x30, 0x00, 0x00,
0x00, 0x00, 0xc0, 0xc0, 0xc0, 0xfe, 0x00, 0x00, 0x00, 0x24, 0x42, 0xff, 0x42, 0x24, 0x00, 0x00,
0x00, 0x10, 0x38, 0x7c, 0xfe, 0xfe, 0x00, 0x00, 0x00, 0xfe, 0xfe, 0x7c, 0x38, 0x10, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x3c, 0x3c, 0x18, 0x18, 0x00, 0x18, 0x00,
0x6c, 0x24, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x6c, 0x6c, 0xfe, 0x6c, 0xfe, 0x6c, 0x6c, 0x00,
0x10, 0x7c, 0xd0, 0x7c, 0x16, 0xfc, 0x10, 0x00, 0x00, 0x66, 0xac, 0xd8, 0x36, 0x6a, 0xcc, 0x00,
0x38, 0x4c, 0x38, 0x78, 0xce, 0xcc, 0x7a, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00,
0x18, 0x30, 0x60, 0x60, 0x60, 0x30, 0x18, 0x00, 0x60, 0x30, 0x18, 0x18, 0x18, 0x30, 0x60, 0x00,
0x00, 0x66, 0x3c, 0xff, 0x3c, 0x66, 0x00, 0x00, 0x00, 0x30, 0x30, 0xfc, 0x30, 0x30, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20, 0x00, 0x00, 0x00, 0xfc, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x02, 0x06, 0x0c, 0x18, 0x30, 0x60, 0xc0, 0x00,
0x7c, 0xce, 0xde, 0xf6, 0xe6, 0xe6, 0x7c, 0x00, 0x18, 0x38, 0x78, 0x18, 0x18, 0x18, 0x7e, 0x00,
0x7c, 0xc6, 0x06, 0x1c, 0x70, 0xc6, 0xfe, 0x00, 0x7c, 0xc6, 0x06, 0x3c, 0x06, 0xc6, 0x7c, 0x00,
0x1c, 0x3c, 0x6c, 0xcc, 0xfe, 0x0c, 0x1e, 0x00, 0xfe, 0xc0, 0xfc, 0x06, 0x06, 0xc6, 0x7c, 0x00,
0x7c, 0xc6, 0xc0, 0xfc, 0xc6, 0xc6, 0x7c, 0x00, 0xfe, 0xc6, 0x0c, 0x18, 0x30, 0x30, 0x30, 0x00,
0x7c, 0xc6, 0xc6, 0x7c, 0xc6, 0xc6, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0x7e, 0x06, 0xc6, 0x7c, 0x00,
0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x30, 0x10, 0x20,
0x0c, 0x18, 0x30, 0x60, 0x30, 0x18, 0x0c, 0x00, 0x00, 0x00, 0x7e, 0x00, 0x00, 0x7e, 0x00, 0x00,
0x60, 0x30, 0x18, 0x0c, 0x18, 0x30, 0x60, 0x00, 0x78, 0xcc, 0x0c, 0x18, 0x30, 0x00, 0x30, 0x00,
0x7c, 0x82, 0x9e, 0xa6, 0x9e, 0x80, 0x7c, 0x00, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xfc, 0x00, 0x7c, 0xc6, 0xc0, 0xc0, 0xc0, 0xc6, 0x7c, 0x00,
0xfc, 0x66, 0x66, 0x66, 0x66, 0x66, 0xfc, 0x00, 0xfe, 0x62, 0x68, 0x78, 0x68, 0x62, 0xfe, 0x00,
0xfe, 0x62, 0x68, 0x78, 0x68, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc0, 0xce, 0xc6, 0x7e, 0x00,
0xc6, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0xc6, 0x00, 0x3c, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x1e, 0x0c, 0x0c, 0x0c, 0xcc, 0xcc, 0x78, 0x00, 0xe6, 0x66, 0x6c, 0x78, 0x6c, 0x66, 0xe6, 0x00,
0xf0, 0x60, 0x60, 0x60, 0x62, 0x66, 0xfe, 0x00, 0x82, 0xc6, 0xee, 0xfe, 0xd6, 0xc6, 0xc6, 0x00,
0xc6, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xfc, 0x66, 0x66, 0x7c, 0x60, 0x60, 0xf0, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xd6, 0xde, 0x7c, 0x06,
0xfc, 0x66, 0x66, 0x7c, 0x66, 0x66, 0xe6, 0x00, 0x7c, 0xc6, 0xc0, 0x7c, 0x06, 0xc6, 0x7c, 0x00,
0x7e, 0x5a, 0x5a, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0xc6, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0xc6, 0xc6, 0xd6, 0xfe, 0xee, 0xc6, 0x82, 0x00,
0xc6, 0x6c, 0x38, 0x38, 0x38, 0x6c, 0xc6, 0x00, 0x66, 0x66, 0x66, 0x3c, 0x18, 0x18, 0x3c, 0x00,
0xfe, 0xc6, 0x8c, 0x18, 0x32, 0x66, 0xfe, 0x00, 0x78, 0x60, 0x60, 0x60, 0x60, 0x60, 0x78, 0x00,
0xc0, 0x60, 0x30, 0x18, 0x0c, 0x06, 0x02, 0x00, 0x78, 0x18, 0x18, 0x18, 0x18, 0x18, 0x78, 0x00,
0x10, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff,
0x30, 0x20, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0xe0, 0x60, 0x60, 0x7c, 0x66, 0x66, 0x7c, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc0, 0xc6, 0x7c, 0x00,
0x1c, 0x0c, 0x0c, 0x7c, 0xcc, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
0x1c, 0x36, 0x30, 0x78, 0x30, 0x30, 0x78, 0x00, 0x00, 0x00, 0x76, 0xcc, 0xcc, 0x7c, 0x0c, 0x78,
0xe0, 0x60, 0x6c, 0x76, 0x66, 0x66, 0xe6, 0x00, 0x18, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x00, 0x0c, 0x00, 0x1c, 0x0c, 0x0c, 0xcc, 0x78, 0xe0, 0x60, 0x66, 0x6c, 0x78, 0x6c, 0xe6, 0x00,
0x38, 0x18, 0x18, 0x18, 0x18, 0x18, 0x3c, 0x00, 0x00, 0x00, 0xcc, 0xfe, 0xd6, 0xd6, 0xd6, 0x00,
0x00, 0x00, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x00, 0x00, 0xdc, 0x66, 0x66, 0x7c, 0x60, 0xf0, 0x00, 0x00, 0x7c, 0xcc, 0xcc, 0x7c, 0x0c, 0x1e,
0x00, 0x00, 0xde, 0x76, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0x7c, 0x06, 0x7c, 0x00,
0x10, 0x30, 0xfc, 0x30, 0x30, 0x34, 0x18, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x00, 0x00, 0xc6, 0xc6, 0x6c, 0x38, 0x10, 0x00, 0x00, 0x00, 0xc6, 0xd6, 0xd6, 0xfe, 0x6c, 0x00,
0x00, 0x00, 0xc6, 0x6c, 0x38, 0x6c, 0xc6, 0x00, 0x00, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8,
0x00, 0x00, 0xfc, 0x98, 0x30, 0x64, 0xfc, 0x00, 0x0e, 0x18, 0x18, 0x30, 0x18, 0x18, 0x0e, 0x00,
0x18, 0x18, 0x18, 0x00, 0x18, 0x18, 0x18, 0x00, 0xe0, 0x30, 0x30, 0x18, 0x30, 0x30, 0xe0, 0x00,
0x76, 0xdc, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x38, 0x6c, 0xc6, 0xc6, 0xfe, 0x00,
0x7c, 0xc6, 0xc0, 0xc0, 0xc6, 0x7c, 0x18, 0x70, 0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x0e, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x7c, 0x82, 0x38, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0xcc, 0x00, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00,
0x30, 0x30, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x00, 0x00, 0x7c, 0xc0, 0xc0, 0x7c, 0x18, 0x70,
0x7c, 0x82, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00,
0xe0, 0x10, 0x7c, 0xc6, 0xfe, 0xc0, 0x7c, 0x00, 0x66, 0x00, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x7c, 0x82, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00, 0xe0, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0xc6, 0x00, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00, 0x38, 0x38, 0x7c, 0xc6, 0xfe, 0xc6, 0xc6, 0x00,
0x0e, 0x10, 0xfe, 0x60, 0x78, 0x60, 0xfe, 0x00, 0x00, 0x00, 0x7c, 0x12, 0x7e, 0xd0, 0x7e, 0x00,
0x7e, 0xc8, 0xc8, 0xfe, 0xc8, 0xc8, 0xce, 0x00, 0x7c, 0x82, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0xe0, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0x7c, 0x82, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00, 0xe0, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0xcc, 0x00, 0xcc, 0xcc, 0xcc, 0x7c, 0x0c, 0xf8, 0xc6, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00,
0xc6, 0x00, 0xc6, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x18, 0x7c, 0xd6, 0xd0, 0xd6, 0x7c, 0x18, 0x00,
0x38, 0x6c, 0x60, 0xf0, 0x60, 0xf2, 0xdc, 0x00, 0x66, 0x3c, 0x18, 0x7e, 0x18, 0x7e, 0x18, 0x00,
0xf8, 0xcc, 0xf8, 0xc4, 0xcc, 0xde, 0xcc, 0x06, 0x0e, 0x1b, 0x18, 0x3c, 0x18, 0x18, 0xd8, 0x70,
0x0e, 0x10, 0x78, 0x0c, 0x7c, 0xcc, 0x76, 0x00, 0x0e, 0x10, 0x38, 0x18, 0x18, 0x18, 0x3c, 0x00,
0x0e, 0x10, 0x7c, 0xc6, 0xc6, 0xc6, 0x7c, 0x00, 0x0e, 0x10, 0xcc, 0xcc, 0xcc, 0xcc, 0x76, 0x00,
0x66, 0x98, 0xdc, 0x66, 0x66, 0x66, 0x66, 0x00, 0x66, 0x98, 0xe6, 0xf6, 0xde, 0xce, 0xc6, 0x00,
0x38, 0x0c, 0x3c, 0x34, 0x00, 0x7e, 0x00, 0x00, 0x38, 0x6c, 0x6c, 0x38, 0x00, 0x7c, 0x00, 0x00,
0x30, 0x00, 0x30, 0x60, 0xc6, 0xc6, 0x7c, 0x00, 0x00, 0x00, 0x00, 0xfc, 0xc0, 0xc0, 0x00, 0x00,
0x00, 0x00, 0x00, 0xfc, 0x0c, 0x0c, 0x00, 0x00, 0xc0, 0xc8, 0xd0, 0xfe, 0x46, 0x8c, 0x1e, 0x00,
0xc0, 0xc8, 0xd0, 0xec, 0x5c, 0xbe, 0x0c, 0x00, 0x18, 0x00, 0x18, 0x18, 0x3c, 0x3c, 0x18, 0x00,
0x00, 0x36, 0x6c, 0xd8, 0x6c, 0x36, 0x00, 0x00, 0x00, 0xd8, 0x6c, 0x36, 0x6c, 0xd8, 0x00, 0x00,
0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x22, 0x88, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa, 0x55, 0xaa,
0xdb, 0x77, 0xdb, 0xee, 0xdb, 0x77, 0xdb, 0xee, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18,
0x36, 0x36, 0x36, 0x36, 0xf6, 0x36, 0x36, 0x36, 0x00, 0x00, 0x00, 0x00, 0xfe, 0x36, 0x36, 0x36,
0x00, 0x00, 0xf8, 0x18, 0xf8, 0x18, 0x18, 0x18, 0x36, 0x36, 0xf6, 0x06, 0xf6, 0x36, 0x36, 0x36,
0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x00, 0x00, 0xfe, 0x06, 0xf6, 0x36, 0x36, 0x36,
0x36, 0x36, 0xf6, 0x06, 0xfe, 0x00, 0x00, 0x00, 0x36, 0x36, 0x36, 0x36, 0xfe, 0x00, 0x00, 0x00,
0x18, 0x18, 0xf8, 0x18, 0xf8, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xf8, 0x18, 0x18, 0x18,
0x18, 0x18, 0x18, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x1f, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0x00, 0x00, 0x18, 0x18, 0x18, 0x18, 0xff, 0x18, 0x18, 0x18,
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18, 0x36, 0x36, 0x36, 0x36, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x30, 0x37, 0x36, 0x36, 0x36,
0x36, 0x36, 0xf7, 0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xf7, 0x36, 0x36, 0x36,
0x36, 0x36, 0x37, 0x30, 0x37, 0x36, 0x36, 0x36, 0x00, 0x00, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x36, 0x36, 0xf7, 0x00, 0xf7, 0x36, 0x36, 0x36, 0x18, 0x18, 0xff, 0x00, 0xff, 0x00, 0x00, 0x00,
0x36, 0x36, 0x36, 0x36, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0x00, 0xff, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0xff, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x3f, 0x00, 0x00, 0x00,
0x18, 0x18, 0x1f, 0x18, 0x1f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x1f, 0x18, 0x18, 0x18,
0x00, 0x00, 0x00, 0x00, 0x3f, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0x36, 0xff, 0x36, 0x36, 0x36,
0x18, 0x18, 0xff, 0x18, 0xff, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xf8, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x1f, 0x18, 0x18, 0x18, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xff, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0, 0xf0,
0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0x0f, 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x74, 0xcc, 0xc8, 0xdc, 0x76, 0x00, 0x78, 0xcc, 0xd8, 0xcc, 0xc6, 0xc6, 0xdc, 0x40,
0xfe, 0x62, 0x60, 0x60, 0x60, 0x60, 0xf0, 0x00, 0x00, 0x02, 0x7e, 0xec, 0x6c, 0x6c, 0x48, 0x00,
0xfe, 0x62, 0x30, 0x18, 0x30, 0x62, 0xfe, 0x00, 0x00, 0x00, 0x7e, 0xd0, 0xc8, 0xc8, 0x70, 0x00,
0x00, 0x00, 0xcc, 0xcc, 0xcc, 0xcc, 0xf8, 0x80, 0x00, 0x00, 0x7e, 0xd8, 0x18, 0x18, 0x10, 0x00,
0x38, 0x10, 0x7c, 0xd6, 0xd6, 0x7c, 0x10, 0x38, 0x7c, 0xc6, 0xc6, 0xfe, 0xc6, 0xc6, 0x7c, 0x00,
0x7c, 0xc6, 0xc6, 0xc6, 0x6c, 0x28, 0xee, 0x00, 0x3c, 0x22, 0x18, 0x7c, 0xcc, 0xcc, 0x78, 0x00,
0x00, 0x00, 0x66, 0x99, 0x99, 0x66, 0x00, 0x00, 0x00, 0x06, 0x7c, 0x9e, 0xf2, 0x7c, 0xc0, 0x00,
0x00, 0x00, 0x7c, 0xc0, 0xf8, 0xc0, 0x7c, 0x00, 0x00, 0x7c, 0xc6, 0xc6, 0xc6, 0xc6, 0xc6, 0x00,
0x00, 0xfe, 0x00, 0xfe, 0x00, 0xfe, 0x00, 0x00, 0x18, 0x18, 0x7e, 0x18, 0x18, 0x00, 0x7e, 0x00,
0x30, 0x18, 0x0c, 0x18, 0x30, 0x00, 0x7c, 0x00, 0x18, 0x30, 0x60, 0x30, 0x18, 0x00, 0x7c, 0x00,
0x0e, 0x1b, 0x1b, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0x18, 0xd8, 0xd8, 0x70,
0x00, 0x18, 0x00, 0x7e, 0x00, 0x18, 0x00, 0x00, 0x00, 0x76, 0xdc, 0x00, 0x76, 0xdc, 0x00, 0x00,
0x38, 0x6c, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x18, 0x18, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x18, 0x00, 0x00, 0x00, 0x0f, 0x0c, 0x0c, 0x0c, 0xec, 0x6c, 0x3c, 0x00,
0xd8, 0x6c, 0x6c, 0x6c, 0x00, 0x00, 0x00, 0x00, 0xf0, 0x30, 0xc0, 0xf0, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x3c, 0x3c, 0x3c, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
};
const int font_size = sizeof(font);
//---------------------------------------------------------------------------------
#endif //_font_h_
//---------------------------------------------------------------------------------

329
source/fs.c Normal file
View File

@ -0,0 +1,329 @@
#include "fs.h"
#include "draw.h"
#include "fatfs/ff.h"
static FATFS fs;
static FIL file;
static DIR dir;
bool InitFS()
{
#ifndef EXEC_GATEWAY
// TODO: Magic?
*(u32*)0x10000020 = 0;
*(u32*)0x10000020 = 0x340;
#endif
bool ret = (f_mount(&fs, "0:", 0) == FR_OK);
#ifdef WORK_DIR
f_chdir(WORK_DIR);
#endif
return ret;
}
void DeinitFS()
{
LogWrite(NULL);
f_mount(NULL, "0:", 1);
}
bool FileOpen(const char* path)
{
unsigned flags = FA_READ | FA_WRITE | FA_OPEN_EXISTING;
if (*path == '/')
path++;
bool ret = (f_open(&file, path, flags) == FR_OK);
#ifdef WORK_DIR
f_chdir("/"); // temporarily change the current directory
if (!ret) ret = (f_open(&file, path, flags) == FR_OK);
f_chdir(WORK_DIR);
#endif
f_lseek(&file, 0);
f_sync(&file);
return ret;
}
bool DebugFileOpen(const char* path)
{
Debug("Opening %s ...", path);
if (!FileOpen(path)) {
Debug("Could not open %s!", path);
return false;
}
return true;
}
bool FileCreate(const char* path, bool truncate)
{
unsigned flags = FA_READ | FA_WRITE;
flags |= truncate ? FA_CREATE_ALWAYS : FA_OPEN_ALWAYS;
if (*path == '/')
path++;
bool ret = (f_open(&file, path, flags) == FR_OK);
f_lseek(&file, 0);
f_sync(&file);
return ret;
}
bool DebugFileCreate(const char* path, bool truncate) {
Debug("Creating %s ...", path);
if (!FileCreate(path, truncate)) {
Debug("Could not create %s!", path);
return false;
}
return true;
}
size_t FileCopyTo(const char* dest, void* buf, size_t bufsize)
{
unsigned flags = FA_READ | FA_WRITE | FA_CREATE_ALWAYS;
size_t fsize = f_size(&file);
size_t result = fsize;
FIL dfile;
// make sure the containing folder exists
char tmp[256] = { 0 };
strncpy(tmp, dest, sizeof(tmp) - 1);
for (char* p = tmp + 1; *p; p++) {
if (*p == '/') {
char s = *p;
*p = 0;
f_mkdir(tmp);
*p = s;
}
}
// do the actual copying
if (f_open(&dfile, dest, flags) != FR_OK)
return 0;
f_lseek(&dfile, 0);
f_sync(&dfile);
f_lseek(&file, 0);
f_sync(&file);
for (size_t pos = 0; pos < fsize; pos += bufsize) {
UINT bytes_read = 0;
UINT bytes_written = 0;
ShowProgress(pos, fsize);
f_read(&file, buf, bufsize, &bytes_read);
f_write(&dfile, buf, bytes_read, &bytes_written);
if (bytes_read != bytes_written) {
result = 0;
}
}
ShowProgress(0, 0);
f_close(&dfile);
return result;
}
size_t FileRead(void* buf, size_t size, size_t foffset)
{
UINT bytes_read = 0;
f_lseek(&file, foffset);
f_read(&file, buf, size, &bytes_read);
return bytes_read;
}
bool DebugFileRead(void* buf, size_t size, size_t foffset) {
size_t bytesRead = FileRead(buf, size, foffset);
if(bytesRead != size) {
Debug("ERROR, file is too small!");
return false;
}
return true;
}
size_t FileWrite(void* buf, size_t size, size_t foffset)
{
UINT bytes_written = 0;
f_lseek(&file, foffset);
f_write(&file, buf, size, &bytes_written);
f_sync(&file);
return bytes_written;
}
bool DebugFileWrite(void* buf, size_t size, size_t foffset)
{
size_t bytesWritten = FileWrite(buf, size, foffset);
if(bytesWritten != size) {
Debug("ERROR, SD card may be full!");
return false;
}
return true;
}
size_t FileGetSize()
{
return f_size(&file);
}
void FileClose()
{
f_close(&file);
}
bool DirMake(const char* path)
{
FRESULT res = f_mkdir(path);
bool ret = (res == FR_OK) || (res == FR_EXIST);
return ret;
}
bool DebugDirMake(const char* path)
{
Debug("Creating dir %s ...", path);
if (!DirMake(path)) {
Debug("Could not create %s!", path);
return false;
}
return true;
}
bool DirOpen(const char* path)
{
return (f_opendir(&dir, path) == FR_OK);
}
bool DebugDirOpen(const char* path)
{
Debug("Opening %s ...", path);
if (!DirOpen(path)) {
Debug("Could not open %s!", path);
return false;
}
return true;
}
bool DirRead(char* fname, int fsize)
{
FILINFO fno;
fno.lfname = fname;
fno.lfsize = fsize;
bool ret = false;
while (f_readdir(&dir, &fno) == FR_OK) {
if (fno.fname[0] == 0) break;
if ((fno.fname[0] != '.') && !(fno.fattrib & AM_DIR)) {
if (fname[0] == 0)
strcpy(fname, fno.fname);
ret = true;
break;
}
}
return ret;
}
void DirClose()
{
f_closedir(&dir);
}
bool GetFileListWorker(char** list, int* lsize, char* fpath, int fsize, bool recursive, bool inc_files, bool inc_dirs)
{
DIR pdir;
FILINFO fno;
char* fname = fpath + strnlen(fpath, fsize - 1);
bool ret = false;
if (f_opendir(&pdir, fpath) != FR_OK)
return false;
(fname++)[0] = '/';
fno.lfname = fname;
fno.lfsize = fsize - (fname - fpath);
while (f_readdir(&pdir, &fno) == FR_OK) {
if ((strncmp(fno.fname, ".", 2) == 0) || (strncmp(fno.fname, "..", 3) == 0))
continue; // filter out virtual entries
if (fname[0] == 0)
strncpy(fname, fno.fname, (fsize - 1) - (fname - fpath));
if (fno.fname[0] == 0) {
ret = true;
break;
} else if ((inc_files && !(fno.fattrib & AM_DIR)) || (inc_dirs && (fno.fattrib & AM_DIR))) {
snprintf(*list, *lsize, "%s\n", fpath);
for(;(*list)[0] != '\0' && (*lsize) > 1; (*list)++, (*lsize)--);
if ((*lsize) <= 1) break;
}
if (recursive && (fno.fattrib & AM_DIR)) {
if (!GetFileListWorker(list, lsize, fpath, fsize, recursive, inc_files, inc_dirs))
break;
}
}
f_closedir(&pdir);
return ret;
}
bool GetFileList(const char* path, char* list, int lsize, bool recursive, bool inc_files, bool inc_dirs)
{
char fpath[256]; // 256 is the maximum length of a full path
strncpy(fpath, path, 256);
return GetFileListWorker(&list, &lsize, fpath, 256, recursive, inc_files, inc_dirs);
}
size_t LogWrite(const char* text)
{
#ifdef LOG_FILE
static FIL lfile;
static bool lready = false;
static size_t lstart = 0;
if ((text == NULL) && lready) {
f_sync(&lfile);
f_close(&lfile);
lready = false;
return lstart; // return the current log start
} else if (text == NULL) {
return 0;
}
if (!lready) {
unsigned flags = FA_READ | FA_WRITE | FA_OPEN_ALWAYS;
lready = (f_open(&lfile, LOG_FILE, flags) == FR_OK);
if (!lready) return 0;
lstart = f_size(&lfile);
f_lseek(&lfile, lstart);
f_sync(&lfile);
}
const char newline = '\n';
UINT bytes_written;
UINT tlen = strnlen(text, 128);
f_write(&lfile, text, tlen, &bytes_written);
if (bytes_written != tlen) return 0;
f_write(&lfile, &newline, 1, &bytes_written);
if (bytes_written != 1) return 0;
return f_size(&lfile); // return the current position
#else
return 0;
#endif
}
static uint64_t ClustersToBytes(FATFS* fs, DWORD clusters)
{
uint64_t sectors = clusters * fs->csize;
#if _MAX_SS != _MIN_SS
return sectors * fs->ssize;
#else
return sectors * _MAX_SS;
#endif
}
uint64_t RemainingStorageSpace()
{
DWORD free_clusters;
FATFS *fs2;
FRESULT res = f_getfree("0:", &free_clusters, &fs2);
if (res)
return -1;
return ClustersToBytes(&fs, free_clusters);
}
uint64_t TotalStorageSpace()
{
return ClustersToBytes(&fs, fs.n_fatent - 2);
}

57
source/fs.h Normal file
View File

@ -0,0 +1,57 @@
#pragma once
#include "common.h"
bool InitFS();
void DeinitFS();
/** Opens existing files */
bool FileOpen(const char* path);
bool DebugFileOpen(const char* path);
/** Opens new files (and creates them if they don't already exist) */
bool FileCreate(const char* path, bool truncate);
bool DebugFileCreate(const char* path, bool truncate);
/** Copies currently opened file to destination (must provide buffer) */
size_t FileCopyTo(const char* dest, void* buf, size_t bufsize);
/** Reads contents of the opened file */
size_t FileRead(void* buf, size_t size, size_t foffset);
bool DebugFileRead(void* buf, size_t size, size_t foffset);
/** Writes to the opened file */
size_t FileWrite(void* buf, size_t size, size_t foffset);
bool DebugFileWrite(void* buf, size_t size, size_t foffset);
/** Gets the size of the opened file */
size_t FileGetSize();
/** Creates a directory */
bool DirMake(const char* path);
bool DebugDirMake(const char* path);
/** Opens an existing directory */
bool DirOpen(const char* path);
bool DebugDirOpen(const char* path);
/** Reads next file name to fname from opened directory,
returns false if all files in directory are processed.
fname needs to be allocated to fsize bytes minimum. */
bool DirRead(char* fname, int fsize);
/** Get list of files under a given path **/
bool GetFileList(const char* path, char* list, int lsize, bool recursive, bool inc_files, bool inc_dirs);
/** Writes text to a constantly open log file **/
size_t LogWrite(const char* text);
/** Gets remaining space on SD card in bytes */
uint64_t RemainingStorageSpace();
/** Gets total space on SD card in bytes */
uint64_t TotalStorageSpace();
void FileClose();
void DirClose();

10
source/hid.c Normal file
View File

@ -0,0 +1,10 @@
#include "hid.h"
u32 InputWait() {
u32 pad_state_old = HID_STATE;
while (true) {
u32 pad_state = HID_STATE;
if (pad_state ^ pad_state_old)
return ~pad_state;
}
}

21
source/hid.h Normal file
View File

@ -0,0 +1,21 @@
#pragma once
#include "common.h"
#define HID_STATE (*(volatile u32*)0x10146000)
#define BUTTON_A (1 << 0)
#define BUTTON_B (1 << 1)
#define BUTTON_SELECT (1 << 2)
#define BUTTON_START (1 << 3)
#define BUTTON_RIGHT (1 << 4)
#define BUTTON_LEFT (1 << 5)
#define BUTTON_UP (1 << 6)
#define BUTTON_DOWN (1 << 7)
#define BUTTON_R1 (1 << 8)
#define BUTTON_L1 (1 << 9)
#define BUTTON_X (1 << 10)
#define BUTTON_Y (1 << 11)
#define BUTTON_ANY 0x00000FFF
u32 InputWait();

150
source/i2c.c Normal file
View File

@ -0,0 +1,150 @@
#include "i2c.h"
#include "draw.h"
//-----------------------------------------------------------------------------
static const struct { u8 bus_id, reg_addr; } dev_data[] = {
{0, 0x4A}, {0, 0x7A}, {0, 0x78},
{1, 0x4A}, {1, 0x78}, {1, 0x2C},
{1, 0x2E}, {1, 0x40}, {1, 0x44},
{2, 0xD6}, {2, 0xD0}, {2, 0xD2},
{2, 0xA4}, {2, 0x9A}, {2, 0xA0},
};
const inline u8 i2cGetDeviceBusId(u8 device_id) {
return dev_data[device_id].bus_id;
}
const inline u8 i2cGetDeviceRegAddr(u8 device_id) {
return dev_data[device_id].reg_addr;
}
//-----------------------------------------------------------------------------
static vu8* const reg_data_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C2_REG_OFF + I2C_REG_DATA),
(vu8*)(I2C3_REG_OFF + I2C_REG_DATA),
};
inline vu8* const i2cGetDataReg(u8 bus_id) {
return reg_data_addrs[bus_id];
}
//-----------------------------------------------------------------------------
static vu8* const reg_cnt_addrs[] = {
(vu8*)(I2C1_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C2_REG_OFF + I2C_REG_CNT),
(vu8*)(I2C3_REG_OFF + I2C_REG_CNT),
};
inline vu8* const i2cGetCntReg(u8 bus_id) {
return reg_cnt_addrs[bus_id];
}
//-----------------------------------------------------------------------------
inline void i2cWaitBusy(u8 bus_id) {
while (*i2cGetCntReg(bus_id) & 0x80);
}
inline bool i2cGetResult(u8 bus_id) {
i2cWaitBusy(bus_id);
return (*i2cGetCntReg(bus_id) >> 4) & 1;
}
void i2cStop(u8 bus_id, u8 arg0) {
*i2cGetCntReg(bus_id) = (arg0 << 5) | 0xC0;
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
}
//-----------------------------------------------------------------------------
bool i2cSelectDevice(u8 bus_id, u8 dev_reg) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = dev_reg;
*i2cGetCntReg(bus_id) = 0xC2;
return i2cGetResult(bus_id);
}
bool i2cSelectRegister(u8 bus_id, u8 reg) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = reg;
*i2cGetCntReg(bus_id) = 0xC0;
return i2cGetResult(bus_id);
}
//-----------------------------------------------------------------------------
u8 i2cReadRegister(u8 dev_id, u8 reg) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for (size_t i = 0; i < 8; i++) {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
if (i2cSelectDevice(bus_id, dev_addr | 1)) {
i2cWaitBusy(bus_id);
i2cStop(bus_id, 1);
i2cWaitBusy(bus_id);
return *i2cGetDataReg(bus_id);
}
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
return 0xff;
}
bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
size_t j = 0;
while (!i2cSelectDevice(bus_id, dev_addr)
|| !i2cSelectRegister(bus_id, reg)
|| !i2cSelectDevice(bus_id, dev_addr | 1))
{
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
if (++j >= 8)
return false;
}
if (buf_size != 1) {
for (int i = 0; i < buf_size - 1; i++) {
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xF0;
i2cWaitBusy(bus_id);
buffer[i] = *i2cGetDataReg(bus_id);
}
}
i2cWaitBusy(bus_id);
*i2cGetCntReg(bus_id) = 0xE1;
i2cWaitBusy(bus_id);
*buffer = *i2cGetDataReg(bus_id);
return true;
}
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data) {
u8 bus_id = i2cGetDeviceBusId(dev_id);
u8 dev_addr = i2cGetDeviceRegAddr(dev_id);
for (int i = 0; i < 8; i++) {
if (i2cSelectDevice(bus_id, dev_addr) && i2cSelectRegister(bus_id, reg)) {
i2cWaitBusy(bus_id);
*i2cGetDataReg(bus_id) = data;
*i2cGetCntReg(bus_id) = 0xC1;
i2cStop(bus_id, 0);
if (i2cGetResult(bus_id))
return true;
}
*i2cGetCntReg(bus_id) = 0xC5;
i2cWaitBusy(bus_id);
}
return false;
}

35
source/i2c.h Normal file
View File

@ -0,0 +1,35 @@
#pragma once
#include "common.h"
#define I2C1_REG_OFF 0x10161000
#define I2C2_REG_OFF 0x10144000
#define I2C3_REG_OFF 0x10148000
#define I2C_REG_DATA 0
#define I2C_REG_CNT 1
#define I2C_REG_CNTEX 2
#define I2C_REG_SCL 4
#define I2C_DEV_MCU 3
#define I2C_DEV_GYRO 10
#define I2C_DEV_IR 13
const u8 i2cGetDeviceBusId(u8 device_id);
const u8 i2cGetDeviceRegAddr(u8 device_id);
vu8* const i2cGetDataReg(u8 bus_id);
vu8* const i2cGetCntReg(u8 bus_id);
void i2cWaitBusy(u8 bus_id);
bool i2cGetResult(u8 bus_id);
u8 i2cGetData(u8 bus_id);
void i2cStop(u8 bus_id, u8 arg0);
bool i2cSelectDevice(u8 bus_id, u8 dev_reg);
bool i2cSelectRegister(u8 bus_id, u8 reg);
u8 i2cReadRegister(u8 dev_id, u8 reg);
bool i2cWriteRegister(u8 dev_id, u8 reg, u8 data);
bool i2cReadRegisterBuffer(unsigned int dev_id, int reg, u8* buffer, size_t buf_size);

215
source/main.c Normal file
View File

@ -0,0 +1,215 @@
#include "common.h"
#include "draw.h"
#include "fs.h"
#include "menu.h"
#include "i2c.h"
#include "decryptor/game.h"
#include "decryptor/nand.h"
#include "decryptor/nandfat.h"
#include "decryptor/titlekey.h"
#define SUBMENU_START 5
MenuInfo menu[] =
{
{
"XORpad Generator Options", 7,
{
{ "NCCH Padgen", &NcchPadgen, 0 },
{ "SD Padgen (SDinfo.bin)", &SdPadgen, 0 },
{ "SD Padgen (SysNAND dir)", &SdPadgenDirect, 0 },
{ "SD Padgen (EmuNAND dir)", &SdPadgenDirect, N_EMUNAND },
{ "CTRNAND Padgen", &CtrNandPadgen, 0 },
{ "TWLNAND Padgen", &TwlNandPadgen, 0 },
{ "FIRM0FIRM1 Padgen", &Firm0Firm1Padgen, 0 }
}
},
{
"Titlekey Decrypt Options", 3,
{
{ "Titlekey Decrypt (file)", &DecryptTitlekeysFile, 0 },
{ "Titlekey Decrypt (SysNAND)", &DecryptTitlekeysNand, 0 },
{ "Titlekey Decrypt (EmuNAND)", &DecryptTitlekeysNand, N_EMUNAND }
}
},
{
"SysNAND Options", 8,
{
{ "NAND Backup", &DumpNand, 0 },
{ "NAND Restore", &RestoreNand, N_NANDWRITE },
{ "Partition Dump...", NULL, SUBMENU_START + 0 },
{ "Partition Inject...", NULL, SUBMENU_START + 2 },
{ "File Dump...", NULL, SUBMENU_START + 4 },
{ "File Inject...", NULL, SUBMENU_START + 6 },
{ "Health&Safety Dump", &DumpHealthAndSafety, 0 },
{ "Health&Safety Inject", &InjectHealthAndSafety, N_NANDWRITE }
}
},
{
"EmuNAND Options", 9,
{
{ "EmuNAND Backup", &DumpNand, N_EMUNAND },
{ "EmuNAND Restore", &RestoreNand, N_NANDWRITE | N_EMUNAND | N_FORCENAND },
{ "Partition Dump...", NULL, SUBMENU_START + 1 },
{ "Partition Inject...", NULL, SUBMENU_START + 3 },
{ "File Dump...", NULL, SUBMENU_START + 5 },
{ "File Inject...", NULL, SUBMENU_START + 7 },
{ "Health&Safety Dump", &DumpHealthAndSafety, N_EMUNAND },
{ "Health&Safety Inject", &InjectHealthAndSafety, N_NANDWRITE | N_EMUNAND },
{ "Update SeedDB", &UpdateSeedDb, N_EMUNAND }
}
},
{
"Game Decryptor Options", 10,
{
{ "NCCH/NCSD Decryptor", &CryptGameFiles, GC_NCCH_PROCESS },
{ "NCCH/NCSD Encryptor", &CryptGameFiles, GC_NCCH_PROCESS | GC_NCCH_ENCRYPT },
{ "CIA Decryptor (shallow)", &CryptGameFiles, GC_CIA_PROCESS },
{ "CIA Decryptor (deep)", &CryptGameFiles, GC_CIA_PROCESS | GC_CIA_DEEP },
{ "CIA Decryptor (CXI only)", &CryptGameFiles, GC_CIA_PROCESS | GC_CIA_DEEP | GC_CXI_ONLY },
{ "CIA Encryptor (NCCH)", &CryptGameFiles, GC_CIA_PROCESS | GC_NCCH_ENCRYPT },
{ "CIA Encryptor (CXI only)", &CryptGameFiles, GC_CIA_PROCESS | GC_NCCH_ENCRYPT | GC_CXI_ONLY },
{ "SD Decryptor/Encryptor", &CryptSdFiles, 0 },
{ "SD Decryptor (SysNAND dir)", &DecryptSdFilesDirect, 0 },
{ "SD Decryptor (EmuNAND dir)", &DecryptSdFilesDirect, N_EMUNAND }
}
},
// everything below is not contained in the main menu
{
"Partition Dump... (SysNAND)", 6, // ID 0
{
{ "Dump TWLN Partition", &DecryptNandPartition, P_TWLN },
{ "Dump TWLP Partition", &DecryptNandPartition, P_TWLP },
{ "Dump AGBSAVE Partition", &DecryptNandPartition, P_AGBSAVE },
{ "Dump FIRM0 Partition", &DecryptNandPartition, P_FIRM0 },
{ "Dump FIRM1 Partition", &DecryptNandPartition, P_FIRM1 },
{ "Dump CTRNAND Partition", &DecryptNandPartition, P_CTRNAND }
}
},
{
"Partition Dump...(EmuNAND)", 6, // ID 1
{
{ "Dump TWLN Partition", &DecryptNandPartition, N_EMUNAND | P_TWLN },
{ "Dump TWLP Partition", &DecryptNandPartition, N_EMUNAND | P_TWLP },
{ "Dump AGBSAVE Partition", &DecryptNandPartition, N_EMUNAND | P_AGBSAVE },
{ "Dump FIRM0 Partition", &DecryptNandPartition, N_EMUNAND | P_FIRM0 },
{ "Dump FIRM1 Partition", &DecryptNandPartition, N_EMUNAND | P_FIRM1 },
{ "Dump CTRNAND Partition", &DecryptNandPartition, N_EMUNAND | P_CTRNAND }
}
},
{
"Partition Inject... (SysNAND)", 6, // ID 2
{
{ "Inject TWLN Partition", &InjectNandPartition, N_NANDWRITE | P_TWLN },
{ "Inject TWLP Partition", &InjectNandPartition, N_NANDWRITE | P_TWLP },
{ "Inject AGBSAVE Partition", &InjectNandPartition, N_NANDWRITE | P_AGBSAVE },
{ "Inject FIRM0 Partition", &InjectNandPartition, N_NANDWRITE | P_FIRM0 },
{ "Inject FIRM1 Partition", &InjectNandPartition, N_NANDWRITE | P_FIRM1 },
{ "Inject CTRNAND Partition", &InjectNandPartition, N_NANDWRITE | P_CTRNAND }
}
},
{
"Partition Inject... (EmuNAND)", 6, // ID 3
{
{ "Inject TWLN Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_TWLN },
{ "Inject TWLP Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_TWLP },
{ "Inject AGBSAVE Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_AGBSAVE },
{ "Inject FIRM0 Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_FIRM0 },
{ "Inject FIRM1 Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_FIRM1 },
{ "Inject CTRNAND Partition", &InjectNandPartition, N_NANDWRITE | N_EMUNAND | P_CTRNAND }
}
},
{
"File Dump... (SysNAND)", 10, // ID 4
{
{ "Dump ticket.db", &DumpFile, F_TICKET },
{ "Dump title.db", &DumpFile, F_TITLE },
{ "Dump import.db", &DumpFile, F_IMPORT },
{ "Dump certs.db", &DumpFile, F_CERTS },
{ "Dump SecureInfo_A", &DumpFile, F_SECUREINFO },
{ "Dump LocalFriendCodeSeed_B", &DumpFile, F_LOCALFRIEND },
{ "Dump rand_seed", &DumpFile, F_RANDSEED },
{ "Dump movable.sed", &DumpFile, F_MOVABLE },
{ "Dump nagsave.bin", &DumpFile, F_NAGSAVE },
{ "Dump nnidsave.bin", &DumpFile, F_NNIDSAVE }
}
},
{
"File Dump... (EmuNAND)", 11, // ID 5
{
{ "Dump ticket.db", &DumpFile, N_EMUNAND | F_TICKET },
{ "Dump title.db", &DumpFile, N_EMUNAND | F_TITLE },
{ "Dump import.db", &DumpFile, N_EMUNAND | F_IMPORT },
{ "Dump certs.db", &DumpFile, N_EMUNAND | F_CERTS },
{ "Dump SecureInfo_A", &DumpFile, N_EMUNAND | F_SECUREINFO },
{ "Dump LocalFriendCodeSeed_B", &DumpFile, N_EMUNAND | F_LOCALFRIEND },
{ "Dump rand_seed", &DumpFile, N_EMUNAND | F_RANDSEED },
{ "Dump movable.sed", &DumpFile, N_EMUNAND | F_MOVABLE },
{ "Dump seedsave.bin", &DumpFile, N_EMUNAND | F_SEEDSAVE },
{ "Dump nagsave.bin", &DumpFile, N_EMUNAND | F_NAGSAVE },
{ "Dump nnidsave.bin", &DumpFile, N_EMUNAND | F_NNIDSAVE }
}
},
{
"File Inject... (SysNAND)", 10, // ID 6
{
{ "Inject ticket.db", &InjectFile, N_NANDWRITE | F_TICKET },
{ "Inject title.db", &InjectFile, N_NANDWRITE | F_TITLE },
{ "Inject import.db", &InjectFile, N_NANDWRITE | F_IMPORT },
{ "Inject certs.db", &InjectFile, N_NANDWRITE | F_CERTS },
{ "Inject SecureInfo_A", &InjectFile, N_NANDWRITE | F_SECUREINFO },
{ "Inject LocalFriendCodeSeed_B", &InjectFile, N_NANDWRITE | F_LOCALFRIEND },
{ "Inject rand_seed", &InjectFile, N_NANDWRITE | F_RANDSEED },
{ "Inject movable.sed", &InjectFile, N_NANDWRITE | F_MOVABLE },
{ "Inject nagsave.bin", &InjectFile, N_NANDWRITE | F_NAGSAVE },
{ "Inject nnidsave.bin", &InjectFile, N_NANDWRITE | F_NNIDSAVE }
}
},
{
"File Inject... (EmuNAND)", 11, // ID 7
{
{ "Inject ticket.db", &InjectFile, N_NANDWRITE | N_EMUNAND | F_TICKET },
{ "Inject title.db", &InjectFile, N_NANDWRITE | N_EMUNAND | F_TITLE },
{ "Inject import.db", &InjectFile, N_NANDWRITE | N_EMUNAND | F_IMPORT },
{ "Inject certs.db", &InjectFile, N_NANDWRITE | N_EMUNAND | F_CERTS },
{ "Inject SecureInfo_A", &InjectFile, N_NANDWRITE | N_EMUNAND | F_SECUREINFO },
{ "Inject LocalFriendCodeSeed_B", &InjectFile, N_NANDWRITE | N_EMUNAND | F_LOCALFRIEND },
{ "Inject rand_seed", &InjectFile, N_NANDWRITE | N_EMUNAND | F_RANDSEED },
{ "Inject movable.sed", &InjectFile, N_NANDWRITE | N_EMUNAND | F_MOVABLE },
{ "Inject seedsave.bin", &InjectFile, N_NANDWRITE | N_EMUNAND | F_SEEDSAVE },
{ "Inject nagsave.bin", &InjectFile, N_NANDWRITE | N_EMUNAND | F_NAGSAVE },
{ "Inject nnidsave.bin", &InjectFile, N_NANDWRITE | N_EMUNAND | F_NNIDSAVE }
}
},
{
NULL, 0, {}, // empty menu to signal end
}
};
void Reboot()
{
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 2);
while(true);
}
void PowerOff()
{
i2cWriteRegister(I2C_DEV_MCU, 0x20, 1 << 0);
while (true);
}
int main()
{
ClearScreenFull(true, true);
InitFS();
u32 menu_exit = ProcessMenu(menu, SUBMENU_START);
DeinitFS();
(menu_exit == MENU_EXIT_REBOOT) ? Reboot() : PowerOff();
return 0;
}

15
source/platform.c Normal file
View File

@ -0,0 +1,15 @@
#include "common.h"
#include "platform.h"
#define CONFIG_PLATFORM_REG ((volatile u32*)0x10140FFC)
Platform GetUnitPlatform()
{
switch (*CONFIG_PLATFORM_REG) {
case 7:
return PLATFORM_N3DS;
case 1:
default:
return PLATFORM_3DS;
}
}

8
source/platform.h Normal file
View File

@ -0,0 +1,8 @@
#pragma once
typedef enum {
PLATFORM_3DS,
PLATFORM_N3DS,
} Platform;
Platform GetUnitPlatform();