diff --git a/examples/graphics/gpu/Makefile b/examples/graphics/gpu/Makefile new file mode 100644 index 0000000..bce05ec --- /dev/null +++ b/examples/graphics/gpu/Makefile @@ -0,0 +1,7 @@ +SUBDIRS:= `ls | egrep -v '^(CVS)$$'` +all: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i || { exit 1;} fi; done; +clean: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i clean || { exit 1;} fi; done; +install: + @for i in $(SUBDIRS); do if test -e $$i/Makefile ; then $(MAKE) -C $$i install || { exit 1;} fi; done; diff --git a/examples/graphics/gpu/geoshader/Makefile b/examples/graphics/gpu/geoshader/Makefile index 1e4e9ef..3b72824 100644 --- a/examples/graphics/gpu/geoshader/Makefile +++ b/examples/graphics/gpu/geoshader/Makefile @@ -164,7 +164,7 @@ $(OUTPUT).elf : $(OFILES) @echo $(notdir $<) $(eval CURBIN := $(patsubst %.pica,%.shbin,$(notdir $<))) $(eval CURH := $(patsubst %.pica,%.psh.h,$(notdir $<))) - @picasso $(CURBIN) $< $(CURH) + @picasso -h $(CURH) -o $(CURBIN) $< @bin2s $(CURBIN) | $(AS) -o $@ @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h diff --git a/examples/graphics/gpu/geoshader/source/gpu.c b/examples/graphics/gpu/geoshader/source/gpu.c index c583ae5..abb8cdd 100644 --- a/examples/graphics/gpu/geoshader/source/gpu.c +++ b/examples/graphics/gpu/geoshader/source/gpu.c @@ -45,7 +45,7 @@ void gpuFrameBegin(void) // Configure some boilerplate GPU_SetFaceCulling(GPU_CULL_BACK_CCW); GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); - GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP); + GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); GPU_SetBlendingColor(0,0,0,0); GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL); diff --git a/examples/graphics/gpu/geoshader/source/main.c b/examples/graphics/gpu/geoshader/source/main.c index a2c9998..b49db2f 100644 --- a/examples/graphics/gpu/geoshader/source/main.c +++ b/examples/graphics/gpu/geoshader/source/main.c @@ -83,7 +83,7 @@ static void sceneRender(void) GPU_SetFloatUniformMatrix(GPU_GEOMETRY_SHADER, uLoc_projection, &projection); // Draw the VBO - GPU_UNKPRIM allows the geoshader to control primitive emission - GPU_DrawArray(GPU_UNKPRIM, vertex_list_count); + GPU_DrawArray(GPU_UNKPRIM, 0, vertex_list_count); } static void sceneExit(void) diff --git a/examples/graphics/gpu/simple_tri/Makefile b/examples/graphics/gpu/simple_tri/Makefile index 1e4e9ef..3b72824 100644 --- a/examples/graphics/gpu/simple_tri/Makefile +++ b/examples/graphics/gpu/simple_tri/Makefile @@ -164,7 +164,7 @@ $(OUTPUT).elf : $(OFILES) @echo $(notdir $<) $(eval CURBIN := $(patsubst %.pica,%.shbin,$(notdir $<))) $(eval CURH := $(patsubst %.pica,%.psh.h,$(notdir $<))) - @picasso $(CURBIN) $< $(CURH) + @picasso -h $(CURH) -o $(CURBIN) $< @bin2s $(CURBIN) | $(AS) -o $@ @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h diff --git a/examples/graphics/gpu/simple_tri/source/gpu.c b/examples/graphics/gpu/simple_tri/source/gpu.c index c583ae5..abb8cdd 100644 --- a/examples/graphics/gpu/simple_tri/source/gpu.c +++ b/examples/graphics/gpu/simple_tri/source/gpu.c @@ -45,7 +45,7 @@ void gpuFrameBegin(void) // Configure some boilerplate GPU_SetFaceCulling(GPU_CULL_BACK_CCW); GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); - GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP); + GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); GPU_SetBlendingColor(0,0,0,0); GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL); diff --git a/examples/graphics/gpu/simple_tri/source/main.c b/examples/graphics/gpu/simple_tri/source/main.c index d82cc12..656fb70 100644 --- a/examples/graphics/gpu/simple_tri/source/main.c +++ b/examples/graphics/gpu/simple_tri/source/main.c @@ -76,7 +76,7 @@ static void sceneRender(void) GPU_SetFloatUniformMatrix(GPU_VERTEX_SHADER, uLoc_projection, &projection); // Draw the VBO - GPU_DrawArray(GPU_TRIANGLES, vertex_list_count); + GPU_DrawArray(GPU_TRIANGLES, 0, vertex_list_count); } static void sceneExit(void) diff --git a/examples/graphics/gpu/textured_cube/Makefile b/examples/graphics/gpu/textured_cube/Makefile index 1e4e9ef..3b72824 100644 --- a/examples/graphics/gpu/textured_cube/Makefile +++ b/examples/graphics/gpu/textured_cube/Makefile @@ -164,7 +164,7 @@ $(OUTPUT).elf : $(OFILES) @echo $(notdir $<) $(eval CURBIN := $(patsubst %.pica,%.shbin,$(notdir $<))) $(eval CURH := $(patsubst %.pica,%.psh.h,$(notdir $<))) - @picasso $(CURBIN) $< $(CURH) + @picasso -h $(CURH) -o $(CURBIN) $< @bin2s $(CURBIN) | $(AS) -o $@ @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(CURBIN) | tr . _)`.h @echo "extern const u8" `(echo $(CURBIN) | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(CURBIN) | tr . _)`.h diff --git a/examples/graphics/gpu/textured_cube/source/gpu.c b/examples/graphics/gpu/textured_cube/source/gpu.c index c583ae5..abb8cdd 100644 --- a/examples/graphics/gpu/textured_cube/source/gpu.c +++ b/examples/graphics/gpu/textured_cube/source/gpu.c @@ -45,7 +45,7 @@ void gpuFrameBegin(void) // Configure some boilerplate GPU_SetFaceCulling(GPU_CULL_BACK_CCW); GPU_SetStencilTest(false, GPU_ALWAYS, 0x00, 0xFF, 0x00); - GPU_SetStencilOp(GPU_KEEP, GPU_KEEP, GPU_KEEP); + GPU_SetStencilOp(GPU_STENCIL_KEEP, GPU_STENCIL_KEEP, GPU_STENCIL_KEEP); GPU_SetBlendingColor(0,0,0,0); GPU_SetDepthTestAndWriteMask(true, GPU_GREATER, GPU_WRITE_ALL); diff --git a/examples/graphics/gpu/textured_cube/source/main.c b/examples/graphics/gpu/textured_cube/source/main.c index d8274b7..f4e13a1 100644 --- a/examples/graphics/gpu/textured_cube/source/main.c +++ b/examples/graphics/gpu/textured_cube/source/main.c @@ -186,7 +186,7 @@ static void sceneRender(void) GPU_SetFloatUniform(GPU_VERTEX_SHADER, uLoc_lightClr, (u32*)(float[]){1.0f, 1.0f, 1.0f, 1.0f}, 1); // Draw the VBO - GPU_DrawArray(GPU_TRIANGLES, vertex_list_count); + GPU_DrawArray(GPU_TRIANGLES, 0, vertex_list_count); } static void sceneExit(void) diff --git a/examples/romfs/Makefile b/examples/romfs/Makefile new file mode 100644 index 0000000..014079e --- /dev/null +++ b/examples/romfs/Makefile @@ -0,0 +1,181 @@ +#--------------------------------------------------------------------------------- +.SUFFIXES: +#--------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITARM)),) +$(error "Please set DEVKITARM in your environment. export DEVKITARM=devkitARM") +endif + +TOPDIR ?= $(CURDIR) +include $(DEVKITARM)/3ds_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 +# +# NO_SMDH: if set to anything, no SMDH file is generated. +# ROMFS is the directory which contains the RomFS, relative to the Makefile (Optional) +# APP_TITLE is the name of the app stored in the SMDH file (Optional) +# APP_DESCRIPTION is the description of the app stored in the SMDH file (Optional) +# APP_AUTHOR is the author of the app stored in the SMDH file (Optional) +# ICON is the filename of the icon (.png), relative to the project folder. +# If not set, it attempts to use one of the following (in this order): +# - .png +# - icon.png +# - /default_icon.png +#--------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := include +ROMFS := romfs + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +ARCH := -march=armv6k -mtune=mpcore -mfloat-abi=hard + +CFLAGS := -g -Wall -O2 -mword-relocations \ + -fomit-frame-pointer -ffast-math \ + $(ARCH) + +CFLAGS += $(INCLUDE) -DARM11 -D_3DS + +CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -std=gnu++11 + +ASFLAGS := -g $(ARCH) +LDFLAGS = -specs=3dsx.specs -g $(ARCH) -Wl,-Map,$(notdir $*.map) + +LIBS := -lctru -lm + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(CTRULIB) + + +#--------------------------------------------------------------------------------- +# no real need to edit anything past this point unless you need to add additional +# rules for different file extensions +#--------------------------------------------------------------------------------- +ifneq ($(BUILD),$(notdir $(CURDIR))) +#--------------------------------------------------------------------------------- + +export OUTPUT := $(CURDIR)/$(TARGET) +export TOPDIR := $(CURDIR) + +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) + +ifeq ($(strip $(ICON)),) + icons := $(wildcard *.png) + ifneq (,$(findstring $(TARGET).png,$(icons))) + export APP_ICON := $(TOPDIR)/$(TARGET).png + else + ifneq (,$(findstring icon.png,$(icons))) + export APP_ICON := $(TOPDIR)/icon.png + endif + endif +else + export APP_ICON := $(TOPDIR)/$(ICON) +endif + +ifeq ($(strip $(NO_SMDH)),) + export _3DSXFLAGS += --smdh=$(CURDIR)/$(TARGET).smdh +endif + +ifneq ($(ROMFS),) + export _3DSXFLAGS += --romfs=$(CURDIR)/$(ROMFS) +endif + +.PHONY: $(BUILD) clean all + +#--------------------------------------------------------------------------------- +all: $(BUILD) + +$(BUILD): + @[ -d $@ ] || mkdir -p $@ + @$(MAKE) --no-print-directory -C $(BUILD) -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -fr $(BUILD) $(TARGET).3dsx $(OUTPUT).smdh $(TARGET).elf + + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +ifeq ($(strip $(NO_SMDH)),) +$(OUTPUT).3dsx : $(OUTPUT).elf $(OUTPUT).smdh +else +$(OUTPUT).3dsx : $(OUTPUT).elf +endif + +$(OUTPUT).elf : $(OFILES) + +#--------------------------------------------------------------------------------- +# you need a rule like this for each extension you use as binary data +#--------------------------------------------------------------------------------- +%.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + +# WARNING: This is not the right way to do this! TODO: Do it right! +#--------------------------------------------------------------------------------- +%.vsh.o : %.vsh +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @python $(AEMSTRO)/aemstro_as.py $< ../$(notdir $<).shbin + @bin2s ../$(notdir $<).shbin | $(PREFIX)as -o $@ + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"_end[];" > `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u8" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`"[];" >> `(echo $(notdir $<).shbin | tr . _)`.h + @echo "extern const u32" `(echo $(notdir $<).shbin | sed -e 's/^\([0-9]\)/_\1/' | tr . _)`_size";" >> `(echo $(notdir $<).shbin | tr . _)`.h + @rm ../$(notdir $<).shbin + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/examples/romfs/romfs/folder/file.txt b/examples/romfs/romfs/folder/file.txt new file mode 100644 index 0000000..2454092 --- /dev/null +++ b/examples/romfs/romfs/folder/file.txt @@ -0,0 +1,6 @@ +Hello, this is the libctru romfs example. +This text is being read off a file in romfs. + + >>3DS Homebrew is Cool<< + +Signed off, fincs diff --git a/examples/romfs/romfs/フォルダ/ファイル.txt b/examples/romfs/romfs/フォルダ/ファイル.txt new file mode 100644 index 0000000..2cd922e --- /dev/null +++ b/examples/romfs/romfs/フォルダ/ファイル.txt @@ -0,0 +1,2 @@ +The path to this file contains UTF-16 +characters that fall outside ASCII. diff --git a/examples/romfs/source/main.c b/examples/romfs/source/main.c new file mode 100644 index 0000000..eb89630 --- /dev/null +++ b/examples/romfs/source/main.c @@ -0,0 +1,58 @@ +#include +#include +#include +#include <3ds.h> + +void printfile(const char* path) +{ + FILE* f = fopen(path, "r"); + if (f) + { + char mystring[100]; + while (fgets(mystring, sizeof(mystring), f)) + { + int a = strlen(mystring); + if (mystring[a-1] == '\n') + { + mystring[a-1] = 0; + if (mystring[a-2] == '\r') + mystring[a-2] = 0; + } + puts(mystring); + } + printf(">>EOF<<\n"); + fclose(f); + } +} + +int main() +{ + gfxInitDefault(); + consoleInit(GFX_TOP, NULL); + + Result rc = romfsInit(); + if (rc) + printf("romfsInit: %08lX\n", rc); + else + { + printf("romfs Init Successful!\n"); + printfile("folder/file.txt"); + // Test reading a file with non-ASCII characters in the name + printfile("フォルダ/ファイル.txt"); + } + + // Main loop + while (aptMainLoop()) + { + gspWaitForVBlank(); + hidScanInput(); + + u32 kDown = hidKeysDown(); + if (kDown & KEY_START) + break; // break in order to return to hbmenu + } + + romfsExit(); + gfxExit(); + return 0; +} diff --git a/libctru/Makefile b/libctru/Makefile index 67b189e..b2b40d3 100644 --- a/libctru/Makefile +++ b/libctru/Makefile @@ -113,7 +113,7 @@ dist: dist-src dist-bin install: dist-bin mkdir -p $(DEVKITPRO)/libctru - bzip2 -cd libctru-$(VERSION).tar.bz2 | tar -x -C $(DEVKITPRO)/libctru + bzip2 -cd libctru-$(VERSION).tar.bz2 | tar -xf - -C $(DEVKITPRO)/libctru dox: @doxygen Doxyfile diff --git a/libctru/include/3ds.h b/libctru/include/3ds.h index 9b54fd1..bfcf542 100644 --- a/libctru/include/3ds.h +++ b/libctru/include/3ds.h @@ -18,6 +18,7 @@ extern "C" { #include <3ds/services/ac.h> #include <3ds/services/am.h> #include <3ds/services/apt.h> +#include <3ds/services/cam.h> #include <3ds/services/cfgnor.h> #include <3ds/services/cfgu.h> #include <3ds/services/csnd.h> @@ -45,6 +46,7 @@ extern "C" { #include <3ds/gpu/shaderProgram.h> #include <3ds/sdmc.h> +#include <3ds/romfs.h> #ifdef __cplusplus } @@ -109,4 +111,4 @@ extern "C" { * @example threads/event/source/main.c * @example time/rtc/source/main.c */ - \ No newline at end of file + diff --git a/libctru/include/3ds/gpu/gpu.h b/libctru/include/3ds/gpu/gpu.h index 8370721..5a48103 100644 --- a/libctru/include/3ds/gpu/gpu.h +++ b/libctru/include/3ds/gpu/gpu.h @@ -33,6 +33,9 @@ void GPUCMD_Finalize(); #define GPU_TEXTURE_WRAP_S(v) (((v)&0x3)<<12) //takes a GPU_TEXTURE_WRAP_PARAM #define GPU_TEXTURE_WRAP_T(v) (((v)&0x3)<<8) //takes a GPU_TEXTURE_WRAP_PARAM +// Combiner buffer write config +#define GPU_TEV_BUFFER_WRITE_CONFIG(stage0, stage1, stage2, stage3) (stage0 | (stage1 << 1) | (stage2 << 2) | (stage3 << 3)) + typedef enum { GPU_NEAREST = 0x0, @@ -93,10 +96,14 @@ typedef enum typedef enum { - GPU_KEEP = 0, // keep destination value - GPU_AND_NOT = 1, // destination & ~source - GPU_XOR = 5, // destination ^ source - // 2 is the same as 1. Other values are too weird to even be usable. + GPU_STENCIL_KEEP = 0, // old_stencil + GPU_STENCIL_ZERO = 1, // 0 + GPU_STENCIL_REPLACE = 2, // ref + GPU_STENCIL_INCR = 3, // old_stencil + 1 saturated to [0, 255] + GPU_STENCIL_DECR = 4, // old_stencil - 1 saturated to [0, 255] + GPU_STENCIL_INVERT = 5, // ~old_stencil + GPU_STENCIL_INCR_WRAP = 6, // old_stencil + 1 + GPU_STENCIL_DECR_WRAP = 7 // old_stencil - 1 } GPU_STENCILOP; typedef enum @@ -184,6 +191,7 @@ typedef enum{ GPU_TEXTURE1 = 0x04, GPU_TEXTURE2 = 0x05, GPU_TEXTURE3 = 0x06, + GPU_PREVIOUS_BUFFER = 0x0D, GPU_CONSTANT = 0x0E, GPU_PREVIOUS = 0x0F, }GPU_TEVSRC; @@ -259,9 +267,11 @@ void GPU_SetScissorTest(GPU_SCISSORMODE mode, u32 x, u32 y, u32 w, u32 h); void GPU_DepthMap(float zScale, float zOffset); void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref); void GPU_SetDepthTestAndWriteMask(bool enable, GPU_TESTFUNC function, GPU_WRITEMASK writemask); // GPU_WRITEMASK values can be ORed together -void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 mask, u8 replace); +void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 input_mask, u8 write_mask); void GPU_SetStencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass); void GPU_SetFaceCulling(GPU_CULLMODE mode); +// Only the first four tev stages can write to the combiner buffer, use GPU_TEV_BUFFER_WRITE_CONFIG to build the parameters +void GPU_SetCombinerBufferWrite(u8 rgb_config, u8 alpha_config); // these two can't be used together void GPU_SetAlphaBlending(GPU_BLENDEQUATION colorEquation, GPU_BLENDEQUATION alphaEquation, @@ -281,10 +291,10 @@ void GPU_SetTexture(GPU_TEXUNIT unit, u32* data, u16 width, u16 height, u32 para /** * @param borderColor The color used for the border when using the @ref GPU_CLAMP_TO_BORDER wrap mode */ - void GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor); +void GPU_SetTextureBorderColor(GPU_TEXUNIT unit,u32 borderColor); void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor); -void GPU_DrawArray(GPU_Primitive_t primitive, u32 n); +void GPU_DrawArray(GPU_Primitive_t primitive, u32 first, u32 count); void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n); void GPU_FinishDrawing(); diff --git a/libctru/include/3ds/gpu/registers.h b/libctru/include/3ds/gpu/registers.h index b08fa2b..c8fd90e 100644 --- a/libctru/include/3ds/gpu/registers.h +++ b/libctru/include/3ds/gpu/registers.h @@ -224,7 +224,7 @@ #define GPUREG_00DD 0x00DD #define GPUREG_00DE 0x00DE #define GPUREG_00DF 0x00DF -#define GPUREG_00E0 0x00E0 +#define GPUREG_TEXENV_BUFFER_CONFIG 0x00E0 #define GPUREG_00E1 0x00E1 #define GPUREG_00E2 0x00E2 #define GPUREG_00E3 0x00E3 @@ -253,7 +253,7 @@ #define GPUREG_TEXENV5_CONFIG2 0x00FA #define GPUREG_TEXENV5_CONFIG3 0x00FB #define GPUREG_TEXENV5_CONFIG4 0x00FC -#define GPUREG_00FD 0x00FD +#define GPUREG_TEXENV_BUFFER_COLOR 0x00FD #define GPUREG_00FE 0x00FE #define GPUREG_00FF 0x00FF #define GPUREG_COLOROUTPUT_CONFIG 0x0100 @@ -554,7 +554,7 @@ #define GPUREG_INDEXBUFFER_CONFIG 0x0227 #define GPUREG_NUMVERTICES 0x0228 #define GPUREG_GEOSTAGE_CONFIG 0x0229 -#define GPUREG_022A 0x022A +#define GPUREG_DRAW_VERTEX_OFFSET 0x022A #define GPUREG_022B 0x022B #define GPUREG_022C 0x022C #define GPUREG_022D 0x022D diff --git a/libctru/include/3ds/romfs.h b/libctru/include/3ds/romfs.h new file mode 100644 index 0000000..0dc5789 --- /dev/null +++ b/libctru/include/3ds/romfs.h @@ -0,0 +1,35 @@ +#pragma once + +#include <3ds/types.h> + +typedef struct +{ + u32 headerSize; + u32 dirHashTableOff, dirHashTableSize; + u32 dirTableOff, dirTableSize; + u32 fileHashTableOff, fileHashTableSize; + u32 fileTableOff, fileTableSize; + u32 fileDataOff; +} romfs_header; + +typedef struct +{ + u32 parent, sibling; + u32 childDir, childFile; + u32 nextHash; + u32 nameLen; + u16 name[]; +} romfs_dir; + +typedef struct +{ + u32 parent, sibling; + u64 dataOff, dataSize; + u32 nextHash; + u32 nameLen; + u16 name[]; +} romfs_file; + +Result romfsInit(void); +Result romfsInitFromFile(Handle file, u32 offset); +Result romfsExit(void); diff --git a/libctru/include/3ds/services/apt.h b/libctru/include/3ds/services/apt.h index 7c5620c..133abcb 100644 --- a/libctru/include/3ds/services/apt.h +++ b/libctru/include/3ds/services/apt.h @@ -12,8 +12,11 @@ typedef enum{ APPID_WEB = 0x114, // Internet Browser APPID_INSTRUCTION_MANUAL = 0x115, // Instruction Manual applet APPID_NOTIFICATIONS = 0x116, // Notifications applet - APPID_MIIVERSE = 0x117, // Miiverse applet + APPID_MIIVERSE = 0x117, // Miiverse applet (olv) + APPID_MIIVERSE_POSTING = 0x118, // Miiverse posting applet (solv3) + APPID_AMIIBO_SETTINGS = 0x119, // Amiibo settings applet (cabinet) APPID_APPLICATION = 0x300, // Application + APPID_ESHOP = 0x301, // eShop (tiger) APPID_SOFTWARE_KEYBOARD = 0x401, // Software Keyboard APPID_APPLETED = 0x402, // appletEd APPID_PNOTE_AP = 0x404, // PNOTE_AP @@ -94,6 +97,7 @@ Result APT_Finalize(Handle* handle, NS_APPID appId); Result APT_HardwareResetAsync(Handle* handle); Result APT_Enable(Handle* handle, u32 a); Result APT_GetAppletManInfo(Handle* handle, u8 inval, u8 *outval8, u32 *outval32, NS_APPID *menu_appid, NS_APPID *active_appid); +Result APT_GetAppletProgramInfo(Handle* handle, u32 id, u32 flags, u16 *titleversion); Result APT_PrepareToJumpToHomeMenu(Handle* handle); Result APT_JumpToHomeMenu(Handle* handle, u32 a, u32 b, u32 c); Result APT_PrepareToJumpToApplication(Handle* handle, u32 a); diff --git a/libctru/include/3ds/services/cam.h b/libctru/include/3ds/services/cam.h new file mode 100644 index 0000000..c0fde59 --- /dev/null +++ b/libctru/include/3ds/services/cam.h @@ -0,0 +1,570 @@ +/** + * @file cam.h + * @brief CAM service for using the 3DS's front and back cameras. + */ +#pragma once +#include <3ds/services/y2r.h> +#include <3ds/types.h> + +/** + * @brief Camera connection target ports. + */ +typedef enum { + PORT_NONE = 0x0, + PORT_CAM1 = BIT(0), + PORT_CAM2 = BIT(1), + + // Port combinations. + PORT_BOTH = PORT_CAM1 | PORT_CAM2, +} CAMU_Port; + +/** + * @brief Camera combinations. + */ +typedef enum { + SELECT_NONE = 0x0, + SELECT_OUT1 = BIT(0), + SELECT_IN1 = BIT(1), + SELECT_OUT2 = BIT(2), + + // Camera combinations. + SELECT_IN1_OUT1 = SELECT_OUT1 | SELECT_IN1, + SELECT_OUT1_OUT2 = SELECT_OUT1 | SELECT_OUT2, + SELECT_IN1_OUT2 = SELECT_IN1 | SELECT_OUT2, + SELECT_ALL = SELECT_OUT1 | SELECT_IN1 | SELECT_OUT2, +} CAMU_CameraSelect; + +/** + * @brief Camera contexts. + */ +typedef enum { + CONTEXT_NONE = 0x0, + CONTEXT_A = BIT(0), + CONTEXT_B = BIT(1), + + // Context combinations. + CONTEXT_BOTH = CONTEXT_A | CONTEXT_B, +} CAMU_Context; + +/** + * @brief Ways to flip the camera image. + */ +typedef enum { + FLIP_NONE = 0x0, + FLIP_HORIZONTAL = 0x1, + FLIP_VERTICAL = 0x2, + FLIP_REVERSE = 0x3, +} CAMU_Flip; + +/** + * @brief Camera image resolutions. + */ +typedef enum { + SIZE_VGA = 0x0, + SIZE_QVGA = 0x1, + SIZE_QQVGA = 0x2, + SIZE_CIF = 0x3, + SIZE_QCIF = 0x4, + SIZE_DS_LCD = 0x5, + SIZE_DS_LCDx4 = 0x6, + SIZE_CTR_TOP_LCD = 0x7, + + // Alias for bottom screen to match top screen naming. + SIZE_CTR_BOTTOM_LCD = SIZE_QVGA, +} CAMU_Size; + +/** + * @brief Camera capture frame rates. + */ +typedef enum { + FRAME_RATE_15 = 0x0, + FRAME_RATE_15_TO_5 = 0x1, + FRAME_RATE_15_TO_2 = 0x2, + FRAME_RATE_10 = 0x3, + FRAME_RATE_8_5 = 0x4, + FRAME_RATE_5 = 0x5, + FRAME_RATE_20 = 0x6, + FRAME_RATE_20_TO_5 = 0x7, + FRAME_RATE_30 = 0x8, + FRAME_RATE_30_TO_5 = 0x9, + FRAME_RATE_15_TO_10 = 0xA, + FRAME_RATE_20_TO_10 = 0xB, + FRAME_RATE_30_TO_10 = 0xC, +} CAMU_FrameRate; + +/** + * @brief Camera white balance modes. + */ +typedef enum { + WHITE_BALANCE_AUTO = 0x0, + WHITE_BALANCE_3200K = 0x1, + WHITE_BALANCE_4150K = 0x2, + WHITE_BALANCE_5200K = 0x3, + WHITE_BALANCE_6000K = 0x4, + WHITE_BALANCE_7000K = 0x5, + WHITE_BALANCE_MAX = 0x6, + + // White balance aliases. + WHITE_BALANCE_NORMAL = WHITE_BALANCE_AUTO, + WHITE_BALANCE_TUNGSTEN = WHITE_BALANCE_3200K, + WHITE_BALANCE_WHITE_FLUORESCENT_LIGHT = WHITE_BALANCE_4150K, + WHITE_BALANCE_DAYLIGHT = WHITE_BALANCE_5200K, + WHITE_BALANCE_CLOUDY = WHITE_BALANCE_6000K, + WHITE_BALANCE_HORIZON = WHITE_BALANCE_6000K, + WHITE_BALANCE_SHADE = WHITE_BALANCE_7000K, +} CAMU_WhiteBalance; + +/** + * @brief Camera photo modes. + */ +typedef enum { + PHOTO_MODE_NORMAL = 0x0, + PHOTO_MODE_PORTRAIT = 0x1, + PHOTO_MODE_LANDSCAPE = 0x2, + PHOTO_MODE_NIGHTVIEW = 0x3, + PHOTO_MODE_LETTER = 0x4, +} CAMU_PhotoMode; + +/** + * @brief Camera special effects. + */ +typedef enum { + EFFECT_NONE = 0x0, + EFFECT_MONO = 0x1, + EFFECT_SEPIA = 0x2, + EFFECT_NEGATIVE = 0x3, + EFFECT_NEGAFILM = 0x4, + EFFECT_SEPIA01 = 0x5, +} CAMU_Effect; + +/** + * @brief Camera contrast patterns. + */ +typedef enum { + CONTRAST_PATTERN_01 = 0x0, + CONTRAST_PATTERN_02 = 0x1, + CONTRAST_PATTERN_03 = 0x2, + CONTRAST_PATTERN_04 = 0x3, + CONTRAST_PATTERN_05 = 0x4, + CONTRAST_PATTERN_06 = 0x5, + CONTRAST_PATTERN_07 = 0x6, + CONTRAST_PATTERN_08 = 0x7, + CONTRAST_PATTERN_09 = 0x8, + CONTRAST_PATTERN_10 = 0x9, + CONTRAST_PATTERN_11 = 0xA, + + // Contrast aliases. + CONTRAST_LOW = CONTRAST_PATTERN_05, + CONTRAST_NORMAL = CONTRAST_PATTERN_06, + CONTRAST_HIGH = CONTRAST_PATTERN_07, +} CAMU_Contrast; + +/** + * @brief Camera lens correction modes. + */ +typedef enum { + LENS_CORRECTION_OFF = 0x0, + LENS_CORRECTION_ON_70 = 0x1, + LENS_CORRECTION_ON_90 = 0x2, + + // Lens correction aliases. + LENS_CORRECTION_DARK = LENS_CORRECTION_OFF, + LENS_CORRECTION_NORMAL = LENS_CORRECTION_ON_70, + LENS_CORRECTION_BRIGHT = LENS_CORRECTION_ON_90, +} CAMU_LensCorrection; + +/** + * @brief Camera image output formats. + */ +typedef enum { + OUTPUT_YUV_422 = 0x0, + OUTPUT_RGB_565 = 0x1, +} CAMU_OutputFormat; + +/** + * @brief Camera shutter sounds. + */ +typedef enum { + SHUTTER_SOUND_TYPE_NORMAL = 0x0, + SHUTTER_SOUND_TYPE_MOVIE = 0x1, + SHUTTER_SOUND_TYPE_MOVIE_END = 0x2, +} CAMU_ShutterSoundType; + +/** + * @brief Image quality calibration data. + */ +typedef struct { + s16 aeBaseTarget; ///< Auto exposure base target brightness. + s16 kRL; ///< Left color correction matrix red normalization coefficient. + s16 kGL; ///< Left color correction matrix green normalization coefficient. + s16 kBL; ///< Left color correction matrix blue normalization coefficient. + s16 ccmPosition; ///< Color correction matrix position. + u16 awbCcmL9Right; ///< Right camera, left color correction matrix red/green gain. + u16 awbCcmL9Left; ///< Left camera, left color correction matrix red/green gain. + u16 awbCcmL10Right; ///< Right camera, left color correction matrix blue/green gain. + u16 awbCcmL10Left; ///< Left camera, left color correction matrix blue/green gain. + u16 awbX0Right; ///< Right camera, color correction matrix position threshold. + u16 awbX0Left; ///< Left camera, color correction matrix position threshold. +} CAMU_ImageQualityCalibrationData; + +/** + * @brief Stereo camera calibration data. + */ +typedef struct { + u8 isValidRotationXY; ///< #bool Whether the X and Y rotation data is valid. + u8 padding[3]; ///< Padding. (Aligns isValidRotationXY to 4 bytes) + float scale; ///< Scale to match the left camera image with the right. + float rotationZ; ///< Z axis rotation to match the left camera image with the right. + float translationX; ///< X axis translation to match the left camera image with the right. + float translationY; ///< Y axis translation to match the left camera image with the right. + float rotationX; ///< X axis rotation to match the left camera image with the right. + float rotationY; ///< Y axis rotation to match the left camera image with the right. + float angleOfViewRight; ///< Right camera angle of view. + float angleOfViewLeft; ///< Left camera angle of view. + float distanceToChart; ///< Distance between cameras and measurement chart. + float distanceCameras; ///< Distance between left and right cameras. + s16 imageWidth; ///< Image width. + s16 imageHeight; ///< Image height. + u8 reserved[16]; ///< Reserved for future use. (unused) +} CAMU_StereoCameraCalibrationData; + +/** + * @brief Batch camera configuration for use without a context. + */ +typedef struct { + u8 camera; ///< #CAMU_CameraSelect Selected camera. + s8 exposure; ///< Camera exposure. + u8 whiteBalance; ///< #CAMU_WhiteBalance Camera white balance. + s8 sharpness; ///< Camera sharpness. + u8 autoExposureOn; ///< #bool Whether to automatically determine the proper exposure. + u8 autoWhiteBalanceOn; ///< #bool Whether to automatically determine the white balance mode. + u8 frameRate; ///< #CAMU_FrameRate Camera frame rate. + u8 photoMode; ///< #CAMU_PhotoMode Camera photo mode. + u8 contrast; ///< #CAMU_Contrast Camera contrast. + u8 lensCorrection; ///< #CAMU_LensCorrection Camera lens correction. + u8 noiseFilterOn; ///< #bool Whether to enable the camera's noise filter. + u8 padding; ///< Padding. (Aligns last 3 fields to 4 bytes) + s16 autoExposureWindowX; ///< X of the region to use for auto exposure. + s16 autoExposureWindowY; ///< Y of the region to use for auto exposure. + s16 autoExposureWindowWidth; ///< Width of the region to use for auto exposure. + s16 autoExposureWindowHeight; ///< Height of the region to use for auto exposure. + s16 autoWhiteBalanceWindowX; ///< X of the region to use for auto white balance. + s16 autoWhiteBalanceWindowY; ///< Y of the region to use for auto white balance. + s16 autoWhiteBalanceWindowWidth; ///< Width of the region to use for auto white balance. + s16 autoWhiteBalanceWindowHeight; ///< Height of the region to use for auto white balance. +} CAMU_PackageParameterCameraSelect; + +/** + * @brief Batch camera configuration for use with a context. + */ +typedef struct { + u8 camera; ///< #CAMU_CameraSelect Selected camera. + u8 context; ///< #CAMU_Context Selected context. + u8 flip; ///< #CAMU_Flip Camera image flip mode. + u8 effect; ///< #CAMU_Effect Camera image special effects. + u8 size; ///< #CAMU_Size Camera image resolution. +} CAMU_PackageParameterContext; + +/** + * @brief Batch camera configuration for use with a context and with detailed size information. + */ +typedef struct { + u8 camera; ///< #CAMU_CameraSelect Selected camera. + u8 context; ///< #CAMU_Context Selected context. + u8 flip; ///< #CAMU_Flip Camera image flip mode. + u8 effect; ///< #CAMU_Effect Camera image special effects. + s16 width; ///< Image width. + s16 height; ///< Image height. + s16 cropX0; ///< First crop point X. + s16 cropY0; ///< First crop point Y. + s16 cropX1; ///< Second crop point X. + s16 cropY1; ///< Second crop point Y. +} CAMU_PackageParameterContextDetail; + +/** + * @brief Initializes the cam service. + * + * This will internally get the handle of the service, and on success call CAMU_DriverInitialize. + */ +Result camInit(); + +/** + * @brief Closes the cam service. + * + * This will internally call CAMU_DriverFinalize and close the handle of the service. + */ +Result camExit(); + +/// Begins capture on the specified camera port. +Result CAMU_StartCapture(CAMU_Port port); + +///Terminates capture on the specified camera port. +Result CAMU_StopCapture(CAMU_Port port); + +/** + * @brief Gets whether the specified camera port is busy. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_IsBusy(bool* busy, CAMU_Port port); + +///Clears the buffer and error flags of the specified camera port. +Result CAMU_ClearBuffer(CAMU_Port port); + +/** + * @brief Gets a handle to the event signaled on vsync interrupts. + * + * Writes the event handle to the provided output pointer. + */ +Result CAMU_GetVsyncInterruptEvent(Handle* event, CAMU_Port port); + +/** + * @brief Gets a handle to the event signaled on camera buffer errors. + * + * Writes the event handle to the provided output pointer. + */ +Result CAMU_GetBufferErrorInterruptEvent(Handle* event, CAMU_Port port); + +/** + * @brief Initiates the process of receiving a camera frame. + * + * Writes a completion event handle to the provided pointer and writes image data to the provided buffer. + */ +Result CAMU_SetReceiving(Handle* event, void* dst, CAMU_Port port, u32 imageSize, s16 transferUnit); + +/** + * @brief Gets whether the specified camera port has finished receiving image data. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_IsFinishedReceiving(bool* finishedReceiving, CAMU_Port port); + +///Sets the number of lines to transfer into an image buffer. +Result CAMU_SetTransferLines(CAMU_Port port, s16 lines, s16 width, s16 height); + +/** + * @brief Gets the maximum number of lines that can be saved to an image buffer. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetMaxLines(s16* maxLines, s16 width, s16 height); + +///Sets the number of bytes to transfer into an image buffer. +Result CAMU_SetTransferBytes(CAMU_Port port, u32 bytes, s16 width, s16 height); + +/** + * @brief Gets the number of bytes to transfer into an image buffer. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetTransferBytes(u32* transferBytes, CAMU_Port port); + +/** + * @brief Gets the maximum number of bytes that can be saved to an image buffer. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetMaxBytes(u32* maxBytes, s16 width, s16 height); + +///Sets whether image trimming is enabled. +Result CAMU_SetTrimming(CAMU_Port port, bool trimming); + +/** + * @brief Gets whether image trimming is enabled. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_IsTrimming(bool* trimming, CAMU_Port port); + +///Sets the parameters used for trimming images. +Result CAMU_SetTrimmingParams(CAMU_Port port, s16 xStart, s16 yStart, s16 xEnd, s16 yEnd); + +/** + * @brief Gets the parameters used for trimming images. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetTrimmingParams(s16* xStart, s16* yStart, s16* xEnd, s16* yEnd, CAMU_Port port); + +///Sets the parameters used for trimming images, relative to the center of the image. +Result CAMU_SetTrimmingParamsCenter(CAMU_Port port, s16 trimWidth, s16 trimHeight, s16 camWidth, s16 camHeight); + +///Activates the specified camera. +Result CAMU_Activate(CAMU_CameraSelect select); + +///Switches the specified camera's active context. +Result CAMU_SwitchContext(CAMU_CameraSelect select, CAMU_Context context); + +///Sets the exposure value of the specified camera. +Result CAMU_SetExposure(CAMU_CameraSelect select, s8 exposure); + +///Sets the white balance mode of the specified camera. +Result CAMU_SetWhiteBalance(CAMU_CameraSelect select, CAMU_WhiteBalance whiteBalance); + +/** + * @brief Sets the white balance mode of the specified camera. + * + * TODO: Explain "without base up"? + */ +Result CAMU_SetWhiteBalanceWithoutBaseUp(CAMU_CameraSelect select, CAMU_WhiteBalance whiteBalance); + +///Sets the sharpness of the specified camera. +Result CAMU_SetSharpness(CAMU_CameraSelect select, s8 sharpness); + +///Sets whether auto exposure is enabled on the specified camera. +Result CAMU_SetAutoExposure(CAMU_CameraSelect select, bool autoExposure); + +/** + * @brief Gets whether auto exposure is enabled on the specified camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_IsAutoExposure(bool* autoExposure, CAMU_CameraSelect select); + +///Sets whether auto white balance is enabled on the specified camera. +Result CAMU_SetAutoWhiteBalance(CAMU_CameraSelect select, bool autoWhiteBalance); + +/** + * @brief Gets whether auto white balance is enabled on the specified camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_IsAutoWhiteBalance(bool* autoWhiteBalance, CAMU_CameraSelect select); + +///Flips the image of the specified camera in the specified context. +Result CAMU_FlipImage(CAMU_CameraSelect select, CAMU_Flip flip, CAMU_Context context); + +///Sets the image resolution of the given camera in the given context, in detail. +Result CAMU_SetDetailSize(CAMU_CameraSelect select, s16 width, s16 height, s16 cropX0, s16 cropY0, s16 cropX1, s16 cropY1, CAMU_Context context); + +///Sets the image resolution of the given camera in the given context. +Result CAMU_SetSize(CAMU_CameraSelect select, CAMU_Size size, CAMU_Context context); + +///Sets the frame rate of the given camera. +Result CAMU_SetFrameRate(CAMU_CameraSelect select, CAMU_FrameRate frameRate); + +///Sets the photo mode of the given camera. +Result CAMU_SetPhotoMode(CAMU_CameraSelect select, CAMU_PhotoMode photoMode); + +///Sets the special effects of the given camera in the given context. +Result CAMU_SetEffect(CAMU_CameraSelect select, CAMU_Effect effect, CAMU_Context context); + +///Sets the contrast mode of the given camera. +Result CAMU_SetContrast(CAMU_CameraSelect select, CAMU_Contrast contrast); + +///Sets the lens correction mode of the given camera. +Result CAMU_SetLensCorrection(CAMU_CameraSelect select, CAMU_LensCorrection lensCorrection); + +///Sets the output format of the given camera in the given context. +Result CAMU_SetOutputFormat(CAMU_CameraSelect select, CAMU_OutputFormat format, CAMU_Context context); + +///Sets the region to base auto exposure off of for the specified camera. +Result CAMU_SetAutoExposureWindow(CAMU_CameraSelect select, s16 x, s16 y, s16 width, s16 height); + +///Sets the region to base auto white balance off of for the specified camera. +Result CAMU_SetAutoWhiteBalanceWindow(CAMU_CameraSelect select, s16 x, s16 y, s16 width, s16 height); + +///Sets whether the specified camera's noise filter is enabled. +Result CAMU_SetNoiseFilter(CAMU_CameraSelect select, bool noiseFilter); + +///Synchronizes the specified cameras' vsync timing. +Result CAMU_SynchronizeVsyncTiming(CAMU_CameraSelect select1, CAMU_CameraSelect select2); + +/** + * @brief Gets the vsync timing record of the specified camera for the specified number of signals. + * + * Writes the result to the provided output pointer, which should be of size "past * sizeof(s64)". + */ +Result CAMU_GetLatestVsyncTiming(s64* timing, CAMU_Port port, u32 past); + +/** + * @brief Gets the specified camera's stereo camera calibration data. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetStereoCameraCalibrationData(CAMU_StereoCameraCalibrationData* data); + +///Sets the specified camera's stereo camera calibration data. +Result CAMU_SetStereoCameraCalibrationData(CAMU_StereoCameraCalibrationData data); + +/** + * @brief Writes to the specified I2C register of the specified camera. + * + * Use with caution. + */ +Result CAMU_WriteRegisterI2c(CAMU_CameraSelect select, u16 addr, u16 data); + +/** + * @brief Writes to the specified MCU variable of the specified camera. + * + * Use with caution. + */ +Result CAMU_WriteMcuVariableI2c(CAMU_CameraSelect select, u16 addr, u16 data); + +/** + * @brief Reads the specified I2C register of the specified camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_ReadRegisterI2cExclusive(u16* data, CAMU_CameraSelect select, u16 addr); + +/** + * @brief Reads the specified MCU variable of the specified camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_ReadMcuVariableI2cExclusive(u16* data, CAMU_CameraSelect select, u16 addr); + +/** + * @brief Sets the specified camera's image quality calibration data. + */ +Result CAMU_SetImageQualityCalibrationData(CAMU_ImageQualityCalibrationData data); + +/** + * @brief Gets the specified camera's image quality calibration data. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetImageQualityCalibrationData(CAMU_ImageQualityCalibrationData* data); + +///Configures a camera with pre-packaged configuration data without a context. +Result CAMU_SetPackageParameterWithoutContext(CAMU_PackageParameterCameraSelect param); + +///Configures a camera with pre-packaged configuration data with a context. +Result CAMU_SetPackageParameterWithContext(CAMU_PackageParameterContext param); + +///Configures a camera with pre-packaged configuration data without a context and extra resolution details. +Result CAMU_SetPackageParameterWithContextDetail(CAMU_PackageParameterContextDetail param); + +///Gets the Y2R coefficient applied to image data by the camera. +Result CAMU_GetSuitableY2rStandardCoefficient(Y2R_StandardCoefficient* coefficient); + +///Plays the specified shutter sound. +Result CAMU_PlayShutterSound(CAMU_ShutterSoundType sound); + +///Initializes the camera driver. +Result CAMU_DriverInitialize(); + +///Finalizes the camera driver. +Result CAMU_DriverFinalize(); + +/** + * @brief Gets the current activated camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetActivatedCamera(CAMU_CameraSelect* select); + +/** + * @brief Gets the current sleep camera. + * + * Writes the result to the provided output pointer. + */ +Result CAMU_GetSleepCamera(CAMU_CameraSelect* select); + +///Sets the current sleep camera. +Result CAMU_SetSleepCamera(CAMU_CameraSelect select); + +///Sets whether to enable synchronization of left and right camera brightnesses. +Result CAMU_SetBrightnessSynchronization(bool brightnessSynchronization); + diff --git a/libctru/include/3ds/services/httpc.h b/libctru/include/3ds/services/httpc.h index 6e1c0ed..4a16702 100644 --- a/libctru/include/3ds/services/httpc.h +++ b/libctru/include/3ds/services/httpc.h @@ -23,7 +23,7 @@ Result httpcReceiveData(httpcContext *context, u8* buffer, u32 size); Result httpcGetRequestState(httpcContext *context, httpcReqStatus* out); Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32* contentsize); Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay);//delay isn't used yet. This writes the HTTP status code from the server to out. - +Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u32 valuebuf_maxsize); Result httpcDownloadData(httpcContext *context, u8* buffer, u32 size, u32 *downloadedsize);//The *entire* content must be downloaded before using httpcCloseContext(), otherwise httpcCloseContext() will hang. //Using the below functions directly is not recommended, use the above functions. See also the http example. @@ -38,5 +38,6 @@ Result HTTPC_BeginRequest(Handle handle, Handle contextHandle); Result HTTPC_ReceiveData(Handle handle, Handle contextHandle, u8* buffer, u32 size); Result HTTPC_GetRequestState(Handle handle, Handle contextHandle, httpcReqStatus* out); Result HTTPC_GetDownloadSizeState(Handle handle, Handle contextHandle, u32* downloadedsize, u32* contentsize); +Result HTTPC_GetResponseHeader(Handle handle, Handle contextHandle, char* name, char* value, u32 valuebuf_maxsize); Result HTTPC_GetResponseStatusCode(Handle handle, Handle contextHandle, u32* out); diff --git a/libctru/include/3ds/services/ps.h b/libctru/include/3ds/services/ps.h index 29c9d95..52b7d65 100644 --- a/libctru/include/3ds/services/ps.h +++ b/libctru/include/3ds/services/ps.h @@ -17,10 +17,11 @@ typedef enum ps_KEYSLOT_31, ps_KEYSLOT_38, ps_KEYSLOT_32, - ps_KEYSLOT_39, + ps_KEYSLOT_39_DLP, ps_KEYSLOT_2E, ps_KEYSLOT_INVALID, - ps_KEYSLOT_36 + ps_KEYSLOT_36, + ps_KEYSLOT_39_NFC } ps_aes_keytypes; /* @@ -73,4 +74,4 @@ About: Gets a 32bit device id, it's used for some key slot inits device_id ptr to where the device id is written to */ -Result PS_GetDeviceId(u32* device_id); \ No newline at end of file +Result PS_GetDeviceId(u32* device_id); diff --git a/libctru/include/3ds/services/soc.h b/libctru/include/3ds/services/soc.h index 3ec99b7..34a8e49 100644 --- a/libctru/include/3ds/services/soc.h +++ b/libctru/include/3ds/services/soc.h @@ -1,7 +1,23 @@ +/** + * @file soc.h + * @brief SOC service for sockets communications + * + * After initializing this service you will be able to use system calls from netdb.h, sys/socket.h etc. + */ #pragma once -Result SOC_Initialize(u32 *context_addr, u32 context_size);//Example context_size: 0x48000. The specified context buffer can no longer be accessed by the process which called this function, since the userland permissions for this block are set to no-access. +/** + * @brief Initializes the SOC service. + * @param context_addr Address of a page-aligned (0x1000) buffer to be used. + * @param context_size Size of the buffer, a multiple of 0x1000. + * @note The specified context buffer can no longer be accessed by the process which called this function, since the userland permissions for this block are set to no-access. + */ +Result SOC_Initialize(u32 *context_addr, u32 context_size); +/** + * @brief Closes the soc service. + * @note You need to call this in order to be able to use the buffer again. + */ Result SOC_Shutdown(void); /* this is supposed to be in unistd.h but newlib only puts it for cygwin */ diff --git a/libctru/include/3ds/svc.h b/libctru/include/3ds/svc.h index 7593939..11a58d9 100644 --- a/libctru/include/3ds/svc.h +++ b/libctru/include/3ds/svc.h @@ -265,11 +265,25 @@ Result svcControlMemory(u32* addr_out, u32 addr0, u32 addr1, u32 size, MemOp op, */ Result svcControlProcessMemory(Handle process, u32 addr0, u32 addr1, u32 size, u32 type, u32 perm); +/** + * @brief Creates a block of shared memory + * @param memblock Pointer to store the handle of the block + * @param addr Address of the memory to map, page-aligned. So its alignment must be 0x1000. + * @param size Size of the memory to map, a multiple of 0x1000. + * @param my_perm Memory permissions for the current process + * @param my_perm Memory permissions for the other processes + * + * @note The shared memory block, and its rights, are destroyed when the handle is closed. + */ Result svcCreateMemoryBlock(Handle* memblock, u32 addr, u32 size, MemPerm my_perm, MemPerm other_perm); Result svcMapMemoryBlock(Handle memblock, u32 addr, MemPerm my_perm, MemPerm other_perm); Result svcMapProcessMemory(Handle process, u32 startAddr, u32 endAddr); Result svcUnmapProcessMemory(Handle process, u32 startAddr, u32 endAddr); Result svcUnmapMemoryBlock(Handle memblock, u32 addr); + +Result svcStartInterProcessDma(Handle* dma, Handle dstProcess, void* dst, Handle srcProcess, const void* src, u32 size, void* dmaConfig); +Result svcStopDma(Handle dma); +Result svcGetDmaState(void* dmaState, Handle dma); /** * @brief Memory information query * @param addr Virtual memory address @@ -280,6 +294,9 @@ Result svcQueryProcessMemory(MemInfo* info, PageInfo* out, Handle process, u32 a Result svcCreateAddressArbiter(Handle *arbiter); Result svcArbitrateAddress(Handle arbiter, u32 addr, ArbitrationType type, s32 value, s64 nanoseconds); +Result svcInvalidateProcessDataCache(Handle process, void* addr, u32 size); +Result svcFlushProcessDataCache(Handle process, void const* addr, u32 size); + Result svcReadProcessMemory(void* buffer, Handle debug, u32 addr, u32 size); Result svcWriteProcessMemory(Handle debug, const void* buffer, u32 addr, u32 size); ///@} @@ -295,6 +312,7 @@ Result svcWriteProcessMemory(Handle debug, const void* buffer, u32 addr, u32 siz */ Result svcOpenProcess(Handle* process, u32 processId); void svcExitProcess() __attribute__((noreturn)); +Result svcTerminateProcess(Handle process); Result svcGetProcessInfo(s64* out, Handle process, u32 type); Result svcGetProcessId(u32 *out, Handle handle); @@ -312,7 +330,7 @@ Result svcConnectToPort(volatile Handle* out, const char* portName); * @param arg The argument passed to @p entrypoint * @param stack_top The top of the thread's stack. Must be 0x8 bytes mem-aligned. * @param thread_priority Low values gives the thread higher priority. - * For userland app, this has to be withing the range [0x18;0x3F] + * For userland apps, this has to be within the range [0x18;0x3F] * @param processor_id The id of the processor the thread should be ran on. Those are labelled starting from 0. * For old 3ds it has to be <2, and for new 3DS <4. * Value -1 means all CPUs and -2 read from the Exheader. @@ -355,7 +373,7 @@ Result svcGetThreadPriority(s32 *out, Handle handle); /** * @brief Changes the priority of a thread - * @param prio For userland apps, this has to be withing the range [0x18;0x3F] + * @param prio For userland apps, this has to be within the range [0x18;0x3F] * * Low values gives the thread higher priority. */ @@ -396,14 +414,20 @@ Result svcGetThreadInfo(s64* out, Handle thread, ThreadInfoType type); ///@{ Result svcCreateMutex(Handle* mutex, bool initially_locked); Result svcReleaseMutex(Handle handle); + Result svcCreateSemaphore(Handle* semaphore, s32 initial_count, s32 max_count); Result svcReleaseSemaphore(s32* count, Handle semaphore, s32 release_count); + Result svcCreateEvent(Handle* event, u8 reset_type); Result svcSignalEvent(Handle handle); Result svcClearEvent(Handle handle); + Result svcWaitSynchronization(Handle handle, s64 nanoseconds); Result svcWaitSynchronizationN(s32* out, Handle* handles, s32 handles_num, bool wait_all, s64 nanoseconds); + Result svcSendSyncRequest(Handle session); +Result svcAcceptSession(Handle* session, Handle port); +Result svcReplyAndReceive(s32* index, Handle* handles, s32 handleCount, Handle replyTarget); ///@} ///@name Time @@ -420,11 +444,13 @@ u64 svcGetSystemTick(); Result svcCloseHandle(Handle handle); Result svcDuplicateHandle(Handle* out, Handle original); Result svcGetSystemInfo(s64* out, u32 type, s32 param); +Result svcKernelSetState(u32 type, u32 param0, u32 param1, u32 param2); ///@} ///@name Debugging ///@{ +void svcBreak(UserBreakType breakReason); Result svcOutputDebugString(const char* str, int length); Result svcDebugActiveProcess(Handle* debug, u32 processId); Result svcBreakDebugProcess(Handle debug); diff --git a/libctru/include/netdb.h b/libctru/include/netdb.h index b3fac81..4e42861 100644 --- a/libctru/include/netdb.h +++ b/libctru/include/netdb.h @@ -14,6 +14,7 @@ struct hostent { int h_addrtype; int h_length; char **h_addr_list; + char *h_addr; }; #ifdef __cplusplus @@ -22,6 +23,7 @@ extern "C" { extern int h_errno; struct hostent* gethostbyname(const char *name); + struct hostent* gethostbyaddr(const void *addr, socklen_t len, int type); void herror(const char *s); const char* hstrerror(int err); diff --git a/libctru/source/allocator/linear.cpp b/libctru/source/allocator/linear.cpp index 0ad052c..66cf920 100644 --- a/libctru/source/allocator/linear.cpp +++ b/libctru/source/allocator/linear.cpp @@ -61,7 +61,7 @@ void* linearMemAlign(size_t size, size_t alignment) void* linearAlloc(size_t size) { - return linearMemAlign(size, 16); + return linearMemAlign(size, 0x80); } void* linearRealloc(void* mem, size_t size) diff --git a/libctru/source/allocator/vram.cpp b/libctru/source/allocator/vram.cpp index 4918729..1d63cdf 100644 --- a/libctru/source/allocator/vram.cpp +++ b/libctru/source/allocator/vram.cpp @@ -59,7 +59,7 @@ void* vramMemAlign(size_t size, size_t alignment) void* vramAlloc(size_t size) { - return vramMemAlign(size, 16); + return vramMemAlign(size, 0x80); } void* vramRealloc(void* mem, size_t size) diff --git a/libctru/source/gpu/gpu.c b/libctru/source/gpu/gpu.c index 49d5809..723b65b 100644 --- a/libctru/source/gpu/gpu.c +++ b/libctru/source/gpu/gpu.c @@ -229,40 +229,65 @@ void GPU_SetFloatUniform(GPU_SHADER_TYPE type, u32 startreg, u32* data, u32 numr GPUCMD_AddWrites(GPUREG_VSH_FLOATUNIFORM_DATA+regOffset, data, numreg*4); } -//TODO : fix -u32 f32tof24(float f) +// f24 has: +// - 1 sign bit +// - 7 exponent bits +// - 16 mantissa bits +static u32 f32tof24(float f) { - if(!f)return 0; - u32 v=*((u32*)&f); - u8 s=v>>31; - u32 exp=((v>>23)&0xFF)-0x40; - u32 man=(v>>7)&0xFFFF; + u32 i; + memcpy(&i, &f, 4); - if(exp>=0)return man|(exp<<16)|(s<<23); - else return s<<23; + u32 mantissa = (i << 9) >> 9; + s32 exponent = (i << 1) >> 24; + u32 sign = (i << 0) >> 31; + + // Truncate mantissa + mantissa >>= 7; + + // Re-bias exponent + exponent = exponent - 127 + 63; + if (exponent < 0) + { + // Underflow: flush to zero + return sign << 23; + } + else if (exponent > 0x7F) + { + // Overflow: saturate to infinity + return sign << 23 | 0x7F << 16; + } + + return sign << 23 | exponent << 16 | mantissa; } -u32 computeInvValue(u32 val) +// f31 has: +// - 1 sign bit +// - 7 exponent bits +// - 23 mantissa bits +static u32 f32tof31(float f) { - //usual values - if(val==240)return 0x38111111; - if(val==480)return 0x37111111; - if(val==400)return 0x3747ae14; - //but let's not limit ourselves to the usual - float fval=2.0/val; - u32 tmp1,tmp2; - u32 tmp3=*((u32*)&fval); - tmp1=(tmp3<<9)>>9; - tmp2=tmp3&(~0x80000000); - if(tmp2) + u32 i; + memcpy(&i, &f, 4); + + u32 mantissa = (i << 9) >> 9; + s32 exponent = (i << 1) >> 24; + u32 sign = (i << 0) >> 31; + + // Re-bias exponent + exponent = exponent - 127 + 63; + if (exponent < 0) { - tmp1=(tmp3<<9)>>9; - int tmp=((tmp3<<1)>>24)-0x40; - if(tmp<0)return ((tmp3>>31)<<30)<<1; - else tmp2=tmp; + // Underflow: flush to zero + return sign << 30; } - tmp3>>=31; - return (tmp1|(tmp2<<23)|(tmp3<<30))<<1; + else if (exponent > 0x7F) + { + // Overflow: saturate to infinity + return sign << 30 | 0x7F << 23; + } + + return sign << 30 | exponent << 23 | mantissa; } //takes PAs as arguments @@ -288,9 +313,9 @@ void GPU_SetViewport(u32* depthBuffer, u32* colorBuffer, u32 x, u32 y, u32 w, u3 GPUCMD_AddWrite(GPUREG_011B, 0x00000000); //? param[0x0]=f32tof24(fw/2); - param[0x1]=computeInvValue(fw); + param[0x1]=f32tof31(2.0f / fw) << 1; param[0x2]=f32tof24(fh/2); - param[0x3]=computeInvValue(fh); + param[0x3]=f32tof31(2.0f / fh) << 1; GPUCMD_AddIncrementalWrites(GPUREG_0041, param, 0x00000004); GPUCMD_AddWrite(GPUREG_0068, (y<<16)|(x&0xFFFF)); @@ -330,9 +355,9 @@ void GPU_SetAlphaTest(bool enable, GPU_TESTFUNC function, u8 ref) GPUCMD_AddWrite(GPUREG_ALPHATEST_CONFIG, (enable&1)|((function&7)<<4)|(ref<<8)); } -void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 mask, u8 replace) +void GPU_SetStencilTest(bool enable, GPU_TESTFUNC function, u8 ref, u8 input_mask, u8 write_mask) { - GPUCMD_AddWrite(GPUREG_STENCILTEST_CONFIG, (enable&1)|((function&7)<<4)|(replace<<8)|(ref<<16)|(mask<<24)); + GPUCMD_AddWrite(GPUREG_STENCILTEST_CONFIG, (enable&1)|((function&7)<<4)|(write_mask<<8)|(ref<<16)|(input_mask<<24)); } void GPU_SetStencilOp(GPU_STENCILOP sfail, GPU_STENCILOP dfail, GPU_STENCILOP pass) @@ -463,6 +488,11 @@ void GPU_SetFaceCulling(GPU_CULLMODE mode) GPUCMD_AddWrite(GPUREG_FACECULLING_CONFIG, mode&0x3); } +void GPU_SetCombinerBufferWrite(u8 rgb_config, u8 alpha_config) +{ + GPUCMD_AddMaskedWrite(GPUREG_TEXENV_BUFFER_CONFIG, 0x2, (rgb_config << 8) | (alpha_config << 12)); +} + const u8 GPU_TEVID[]={0xC0,0xC8,0xD0,0xD8,0xF0,0xF8}; void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 alphaOperands, GPU_COMBINEFUNC rgbCombine, GPU_COMBINEFUNC alphaCombine, u32 constantColor) @@ -480,7 +510,7 @@ void GPU_SetTexEnv(u8 id, u16 rgbSources, u16 alphaSources, u16 rgbOperands, u16 GPUCMD_AddIncrementalWrites(GPUREG_0000|GPU_TEVID[id], param, 0x00000005); } -void GPU_DrawArray(GPU_Primitive_t primitive, u32 n) +void GPU_DrawArray(GPU_Primitive_t primitive, u32 first, u32 count) { //set primitive type GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x2, primitive); @@ -488,7 +518,9 @@ void GPU_DrawArray(GPU_Primitive_t primitive, u32 n) //index buffer address register should be cleared (except bit 31) before drawing GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000); //pass number of vertices - GPUCMD_AddWrite(GPUREG_NUMVERTICES, n); + GPUCMD_AddWrite(GPUREG_NUMVERTICES, count); + //set first vertex + GPUCMD_AddWrite(GPUREG_DRAW_VERTEX_OFFSET, first); //all the following except 0x000F022E might be useless GPUCMD_AddMaskedWrite(GPUREG_0253, 0x1, 0x00000001); @@ -508,7 +540,9 @@ void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n) GPUCMD_AddWrite(GPUREG_INDEXBUFFER_CONFIG, 0x80000000|((u32)indexArray)); //pass number of vertices GPUCMD_AddWrite(GPUREG_NUMVERTICES, n); - + + GPUCMD_AddWrite(GPUREG_DRAW_VERTEX_OFFSET, 0x00000000); + GPUCMD_AddMaskedWrite(GPUREG_GEOSTAGE_CONFIG, 0x2, 0x00000100); GPUCMD_AddMaskedWrite(GPUREG_0253, 0x2, 0x00000100); diff --git a/libctru/source/romfs_dev.c b/libctru/source/romfs_dev.c new file mode 100644 index 0000000..31e1263 --- /dev/null +++ b/libctru/source/romfs_dev.c @@ -0,0 +1,484 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include <3ds/types.h> +#include <3ds/svc.h> +#include <3ds/romfs.h> +#include <3ds/services/fs.h> +#include <3ds/util/utf.h> + +static bool romFS_active; +static Handle romFS_file; +static u32 romFS_offset; +static romfs_header romFS_header; +static romfs_dir* romFS_cwd; + +static u32 *dirHashTable, *fileHashTable; +static void *dirTable, *fileTable; + +extern u32 __service_ptr; +extern int __system_argc; +extern char** __system_argv; + +static char __component[PATH_MAX+1]; +static uint16_t __utf16path[PATH_MAX+1]; + +#define romFS_root ((romfs_dir*)dirTable) +#define romFS_dir(x) ((romfs_dir*) ((u8*)dirTable + (x))) +#define romFS_file(x) ((romfs_file*)((u8*)fileTable + (x))) +#define romFS_none ((u32)~0) + +static ssize_t _romfs_read(u64 offset, void* buffer, u32 size) +{ + u64 pos = (u64)romFS_offset + offset; + u32 read = 0; + Result rc = FSFILE_Read(romFS_file, &read, pos, buffer, size); + if (rc) return -1; + return read; +} + +static bool _romfs_read_chk(u64 offset, void* buffer, u32 size) +{ + return _romfs_read(offset, buffer, size) == size; +} + +//----------------------------------------------------------------------------- + +static int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode); +static int romfs_close(struct _reent *r, int fd); +static ssize_t romfs_read(struct _reent *r, int fd, char *ptr, size_t len); +static off_t romfs_seek(struct _reent *r, int fd, off_t pos, int dir); +static int romfs_fstat(struct _reent *r, int fd, struct stat *st); +static int romfs_stat(struct _reent *r, const char *file, struct stat *st); +static int romfs_chdir(struct _reent *r, const char *name); +static DIR_ITER* romfs_diropen(struct _reent *r, DIR_ITER *dirState, const char *path); +static int romfs_dirreset(struct _reent *r, DIR_ITER *dirState); +static int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat); +static int romfs_dirclose(struct _reent *r, DIR_ITER *dirState); + +typedef struct +{ + u64 offset, size, pos; +} romfs_fileobj; + +typedef struct +{ +} romfs_diriter; + +static devoptab_t romFS_devoptab = +{ + .name = "romfs", + .structSize = sizeof(romfs_fileobj), + .open_r = romfs_open, + .close_r = romfs_close, + .read_r = romfs_read, + .seek_r = romfs_seek, + .fstat_r = romfs_fstat, + .stat_r = romfs_stat, + .chdir_r = romfs_chdir, + .dirStateSize = sizeof(romfs_diriter), + .diropen_r = romfs_diropen, + .dirreset_r = romfs_dirreset, + .dirnext_r = romfs_dirnext, + .dirclose_r = romfs_dirclose, + .deviceData = NULL, +}; + +//----------------------------------------------------------------------------- + +// File header +#define _3DSX_MAGIC 0x58534433 // '3DSX' +typedef struct +{ + u32 magic; + u16 headerSize, relocHdrSize; + u32 formatVer; + u32 flags; + + // Sizes of the code, rodata and data segments + + // size of the BSS section (uninitialized latter half of the data segment) + u32 codeSegSize, rodataSegSize, dataSegSize, bssSize; + // offset and size of smdh + u32 smdhOffset, smdhSize; + // offset to filesystem + u32 fsOffset; +} _3DSX_Header; + +static Result romfsInitCommon(void); + +Result romfsInit(void) +{ + if (romFS_active) return 0; + if (__service_ptr) + { + // RomFS appended to a 3DSX file + if (__system_argc == 0 || !__system_argv[0]) return 1; + const char* filename = __system_argv[0]; + if (strncmp(filename, "sdmc:/", 6) == 0) + filename += 5; + else if (strncmp(filename, "3dslink:/", 9) == 0) + { + strncpy(__component, "/3ds", PATH_MAX); + strncat(__component, filename+8, PATH_MAX); + __component[PATH_MAX] = 0; + filename = __component; + } else + return 2; + + size_t units = utf8_to_utf16(__utf16path, (const uint8_t*)filename, PATH_MAX+1); + if (units == (size_t)-1) return 3; + __utf16path[units] = 0; + + FS_archive arch = { ARCH_SDMC, { PATH_EMPTY, 1, (u8*)"" }, 0, 0 }; + FS_path path = { PATH_WCHAR, units+1, (u8*)__utf16path }; + + Result rc = FSUSER_OpenFileDirectly(NULL, &romFS_file, arch, path, FS_OPEN_READ, FS_ATTRIBUTE_NONE); + if (rc) return rc; + + _3DSX_Header hdr; + if (!_romfs_read_chk(0, &hdr, sizeof(hdr))) goto _fail0; + if (hdr.magic != _3DSX_MAGIC) goto _fail0; + if (hdr.headerSize < sizeof(hdr)) goto _fail0; + romFS_offset = hdr.fsOffset; + if (!romFS_offset) goto _fail0; + } else + { + // Regular RomFS + u8 zeros[0xC]; + memset(zeros, 0, sizeof(zeros)); + + FS_archive arch = { ARCH_ROMFS, { PATH_EMPTY, 1, (u8*)"" }, 0, 0 }; + FS_path path = { PATH_BINARY, sizeof(zeros), zeros }; + + Result rc = FSUSER_OpenFileDirectly(NULL, &romFS_file, arch, path, FS_OPEN_READ, FS_ATTRIBUTE_NONE); + if (rc) return rc; + } + + return romfsInitCommon(); + +_fail0: + FSFILE_Close(romFS_file); + return 10; +} + +Result romfsInitFromFile(Handle file, u32 offset) +{ + if (romFS_active) return 0; + romFS_file = file; + romFS_offset = offset; + return romfsInitCommon(); +} + +Result romfsInitCommon(void) +{ + if (_romfs_read(0, &romFS_header, sizeof(romFS_header)) != sizeof(romFS_header)) + goto _fail0; + + dirHashTable = (u32*)malloc(romFS_header.dirHashTableSize); + if (!dirHashTable) goto _fail0; + if (!_romfs_read_chk(romFS_header.dirHashTableOff, dirHashTable, romFS_header.dirHashTableSize)) goto _fail1; + + dirTable = malloc(romFS_header.dirTableSize); + if (!dirTable) goto _fail1; + if (!_romfs_read_chk(romFS_header.dirTableOff, dirTable, romFS_header.dirTableSize)) goto _fail2; + + fileHashTable = (u32*)malloc(romFS_header.fileHashTableSize); + if (!fileHashTable) goto _fail2; + if (!_romfs_read_chk(romFS_header.fileHashTableOff, fileHashTable, romFS_header.fileHashTableSize)) goto _fail3; + + fileTable = malloc(romFS_header.fileTableSize); + if (!fileTable) goto _fail3; + if (!_romfs_read_chk(romFS_header.fileTableOff, fileTable, romFS_header.fileTableSize)) goto _fail4; + + romFS_cwd = romFS_root; + romFS_active = true; + + AddDevice(&romFS_devoptab); + chdir("romfs:/"); + + return 0; + +_fail4: + free(fileTable); +_fail3: + free(fileHashTable); +_fail2: + free(dirTable); +_fail1: + free(dirHashTable); +_fail0: + FSFILE_Close(romFS_file); + return 10; +} + +Result romfsExit(void) +{ + if (!romFS_active) return 0; + romFS_active = false; + + RemoveDevice("romfs"); + FSFILE_Close(romFS_file); + free(dirHashTable); + free(fileHashTable); + free(dirTable); + free(fileTable); + + return 0; +} + +//----------------------------------------------------------------------------- + +static u32 calcHash(u32 parent, u16* name, u32 namelen, u32 total) +{ + u32 hash = parent ^ 123456789; + u32 i; + for (i = 0; i < namelen; i ++) + { + hash = (hash >> 5) | (hash << 27); + hash ^= name[i]; + } + return hash % total; +} + +static romfs_dir* searchForDir(romfs_dir* parent, u16* name, u32 namelen) +{ + u32 parentOff = (u32)parent - (u32)dirTable; + u32 hash = calcHash(parentOff, name, namelen, romFS_header.dirHashTableSize/4); + romfs_dir* curDir = NULL; + u32 curOff; + for (curOff = dirHashTable[hash]; curOff != romFS_none; curOff = curDir->nextHash) + { + curDir = romFS_dir(curOff); + if (curDir->parent != parentOff) continue; + if (curDir->nameLen != namelen*2) continue; + if (memcmp(curDir->name, name, namelen*2) != 0) continue; + return curDir; + } + return NULL; +} + +static romfs_file* searchForFile(romfs_dir* parent, u16* name, u32 namelen) +{ + u32 parentOff = (u32)parent - (u32)dirTable; + u32 hash = calcHash(parentOff, name, namelen, romFS_header.fileHashTableSize/4); + romfs_file* curFile = NULL; + u32 curOff; + for (curOff = fileHashTable[hash]; curOff != romFS_none; curOff = curFile->nextHash) + { + curFile = romFS_file(curOff); + if (curFile->parent != parentOff) continue; + if (curFile->nameLen != namelen*2) continue; + if (memcmp(curFile->name, name, namelen*2) != 0) continue; + return curFile; + } + return NULL; +} + +static int navigateToDir(romfs_dir** ppDir, const char** pPath, bool isDir) +{ + size_t units; + + char* colonPos = strchr(*pPath, ':'); + if (colonPos) *pPath = colonPos+1; + if (!**pPath) + return EILSEQ; + + *ppDir = romFS_cwd; + if (**pPath == '/') + { + *ppDir = romFS_root; + (*pPath)++; + } + + while (**pPath) + { + char* slashPos = strchr(*pPath, '/'); + char* component = __component; + + if (slashPos) + { + u32 len = slashPos - *pPath; + if (!len) + return EILSEQ; + if (len > PATH_MAX) + return ENAMETOOLONG; + + memcpy(component, *pPath, len); + component[len] = 0; + *pPath = slashPos+1; + } else if (isDir) + { + component = (char*)*pPath; + *pPath += strlen(component); + } else + return 0; + + if (component[0]=='.') + { + if (!component[1]) continue; + if (component[1]=='.' && !component[2]) + { + *ppDir = romFS_dir((*ppDir)->parent); + continue; + } + } + + units = utf8_to_utf16(__utf16path, (const uint8_t*)component, PATH_MAX+1); + if (units == (size_t)-1) + return EILSEQ; + + *ppDir = searchForDir(*ppDir, __utf16path, units); + if (!*ppDir) + return EEXIST; + } + + if (!isDir && !**pPath) + return EILSEQ; + + return 0; +} + +//----------------------------------------------------------------------------- + +int romfs_open(struct _reent *r, void *fileStruct, const char *path, int flags, int mode) +{ + romfs_fileobj* fileobj = (romfs_fileobj*)fileStruct; + + if ((flags & O_ACCMODE) != O_RDONLY) + { + r->_errno = EINVAL; + return -1; + } + + romfs_dir* curDir = NULL; + r->_errno = navigateToDir(&curDir, &path, false); + if (r->_errno != 0) + return -1; + + size_t units = utf8_to_utf16(__utf16path, (const uint8_t*)path, PATH_MAX+1); + if (!units || units == (size_t)-1) + { + r->_errno = EILSEQ; + return -1; + } + + romfs_file* file = searchForFile(curDir, __utf16path, units); + if (!file) + { + r->_errno = EEXIST; + return -1; + } + + fileobj->offset = (u64)romFS_header.fileDataOff + file->dataOff; + fileobj->size = file->dataSize; + fileobj->pos = 0; + + return 0; +} + +int romfs_close(struct _reent *r, int fd) +{ + return 0; +} + +ssize_t romfs_read(struct _reent *r, int fd, char *ptr, size_t len) +{ + romfs_fileobj* file = (romfs_fileobj*)fd; + u64 endPos = file->pos + len; + if (endPos > file->size) + endPos = file->size; + len = endPos - file->pos; + + ssize_t adv = _romfs_read(file->offset + file->pos, ptr, len); + if (adv >= 0) + { + file->pos += adv; + return adv; + } + + r->_errno = EIO; + return -1; +} + +off_t romfs_seek(struct _reent *r, int fd, off_t pos, int dir) +{ + romfs_fileobj* file = (romfs_fileobj*)fd; + switch (dir) + { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->size + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + if (file->pos > file->size) + file->pos = file->size; + return file->pos; +} + +int romfs_fstat(struct _reent *r, int fd, struct stat *st) +{ + romfs_fileobj* file = (romfs_fileobj*)fd; + memset(st, 0, sizeof(struct stat)); + st->st_size = (off_t)file->size; + st->st_nlink = 1; + st->st_mode = S_IFREG | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP | S_IROTH | S_IWOTH; + return 0; +} + +int romfs_stat(struct _reent *r, const char *file, struct stat *st) +{ + r->_errno = ENOTSUP; + return 1; +} + +int romfs_chdir(struct _reent *r, const char *name) +{ + romfs_dir* curDir = NULL; + r->_errno = navigateToDir(&curDir, &name, true); + if (r->_errno != 0) + return -1; + + romFS_cwd = curDir; + return 0; +} + +DIR_ITER* romfs_diropen(struct _reent *r, DIR_ITER *dirState, const char *path) +{ + //romfs_diriter* dir = (romfs_diriter*)(dirState->dirStruct); + r->_errno = ENOTSUP; + return NULL; +} + +int romfs_dirreset(struct _reent *r, DIR_ITER *dirState) +{ + //romfs_diriter* dir = (romfs_diriter*)(dirState->dirStruct); + r->_errno = ENOTSUP; + return 1; +} + +int romfs_dirnext(struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat) +{ + //romfs_diriter* dir = (romfs_diriter*)(dirState->dirStruct); + r->_errno = ENOTSUP; + return 1; +} + +int romfs_dirclose(struct _reent *r, DIR_ITER *dirState) +{ + return 0; +} diff --git a/libctru/source/services/apt.c b/libctru/source/services/apt.c index 41a5228..644f181 100644 --- a/libctru/source/services/apt.c +++ b/libctru/source/services/apt.c @@ -798,6 +798,22 @@ Result APT_GetAppletManInfo(Handle* handle, u8 inval, u8 *outval8, u32 *outval32 return cmdbuf[1]; } +Result APT_GetAppletProgramInfo(Handle* handle, u32 id, u32 flags, u16 *titleversion) +{ + if(!handle)handle=&aptuHandle; + u32* cmdbuf=getThreadCommandBuffer(); + cmdbuf[0]=0x004D0080; //request header code + cmdbuf[1]=id; + cmdbuf[2]=flags; + + Result ret=0; + if((ret=svcSendSyncRequest(*handle)))return ret; + + if(titleversion)*titleversion=cmdbuf[2]; + + return cmdbuf[1]; +} + Result APT_IsRegistered(Handle* handle, NS_APPID appID, u8* out) { if(!handle)handle=&aptuHandle; diff --git a/libctru/source/services/cam.c b/libctru/source/services/cam.c new file mode 100644 index 0000000..ea1ffc5 --- /dev/null +++ b/libctru/source/services/cam.c @@ -0,0 +1,738 @@ +#include <3ds/services/cam.h> +#include <3ds/services/y2r.h> +#include <3ds/srv.h> +#include <3ds/svc.h> +#include <3ds/types.h> + +Handle camHandle; +static bool initialized = false; + +Result camInit() { + Result ret = 0; + + if (initialized) return 0; + + if (camHandle == 0) + { + ret = srvGetServiceHandle(&camHandle, "cam:u"); + if (ret < 0) return ret; + } + + ret = CAMU_DriverInitialize(); + if (ret < 0) return ret; + initialized = true; + + return 0; +} + +Result camExit() { + Result ret = 0; + + if (initialized) + { + ret = CAMU_DriverFinalize(); + if (ret < 0) return ret; + } + + if (camHandle != 0) + { + ret = svcCloseHandle(camHandle); + if (ret < 0) return ret; + camHandle = 0; + } + + return 0; +} + +Result CAMU_StartCapture(CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00010040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_StopCapture(CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00020040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_IsBusy(bool* busy, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00030040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *busy = (bool) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_ClearBuffer(CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00040040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetVsyncInterruptEvent(Handle* event, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00050040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *event = cmdbuf[3]; + return cmdbuf[1]; +} + +Result CAMU_GetBufferErrorInterruptEvent(Handle* event, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00060040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *event = cmdbuf[3]; + return cmdbuf[1]; +} + +Result CAMU_SetReceiving(Handle* event, void* dst, CAMU_Port port, u32 imageSize, s16 transferUnit) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00070102; + cmdbuf[1] = (u32) dst; + cmdbuf[2] = port; + cmdbuf[3] = imageSize; + cmdbuf[4] = transferUnit; + cmdbuf[5] = 0; + cmdbuf[6] = 0xFFFF8001; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *event = cmdbuf[3]; + return cmdbuf[1]; +} + +Result CAMU_IsFinishedReceiving(bool* finishedReceiving, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00080040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *finishedReceiving = (bool) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetTransferLines(CAMU_Port port, s16 lines, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00090100; + cmdbuf[1] = port; + cmdbuf[2] = lines; + cmdbuf[3] = width; + cmdbuf[4] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetMaxLines(s16* maxLines, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000A0080; + cmdbuf[1] = width; + cmdbuf[2] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *maxLines = (s16) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetTransferBytes(CAMU_Port port, u32 bytes, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000B0100; + cmdbuf[1] = port; + cmdbuf[2] = bytes; + cmdbuf[3] = width; + cmdbuf[4] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetTransferBytes(u32* transferBytes, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000C0040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *transferBytes = cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_GetMaxBytes(u32* maxBytes, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000D0080; + cmdbuf[1] = width; + cmdbuf[2] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *maxBytes = cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetTrimming(CAMU_Port port, bool trimming) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000E0080; + cmdbuf[1] = port; + cmdbuf[2] = trimming; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_IsTrimming(bool* trimming, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x000F0040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *trimming = (bool) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetTrimmingParams(CAMU_Port port, s16 xStart, s16 yStart, s16 xEnd, s16 yEnd) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00100140; + cmdbuf[1] = port; + cmdbuf[2] = xStart; + cmdbuf[3] = yStart; + cmdbuf[4] = xEnd; + cmdbuf[5] = yEnd; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetTrimmingParams(s16* xStart, s16* yStart, s16* xEnd, s16* yEnd, CAMU_Port port) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00110040; + cmdbuf[1] = port; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *xStart = (s16) cmdbuf[2]; + *yStart = (s16) cmdbuf[3]; + *xEnd = (s16) cmdbuf[4]; + *yEnd = (s16) cmdbuf[5]; + return cmdbuf[1]; +} + +Result CAMU_SetTrimmingParamsCenter(CAMU_Port port, s16 trimWidth, s16 trimHeight, s16 camWidth, s16 camHeight) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00120140; + cmdbuf[1] = port; + cmdbuf[2] = trimWidth; + cmdbuf[3] = trimHeight; + cmdbuf[4] = camWidth; + cmdbuf[5] = camHeight; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_Activate(CAMU_CameraSelect select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00130040; + cmdbuf[1] = select; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SwitchContext(CAMU_CameraSelect select, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00140080; + cmdbuf[1] = select; + cmdbuf[2] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetExposure(CAMU_CameraSelect select, s8 exposure) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00150080; + cmdbuf[1] = select; + cmdbuf[2] = exposure; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetWhiteBalance(CAMU_CameraSelect select, CAMU_WhiteBalance whiteBalance) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00160080; + cmdbuf[1] = select; + cmdbuf[2] = whiteBalance; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetWhiteBalanceWithoutBaseUp(CAMU_CameraSelect select, CAMU_WhiteBalance whiteBalance) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00170080; + cmdbuf[1] = select; + cmdbuf[2] = whiteBalance; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetSharpness(CAMU_CameraSelect select, s8 sharpness) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00180080; + cmdbuf[1] = select; + cmdbuf[2] = sharpness; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetAutoExposure(CAMU_CameraSelect select, bool autoExposure) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00190080; + cmdbuf[1] = select; + cmdbuf[2] = autoExposure; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_IsAutoExposure(bool* autoExposure, CAMU_CameraSelect select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001A0040; + cmdbuf[1] = select; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *autoExposure = (bool) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetAutoWhiteBalance(CAMU_CameraSelect select, bool autoWhiteBalance) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001B0080; + cmdbuf[1] = select; + cmdbuf[2] = autoWhiteBalance; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_IsAutoWhiteBalance(bool* autoWhiteBalance, CAMU_CameraSelect select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001C0040; + cmdbuf[1] = select; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *autoWhiteBalance = (bool) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_FlipImage(CAMU_CameraSelect select, CAMU_Flip flip, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001D00C0; + cmdbuf[1] = select; + cmdbuf[2] = flip; + cmdbuf[3] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetDetailSize(CAMU_CameraSelect select, s16 width, s16 height, s16 cropX0, s16 cropY0, s16 cropX1, s16 cropY1, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001E0200; + cmdbuf[1] = select; + cmdbuf[2] = width; + cmdbuf[3] = height; + cmdbuf[4] = cropX0; + cmdbuf[5] = cropY0; + cmdbuf[6] = cropX1; + cmdbuf[7] = cropY1; + cmdbuf[8] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetSize(CAMU_CameraSelect select, CAMU_Size size, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x001F00C0; + cmdbuf[1] = select; + cmdbuf[2] = size; + cmdbuf[3] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetFrameRate(CAMU_CameraSelect select, CAMU_FrameRate frameRate) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00200080; + cmdbuf[1] = select; + cmdbuf[2] = frameRate; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetPhotoMode(CAMU_CameraSelect select, CAMU_PhotoMode photoMode) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00210080; + cmdbuf[1] = select; + cmdbuf[2] = photoMode; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetEffect(CAMU_CameraSelect select, CAMU_Effect effect, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002200C0; + cmdbuf[1] = select; + cmdbuf[2] = effect; + cmdbuf[3] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetContrast(CAMU_CameraSelect select, CAMU_Contrast contrast) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00230080; + cmdbuf[1] = select; + cmdbuf[2] = contrast; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetLensCorrection(CAMU_CameraSelect select, CAMU_LensCorrection lensCorrection) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00240080; + cmdbuf[1] = select; + cmdbuf[2] = lensCorrection; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetOutputFormat(CAMU_CameraSelect select, CAMU_OutputFormat format, CAMU_Context context) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002500C0; + cmdbuf[1] = select; + cmdbuf[2] = format; + cmdbuf[3] = context; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetAutoExposureWindow(CAMU_CameraSelect select, s16 x, s16 y, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00260140; + cmdbuf[1] = select; + cmdbuf[2] = x; + cmdbuf[3] = y; + cmdbuf[4] = width; + cmdbuf[5] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetAutoWhiteBalanceWindow(CAMU_CameraSelect select, s16 x, s16 y, s16 width, s16 height) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00270140; + cmdbuf[1] = select; + cmdbuf[2] = x; + cmdbuf[3] = y; + cmdbuf[4] = width; + cmdbuf[5] = height; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetNoiseFilter(CAMU_CameraSelect select, bool noiseFilter) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00280080; + cmdbuf[1] = select; + cmdbuf[2] = noiseFilter; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SynchronizeVsyncTiming(CAMU_CameraSelect select1, CAMU_CameraSelect select2) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00290080; + cmdbuf[1] = select1; + cmdbuf[2] = select2; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetLatestVsyncTiming(s64* timing, CAMU_Port port, u32 past) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002A0080; + cmdbuf[1] = port; + cmdbuf[2] = past; + cmdbuf[49] = (past << 17) | 2; + cmdbuf[50] = (u32) timing; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetStereoCameraCalibrationData(CAMU_StereoCameraCalibrationData* data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002B0000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *data = *(CAMU_StereoCameraCalibrationData*) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetStereoCameraCalibrationData(CAMU_StereoCameraCalibrationData data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002C0400; + *(CAMU_StereoCameraCalibrationData*) cmdbuf[1] = data; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_WriteRegisterI2c(CAMU_CameraSelect select, u16 addr, u16 data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002D00C0; + cmdbuf[1] = select; + cmdbuf[2] = addr; + cmdbuf[3] = data; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_WriteMcuVariableI2c(CAMU_CameraSelect select, u16 addr, u16 data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002E00C0; + cmdbuf[1] = select; + cmdbuf[2] = addr; + cmdbuf[3] = data; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_ReadRegisterI2cExclusive(u16* data, CAMU_CameraSelect select, u16 addr) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x002F0080; + cmdbuf[1] = select; + cmdbuf[2] = addr; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *data = (u16) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_ReadMcuVariableI2cExclusive(u16* data, CAMU_CameraSelect select, u16 addr) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00300080; + cmdbuf[1] = select; + cmdbuf[2] = addr; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *data = (u16) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetImageQualityCalibrationData(CAMU_ImageQualityCalibrationData data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00310180; + *(CAMU_ImageQualityCalibrationData*) cmdbuf[1] = data; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetImageQualityCalibrationData(CAMU_ImageQualityCalibrationData* data) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00320000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *data = *(CAMU_ImageQualityCalibrationData*) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetPackageParameterWithoutContext(CAMU_PackageParameterCameraSelect param) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003302C0; + *(CAMU_PackageParameterCameraSelect*) cmdbuf[1] = param; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetPackageParameterWithContext(CAMU_PackageParameterContext param) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00340140; + *(CAMU_PackageParameterContext*) cmdbuf[1] = param; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetPackageParameterWithContextDetail(CAMU_PackageParameterContextDetail param) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003501C0; + *(CAMU_PackageParameterContextDetail*) cmdbuf[1] = param; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetSuitableY2rStandardCoefficient(Y2R_StandardCoefficient* coefficient) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00360000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *coefficient = (Y2R_StandardCoefficient) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_PlayShutterSound(CAMU_ShutterSoundType sound) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00380040; + cmdbuf[1] = sound; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_DriverInitialize() { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x00390000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_DriverFinalize() { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003A0000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_GetActivatedCamera(CAMU_CameraSelect* select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003B0000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *select = (CAMU_CameraSelect) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_GetSleepCamera(CAMU_CameraSelect* select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003C0000; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + *select = (CAMU_CameraSelect) cmdbuf[2]; + return cmdbuf[1]; +} + +Result CAMU_SetSleepCamera(CAMU_CameraSelect select) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003D0040; + cmdbuf[1] = select; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + +Result CAMU_SetBrightnessSynchronization(bool brightnessSynchronization) { + Result ret = 0; + u32* cmdbuf = getThreadCommandBuffer(); + cmdbuf[0] = 0x003E0040; + cmdbuf[1] = brightnessSynchronization; + + if ((ret = svcSendSyncRequest(camHandle)) != 0) return ret; + return cmdbuf[1]; +} + diff --git a/libctru/source/services/gsp.c b/libctru/source/services/gsp.c index 0234712..4dcfadf 100644 --- a/libctru/source/services/gsp.c +++ b/libctru/source/services/gsp.c @@ -82,6 +82,50 @@ void gspWaitForEvent(GSP_Event id, bool nextEvent) svcClearEvent(gspEvents[id]); } +static int popInterrupt() +{ + int curEvt; + u32 strexFailed; + do { + union { + struct { + u8 cur; + u8 count; + u8 err; + u8 unused; + }; + u32 as_u32; + } header; + + u32* gsp_header_ptr = (u32*)(gspEventData + 0); + + // Do a load on all header fields as an atomic unit + __asm__ volatile ( + "ldrex %[result], %[addr]" : + [result]"=r"(header.as_u32) : + [addr]"Q"(*gsp_header_ptr)); + + if (__builtin_expect(header.count == 0, 0)) { + __asm__ volatile ("clrex"); + return -1; + } + + curEvt = gspEventData[0xC + header.cur]; + + header.cur += 1; + if (header.cur >= 0x34) header.cur -= 0x34; + header.count -= 1; + header.err = 0; // Should this really be set? + + __asm__ volatile ( + "strex %[result], %[val], %[addr]" : + [result]"=&r"(strexFailed), [addr]"=Q"(*gsp_header_ptr) : + [val]"r"(header.as_u32)); + } while (__builtin_expect(strexFailed, 0)); + + return curEvt; +} + void gspEventThreadMain(void *arg) { while (gspRunEvents) @@ -89,24 +133,18 @@ void gspEventThreadMain(void *arg) svcWaitSynchronization(gspEvent, U64_MAX); svcClearEvent(gspEvent); - int count = gspEventData[1]; - int cur = gspEventData[0]; - int last = cur + count; - while (last >= 0x34) last -= 0x34; - int i; - for (i = 0; i < count; i ++) + while (true) { - int curEvt = gspEventData[0xC + cur]; - cur ++; - if (cur >= 0x34) cur -= 0x34; - if (curEvt >= GSPEVENT_MAX) continue; - svcSignalEvent(gspEvents[curEvt]); - gspEventCounts[curEvt]++; - } + int curEvt = popInterrupt(); - gspEventData[0] = last; - gspEventData[1] -= count; - gspEventData[2] = 0; + if (curEvt == -1) + break; + + if (curEvt < GSPEVENT_MAX) { + svcSignalEvent(gspEvents[curEvt]); + gspEventCounts[curEvt]++; + } + } } svcExitThread(); } diff --git a/libctru/source/services/hid.c b/libctru/source/services/hid.c index 8367e8d..7eeb29d 100644 --- a/libctru/source/services/hid.c +++ b/libctru/source/services/hid.c @@ -149,14 +149,14 @@ void hidScanInput() if(Id>7)Id=7; if(hidCheckSectionUpdateTime(&hidSharedMem[66], Id)==0) { - aVec = *(accelVector*)&hidSharedMem[66 + 8 + Id*2]; + aVec = ((accelVector*)&hidSharedMem[66 + 8])[Id]; } Id = hidSharedMem[86 + 4];//Gyroscope if(Id>31)Id=31; if(hidCheckSectionUpdateTime(&hidSharedMem[86], Id)==0) { - gRate = *(angularRate*)&hidSharedMem[86 + 8 + Id*2]; + gRate = ((angularRate*)&hidSharedMem[86 + 8])[Id]; } } diff --git a/libctru/source/services/httpc.c b/libctru/source/services/httpc.c index 8b839e8..c8863e8 100644 --- a/libctru/source/services/httpc.c +++ b/libctru/source/services/httpc.c @@ -95,6 +95,11 @@ Result httpcGetDownloadSizeState(httpcContext *context, u32* downloadedsize, u32 return HTTPC_GetDownloadSizeState(context->servhandle, context->httphandle, downloadedsize, contentsize); } +Result httpcGetResponseHeader(httpcContext *context, char* name, char* value, u32 valuebuf_maxsize) +{ + return HTTPC_GetResponseHeader(context->servhandle, context->httphandle, name, value, valuebuf_maxsize); +} + Result httpcGetResponseStatusCode(httpcContext *context, u32* out, u64 delay) { return HTTPC_GetResponseStatusCode(context->servhandle, context->httphandle, out); @@ -294,6 +299,27 @@ Result HTTPC_GetDownloadSizeState(Handle handle, Handle contextHandle, u32* down return cmdbuf[1]; } +Result HTTPC_GetResponseHeader(Handle handle, Handle contextHandle, char* name, char* value, u32 valuebuf_maxsize) +{ + u32* cmdbuf=getThreadCommandBuffer(); + + int name_len=strlen(name)+1; + + cmdbuf[0]=0x001e00c4; //request header code + cmdbuf[1]=contextHandle; + cmdbuf[2]=name_len; + cmdbuf[3]=valuebuf_maxsize; + cmdbuf[4]=(name_len<<14)|0xC02; + cmdbuf[5]=(u32)name; + cmdbuf[6]=(valuebuf_maxsize<<4)|0xC; + cmdbuf[7]=(u32)value; + + Result ret=0; + if((ret=svcSendSyncRequest(handle)))return ret; + + return cmdbuf[1]; +} + Result HTTPC_GetResponseStatusCode(Handle handle, Handle contextHandle, u32* out) { u32* cmdbuf=getThreadCommandBuffer(); diff --git a/libctru/source/services/soc/soc_common.c b/libctru/source/services/soc/soc_common.c index a610919..d31d9b2 100644 --- a/libctru/source/services/soc/soc_common.c +++ b/libctru/source/services/soc/soc_common.c @@ -4,6 +4,7 @@ Handle SOCU_handle = 0; Handle socMemhandle = 0; +int h_errno = 0; //This is based on the array from libogc network_wii.c. static u8 _net_error_code_map[] = { diff --git a/libctru/source/services/soc/soc_gethostbyaddr.c b/libctru/source/services/soc/soc_gethostbyaddr.c new file mode 100644 index 0000000..7e1a117 --- /dev/null +++ b/libctru/source/services/soc/soc_gethostbyaddr.c @@ -0,0 +1,72 @@ +#include "soc_common.h" +#include + +#define MAX_HOSTENT_RESULTS 16 +static struct hostent SOC_hostent; +static char *SOC_hostent_results[MAX_HOSTENT_RESULTS+1]; +static char *SOC_hostent_alias = NULL; + +struct hostent* gethostbyaddr(const void *addr, socklen_t len, int type) +{ + int ret = 0; + u32 *cmdbuf = getThreadCommandBuffer(); + u32 saved_threadstorage[2]; + static u8 outbuf[0x1A88]; + + h_errno = 0; + + cmdbuf[0] = 0x000E00C2; + cmdbuf[1] = len; + cmdbuf[2] = type; + cmdbuf[3] = sizeof(outbuf); + cmdbuf[4] = (len << 14) | 0x1002; + cmdbuf[5] = (u32)addr; + + saved_threadstorage[0] = cmdbuf[0x100>>2]; + saved_threadstorage[1] = cmdbuf[0x104>>2]; + + cmdbuf[0x100>>2] = (sizeof(outbuf) << 14) | 2; + cmdbuf[0x104>>2] = (u32)outbuf; + + ret = svcSendSyncRequest(SOCU_handle); + if(ret != 0) { + h_errno = NO_RECOVERY; + return NULL; + } + + + cmdbuf[0x100>>2] = saved_threadstorage[0]; + cmdbuf[0x104>>2] = saved_threadstorage[1]; + + ret = (int)cmdbuf[1]; + if(ret == 0) + ret = _net_convert_error(cmdbuf[2]); + + if(ret < 0) { + /* TODO: set h_errno based on ret */ + h_errno = HOST_NOT_FOUND; + return NULL; + } + + u32 num_results, i; + memcpy(&num_results, (char*)outbuf+4, sizeof(num_results)); + if(num_results > MAX_HOSTENT_RESULTS) + num_results = MAX_HOSTENT_RESULTS; + + SOC_hostent.h_name = (char*)outbuf + 8; + SOC_hostent.h_aliases = &SOC_hostent_alias; + SOC_hostent.h_addrtype = AF_INET; + SOC_hostent.h_length = 4; + SOC_hostent.h_addr_list = SOC_hostent_results; + + SOC_hostent_alias = NULL; + + for(i = 0; i < num_results; ++i) + SOC_hostent_results[i] = (char*)outbuf + 0x1908 + i*0x10; + SOC_hostent_results[num_results] = NULL; + + SOC_hostent.h_addr = SOC_hostent.h_addr_list[0]; + + return &SOC_hostent; +} + diff --git a/libctru/source/services/soc/soc_gethostbyname.c b/libctru/source/services/soc/soc_gethostbyname.c index ed712db..2121c3b 100644 --- a/libctru/source/services/soc/soc_gethostbyname.c +++ b/libctru/source/services/soc/soc_gethostbyname.c @@ -6,8 +6,6 @@ static struct hostent SOC_hostent; static char *SOC_hostent_results[MAX_HOSTENT_RESULTS+1]; static char *SOC_hostent_alias = NULL; -int h_errno = 0; - struct hostent* gethostbyname(const char *name) { int ret = 0; @@ -66,5 +64,7 @@ struct hostent* gethostbyname(const char *name) SOC_hostent_results[i] = (char*)outbuf + 0x1908 + i*0x10; SOC_hostent_results[num_results] = NULL; + SOC_hostent.h_addr = SOC_hostent.h_addr_list[0]; + return &SOC_hostent; } diff --git a/libctru/source/srv.c b/libctru/source/srv.c index ca404dd..2243717 100644 --- a/libctru/source/srv.c +++ b/libctru/source/srv.c @@ -30,8 +30,7 @@ typedef struct { extern service_list_t* __service_ptr; -// not static so that apps can actually access it if need be -Handle g_srv_handle = 0; +static Handle g_srv_handle = 0; static int __name_cmp(const char* a, const char* b) { diff --git a/libctru/source/svc.s b/libctru/source/svc.s index ac893ef..427cd81 100644 --- a/libctru/source/svc.s +++ b/libctru/source/svc.s @@ -270,7 +270,7 @@ svcDuplicateHandle: .type svcGetSystemTick, %function svcGetSystemTick: svc 0x28 - bx lr + bx lr .global svcGetSystemInfo .type svcGetSystemInfo, %function @@ -315,7 +315,7 @@ svcConnectToPort: .type svcSendSyncRequest, %function svcSendSyncRequest: svc 0x32 - bx lr + bx lr .global svcOpenProcess .type svcOpenProcess, %function @@ -324,8 +324,7 @@ svcOpenProcess: svc 0x33 pop {r2} str r1, [r2] - bx lr - + bx lr .global svcOpenThread .type svcOpenThread, %function @@ -334,8 +333,7 @@ svcOpenThread: svc 0x34 pop {r2} str r1, [r2] - bx lr - + bx lr .global svcGetProcessId .type svcGetProcessId, %function @@ -346,7 +344,6 @@ svcGetProcessId: str r1, [r3] bx lr - .global svcGetProcessIdOfThread .type svcGetProcessIdOfThread, %function svcGetProcessIdOfThread: @@ -365,6 +362,12 @@ svcGetThreadId: str r1, [r3] bx lr +.global svcBreak +.type svcBreak, %function +svcBreak: + svc 0x3C + bx lr + .global svcOutputDebugString .type svcOutputDebugString, %function svcOutputDebugString: @@ -381,7 +384,66 @@ svcCreatePort: ldr r3, [sp, #4] str r2, [r3] add sp, sp, #8 - bx lr + bx lr + +.global svcAcceptSession +.type svcAcceptSession, %function +svcAcceptSession: + str r0, [sp, #-4]! + svc 0x4A + ldr r2, [sp] + str r1, [r2] + add sp, sp, #4 + bx lr + +.global svcReplyAndReceive +.type svcReplyAndReceive, %function +svcReplyAndReceive: + str r0, [sp, #-4]! + svc 0x4F + ldr r2, [sp] + str r1, [r2] + add sp, sp, #4 + bx lr + +.global svcInvalidateProcessDataCache +.type svcInvalidateProcessDataCache, %function +svcInvalidateProcessDataCache: + svc 0x52 + bx lr + +.global svcFlushProcessDataCache +.type svcFlushProcessDataCache, %function +svcFlushProcessDataCache: + svc 0x54 + bx lr + +.global svcStartInterProcessDma +.type svcStartInterProcessDma, %function +svcStartInterProcessDma: + stmfd sp!, {r0, r4, r5} + ldr r0, [sp, #0xC] + ldr r4, [sp, #0x10] + ldr r5, [sp, #0x14] + svc 0x55 + ldmfd sp!, {r2, r4, r5} + str r1, [r2] + bx lr + +.global svcStopDma +.type svcStopDma, %function +svcStopDma: + svc 0x56 + bx lr + +.global svcGetDmaState +.type svcGetDmaState, %function +svcGetDmaState: + str r0, [sp, #-4]! + svc 0x57 + ldr r3, [sp], #4 + str r1, [r3] + bx lr .global svcDebugActiveProcess .type svcDebugActiveProcess, %function @@ -390,31 +452,31 @@ svcDebugActiveProcess: svc 0x60 pop {r2} str r1, [r2] - bx lr + bx lr .global svcBreakDebugProcess .type svcBreakDebugProcess, %function svcBreakDebugProcess: svc 0x61 - bx lr + bx lr .global svcTerminateDebugProcess .type svcTerminateDebugProcess, %function svcTerminateDebugProcess: svc 0x62 - bx lr + bx lr .global svcGetProcessDebugEvent .type svcGetProcessDebugEvent, %function svcGetProcessDebugEvent: svc 0x63 - bx lr + bx lr .global svcContinueDebugEvent .type svcContinueDebugEvent, %function svcContinueDebugEvent: svc 0x64 - bx lr + bx lr .global svcGetProcessList .type svcGetProcessList, %function @@ -426,13 +488,13 @@ svcGetProcessList: ldr r3, [sp, #4] str r2, [r3] add sp, sp, #8 - bx lr + bx lr .global svcReadProcessMemory .type svcReadProcessMemory, %function svcReadProcessMemory: svc 0x6A - bx lr + bx lr .global svcWriteProcessMemory .type svcWriteProcessMemory, %function @@ -448,25 +510,37 @@ svcControlProcessMemory: ldr r5, [sp, #0xC] svc 0x70 pop {r4-r5} - bx lr + bx lr .global svcMapProcessMemory .type svcMapProcessMemory, %function svcMapProcessMemory: svc 0x71 - bx lr + bx lr .global svcUnmapProcessMemory .type svcUnmapProcessMemory, %function svcUnmapProcessMemory: svc 0x72 - bx lr + bx lr + +.global svcTerminateProcess +.type svcTerminateProcess, %function +svcTerminateProcess: + svc 0x76 + bx lr .global svcBackdoor .type svcBackdoor, %function svcBackdoor: svc 0x7B - bx lr + bx lr + +.global svcKernelSetState +.type svcKernelSetState, %function +svcKernelSetState: + svc 0x7C + bx lr .global svcQueryProcessMemory .type svcQueryProcessMemory, %function @@ -479,4 +553,4 @@ svcQueryProcessMemory: str r5, [r6] add sp, sp, #8 pop {r4-r6} - bx lr + bx lr