diff --git a/.editorconfig b/.editorconfig index 2ee2ca19f1..9d13991864 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,4 +1,4 @@ -# EditorConfig: http://EditorConfig.org +# EditorConfig: https://EditorConfig.org # Top-most EditorConfig file root = true diff --git a/.gitignore b/.gitignore index cec9e0c4fd..485e7b46fe 100644 --- a/.gitignore +++ b/.gitignore @@ -94,7 +94,6 @@ database overlays playlists states -system shaders/shaders_cg shaders/shaders_glsl shaders/shaders_slang @@ -220,7 +219,6 @@ libretro-common/samples/streams/rzip/rzip #VITA param.sfo -*.S *.wo *.elf *.self diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 2cd195ef29..88c203ba46 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -426,6 +426,28 @@ build-retroarch-dingux-odbeta-mips32: - "cp -f libretro-common/audio/dsp_filters/*.dsp ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/audio" - "cp -f gfx/video_filters/*.filt ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/video" +build-retroarch-rs90-odbeta-mips32: + image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-dingux:odbeta + stage: build + variables: + MEDIA_PATH: .media + STRIP_BIN: 1 + before_script: + - export NUMPROC=$(($(nproc)/3)) + artifacts: + paths: + - retroarch + - retroarch_rs90_odbeta.opk + - ${MEDIA_PATH} + expire_in: 10 min + dependencies: [] + script: + - "make -j$NUMPROC -f Makefile.rs90" + - "mkdir -p ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/audio" + - "mkdir -p ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/video" + - "cp -f libretro-common/audio/dsp_filters/*.dsp ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/audio" + - "cp -f gfx/video_filters/*.filt ${MEDIA_PATH}/${CI_PROJECT_NAME}/filters/video" + build-retroarch-android-normal: image: $CI_SERVER_HOST:5050/libretro-infrastructure/libretro-build-android:latest stage: build diff --git a/Makefile.common b/Makefile.common index 5f4654ba33..5b9947dd28 100644 --- a/Makefile.common +++ b/Makefile.common @@ -668,7 +668,7 @@ else ifeq ($(HAVE_BUILTINMBEDTLS), 1) DEFINES += -DMBEDTLS_SSL_DEBUG_ALL endif - # MinGW requires this for some reason, + # MinGW requires this for some reason, # even though the include paths are relative to the source INCLUDE_DIRS += -Ideps/mbedtls @@ -829,7 +829,9 @@ ifeq ($(HAVE_ALSA), 1) ifneq ($(HAVE_HAKCHI), 1) ifneq ($(HAVE_SEGAM), 1) - OBJ += midi/drivers/alsa_midi.o + ifneq ($(DINGUX), 1) + OBJ += midi/drivers/alsa_midi.o + endif endif endif @@ -1574,8 +1576,14 @@ else ifeq ($(HAVE_SDL), 1) else ifeq ($(HAVE_SDL_DINGUX), 1) HAVE_SDL_COMMON = 1 DEF_FLAGS += -DHAVE_SDL -DHAVE_SDL_DINGUX - OBJ += gfx/drivers/sdl_dingux_gfx.o \ - input/drivers/sdl_dingux_input.o \ + + ifeq ($(RS90), 1) + OBJ += gfx/drivers/sdl_rs90_gfx.o + else + OBJ += gfx/drivers/sdl_dingux_gfx.o + endif + + OBJ += input/drivers/sdl_dingux_input.o \ input/drivers_joypad/sdl_dingux_joypad.o DEF_FLAGS += $(SDL_DINGUX_CFLAGS) LIBS += $(SDL_DINGUX_LIBS) @@ -2298,9 +2306,9 @@ ifeq ($(HAVE_CRTSWITCHRES), 1) $(DEPS_DIR)/switchres/resync_windows.o endif ifneq ($(findstring Linux,$(OS)),) - OBJ += $(DEPS_DIR)/switchres/display_linux.o + OBJ += $(DEPS_DIR)/switchres/display_linux.o ifeq ($(HAVE_X11)$(HAVE_XRANDR), 11) - OBJ += $(DEPS_DIR)/switchres/custom_video_xrandr.o + OBJ += $(DEPS_DIR)/switchres/custom_video_xrandr.o DEFINES += -DSR_WITH_XRANDR endif endif @@ -2327,9 +2335,9 @@ ifeq ($(HAVE_COCOA_COMMON),1) OBJ += input/drivers/cocoa_input.o \ ui/drivers/ui_cocoa.o \ ui/drivers/cocoa/cocoa_common.o - + ifeq ($(HAVE_OPENGL), 1) - DEFINES += -DGL_SILENCE_DEPRECATION + DEFINES += -DGL_SILENCE_DEPRECATION OBJ += gfx/drivers_context/cocoa_gl_ctx.o endif ifeq ($(HAVE_VULKAN), 1) @@ -2373,10 +2381,10 @@ endif ifeq ($(WANT_IOSUHAX), 1) DEFINES += -DHAVE_IOSUHAX - INCLUDE_DIRS += -I$(DEPS_DIR)/libiosuhax - OBJ += $(DEPS_DIR)/libiosuhax/iosuhax.o \ - $(DEPS_DIR)/libiosuhax/iosuhax_devoptab.o \ - $(DEPS_DIR)/libiosuhax/iosuhax_disc_interface.o + INCLUDE_DIRS += -I$(DEPS_DIR)/libiosuhax/include + OBJ += $(DEPS_DIR)/libiosuhax/source/iosuhax.o \ + $(DEPS_DIR)/libiosuhax/source/iosuhax_devoptab.o \ + $(DEPS_DIR)/libiosuhax/source/iosuhax_disc_interface.o endif ifeq ($(WANT_LIBFAT), 1) @@ -2484,4 +2492,3 @@ ifeq ($(HAVE_ODROIDGO2), 1) endif ################################## - diff --git a/Makefile.libnx b/Makefile.libnx index f75703b060..efe1f309ef 100644 --- a/Makefile.libnx +++ b/Makefile.libnx @@ -32,6 +32,7 @@ HAVE_RTGA = 1 HAVE_RPNG = 1 HAVE_RJPEG = 1 HAVE_RBMP = 1 +HAVE_7ZIP = 1 HAVE_ZLIB = 1 HAVE_BUILTINZLIB = 1 HAVE_LIBRETRODB = 1 diff --git a/Makefile.ps2 b/Makefile.ps2 index 2877840d3c..7e4f58b2bd 100644 --- a/Makefile.ps2 +++ b/Makefile.ps2 @@ -50,7 +50,7 @@ CFLAGS += $(RARCH_DEFINES) # All the IRX objects EE_OBJS += $(IRX_DIR)/sio2man_irx.o $ $(IRX_DIR)/iomanX_irx.o $(IRX_DIR)/fileXio_irx.o EE_OBJS += $(IRX_DIR)/mcman_irx.o $(IRX_DIR)/mcserv_irx.o -EE_OBJS += $(IRX_DIR)/usbd_irx.o $(IRX_DIR)/usbhdfsd_irx.o +EE_OBJS += $(IRX_DIR)/usbd_irx.o $(IRX_DIR)/bdm_irx.o $(IRX_DIR)/bdmfs_vfat_irx.o $(IRX_DIR)/usbmass_bd_irx.o EE_OBJS += $(IRX_DIR)/libsd_irx.o $(IRX_DIR)/audsrv_irx.o EE_OBJS += $(IRX_DIR)/cdfs_irx.o EE_OBJS += $(IRX_DIR)/mtapman_irx.o $(IRX_DIR)/padman_irx.o diff --git a/Makefile.ps2.salamander b/Makefile.ps2.salamander index 85cdb10895..80ea5b55d0 100644 --- a/Makefile.ps2.salamander +++ b/Makefile.ps2.salamander @@ -61,7 +61,8 @@ EE_OBJS = frontend/frontend_salamander.o \ # Needed IRX objects EE_OBJS += $(IRX_DIR)/sio2man_irx.o $ $(IRX_DIR)/iomanX_irx.o $(IRX_DIR)/fileXio_irx.o -EE_OBJS += $(IRX_DIR)/mcman_irx.o $(IRX_DIR)/mcserv_irx.o $(IRX_DIR)/usbd_irx.o $(IRX_DIR)/usbhdfsd_irx.o +EE_OBJS += $(IRX_DIR)/mcman_irx.o $(IRX_DIR)/mcserv_irx.o +EE_OBJS += $(IRX_DIR)/usbd_irx.o $(IRX_DIR)/bdm_irx.o $(IRX_DIR)/bdmfs_vfat_irx.o $(IRX_DIR)/usbmass_bd_irx.o EE_OBJS += $(IRX_DIR)/cdfs_irx.o EE_CFLAGS = $(CFLAGS) diff --git a/Makefile.psl1ght b/Makefile.psl1ght index 892406cf44..6ce56f09ca 100644 --- a/Makefile.psl1ght +++ b/Makefile.psl1ght @@ -66,7 +66,7 @@ endif SHARED_FLAGS := SHARED_FLAGS += -DHAVE_VIDEO_LAYOUT -SHARED_FLAGS += -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_CHEATS -DRARCH_CONSOLE -DHAVE_OVERLAY -DHAVE_HEADSET -DHAVE_CG -DHAVE_CG_RUNTIME_COMPILER -DHAVE_GCMGL -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_RARCH_EXEC -DHAVE_MOUSE -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_GRIFFIN=1 -DHAVE_NETWORKING=1 -DHAVE_SOCKET_LEGACY=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts -DHAVE_CC_RESAMPLER -DRARCH_INTERNAL -DHAVE_SCREENSHOTS -DHAVE_REWIND -DHAVE_MULTIMAN -DHAVE_RGUI +SHARED_FLAGS += -DHAVE_MENU -DHAVE_CONFIGFILE -DHAVE_PATCH -DHAVE_CHEATS -DRARCH_CONSOLE -DHAVE_OVERLAY -DHAVE_HEADSET -DHAVE_CG -DHAVE_CG_RUNTIME_COMPILER -DHAVE_SYSMODULES -DHAVE_SYSUTILS -DHAVE_RARCH_EXEC -DHAVE_MOUSE -DHAVE_ZLIB -DHAVE_RPNG -DHAVE_GRIFFIN=1 -DHAVE_NETWORKING=1 -DHAVE_SOCKET_LEGACY=1 -DPC_DEVELOPMENT_IP_ADDRESS=\"$(PC_DEVELOPMENT_IP_ADDRESS)\" -DPC_DEVELOPMENT_UDP_PORT=$(PC_DEVELOPMENT_UDP_PORT) -Wno-char-subscripts -DHAVE_CC_RESAMPLER -DRARCH_INTERNAL -DHAVE_SCREENSHOTS -DHAVE_REWIND -DHAVE_MULTIMAN -DHAVE_RGUI CFLAGS += -std=gnu99 $(SHARED_FLAGS) CXXFLAGS += $(SHARED_FLAGS) diff --git a/Makefile.rg350_odbeta b/Makefile.rg350_odbeta index 715d35f963..2ec4e6ce00 100644 --- a/Makefile.rg350_odbeta +++ b/Makefile.rg350_odbeta @@ -45,8 +45,7 @@ HAVE_SCREENSHOTS = 0 HAVE_REWIND = 1 HAVE_7ZIP = 1 HAVE_AL = 1 -# ALSA freezes when switching back from menu -HAVE_ALSA = 0 +HAVE_ALSA = 1 HAVE_DSP_FILTER = 1 HAVE_VIDEO_FILTER = 1 HAVE_STATIC_VIDEO_FILTERS = 1 @@ -121,6 +120,7 @@ DEF_FLAGS += -ffunction-sections -fdata-sections DEF_FLAGS += -I. -Ideps -Ideps/stb -DDINGUX=1 -DDINGUX_BETA=1 -MMD DEF_FLAGS += -Wall -Wno-unused-variable DEF_FLAGS += -std=gnu99 -D_GNU_SOURCE -flto +DEF_FLAGS += -lasound LIBS := -ldl -lz -lrt -ludev -pthread CFLAGS := CXXFLAGS := -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS @@ -134,6 +134,7 @@ DEFINES += -DHAVE_GETOPT_LONG=1 -DHAVE_STRCASESTR=1 -DHAVE_DYNAMIC=1 DEFINES += -DHAVE_AL=1 DEFINES += -DHAVE_FILTERS_BUILTIN DEFINES += -DHAVE_UDEV=1 +DEFINES += -DHAVE_ALSA SDL_DINGUX_CFLAGS := $(shell $(GCW0_SDL_CONFIG) --cflags) SDL_DINGUX_LIBS := $(shell $(GCW0_SDL_CONFIG) --libs) diff --git a/Makefile.rs90 b/Makefile.rs90 new file mode 100644 index 0000000000..7b5f2b1d18 --- /dev/null +++ b/Makefile.rs90 @@ -0,0 +1,234 @@ +######################### +## Toolchain variables ## +######################### + +# Alpha toolchain +TOOLCHAIN_DIR=/opt/rs90-toolchain + +# All toolchain-related variables may be +# overridden via the command line +ifdef GCW0_CC +CC = $(GCW0_CC) +else +CC = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-gcc +endif + +ifdef GCW0_CXX +CXX = $(GCW0_CXX) +else +CXX = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-g++ +endif + +ifdef GCW0_STRIP +STRIP = $(GCW0_STRIP) +else +STRIP = $(TOOLCHAIN_DIR)/usr/bin/mipsel-rs90-linux-musl-strip +endif + +GCW0_SDL_CONFIG ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/bin/sdl-config +GCW0_FREETYPE_CONFIG ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/bin/freetype-config +GCW0_MK_SQUASH_FS ?= $(TOOLCHAIN_DIR)/usr/bin/mksquashfs + +GCW0_INC_DIR ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/include +GCW0_LIB_DIR ?= $(TOOLCHAIN_DIR)/usr/mipsel-rs90-linux-musl/sysroot/usr/lib + +######################### +######################### + +PACKAGE_NAME = retroarch + +DEBUG ?= 0 + +RS90 = 1 +DINGUX = 1 +DINGUX_BETA = 1 +HAVE_SCREENSHOTS = 0 +HAVE_REWIND = 0 +HAVE_7ZIP = 1 +HAVE_AL = 0 +HAVE_ALSA = 1 +HAVE_DSP_FILTER = 1 +HAVE_VIDEO_FILTER = 1 +HAVE_STATIC_VIDEO_FILTERS = 1 +HAVE_STATIC_AUDIO_FILTERS = 1 +HAVE_FILTERS_BUILTIN = 1 +HAVE_BUILTINMBEDTLS = 0 +HAVE_BUILTINZLIB = 1 +HAVE_C99 = 1 +HAVE_CC = 1 +HAVE_CC_RESAMPLER = 1 + +HAVE_CHD = 0 +HAVE_COMMAND = 0 +HAVE_CXX = 1 +HAVE_DR_MP3 = 0 +HAVE_DYNAMIC = 1 +HAVE_EGL = 0 +HAVE_FREETYPE = 0 +HAVE_GDI = 0 +HAVE_GETADDRINFO = 0 +HAVE_GETOPT_LONG = 1 +HAVE_GLSL = 0 +HAVE_HID = 0 +HAVE_IBXM = 0 +HAVE_IMAGEVIEWER = 0 +HAVE_LANGEXTRA = 0 +HAVE_LIBRETRODB = 1 +HAVE_MENU = 1 +HAVE_MENU_COMMON = 1 +HAVE_GFX_WIDGETS = 0 +HAVE_MMAP = 1 +HAVE_OPENDINGUX_FBDEV = 0 +HAVE_OPENGL = 0 +HAVE_OPENGL1 = 0 +HAVE_OPENGLES = 0 +HAVE_OPENGLES3 = 0 +HAVE_OPENGL_CORE = 0 +HAVE_OPENSSL = 0 +HAVE_OVERLAY = 0 +HAVE_RBMP = 1 +HAVE_RJPEG = 1 +HAVE_RPILED = 0 +HAVE_RPNG = 1 +HAVE_RUNAHEAD = 0 +HAVE_SDL_DINGUX = 1 +HAVE_SHADERPIPELINE = 0 +HAVE_STB_FONT = 0 +HAVE_STB_IMAGE = 0 +HAVE_STB_VORBIS = 0 +HAVE_STDIN_CMD = 0 +HAVE_STRCASESTR = 1 +HAVE_THREADS = 1 +HAVE_UDEV = 1 +HAVE_RGUI = 1 +HAVE_MATERIALUI = 0 +HAVE_XMB = 0 +HAVE_OZONE = 0 +HAVE_ZLIB = 1 +HAVE_CONFIGFILE = 1 +HAVE_PATCH = 1 +HAVE_CHEATS = 1 +HAVE_CHEEVOS = 0 +HAVE_LIBSHAKE = 0 +HAVE_TINYALSA = 1 +HAVE_NEAREST_RESAMPLER = 1 + +OS = Linux +TARGET = retroarch +OPK_NAME = retroarch_rs90_odbeta.opk + +OBJ := +LINK := $(CXX) +DEF_FLAGS := -mplt -mno-shared +DEF_FLAGS += -ffunction-sections -fdata-sections +DEF_FLAGS += -I. -Ideps -Ideps/stb -DRS90=1 -DDINGUX=1 -DDINGUX_BETA=1 -MMD +DEF_FLAGS += -Wall -Wno-unused-variable +DEF_FLAGS += -std=gnu99 -D_GNU_SOURopendinguxCE -flto -lasound +LIBS := -ldl -lz -lrt -ludev -pthread +CFLAGS := +CXXFLAGS := -fno-exceptions -fno-rtti -std=c++11 -D__STDC_CONSTANT_MACROS +ASFLAGS := +LDFLAGS := -Wl,--gc-sections +INCLUDE_DIRS = -I$(GCW0_INC_DIR) +LIBRARY_DIRS = -L$(GCW0_LIB_DIR) +DEFINES := -DRARCH_INTERNAL -D_FILE_OFFSET_BITS=64 -UHAVE_STATIC_DUMMY +DEFINES += -DHAVE_C99=1 -DHAVE_CXX=1 +DEFINES += -DHAVE_GETOPT_LONG=1 -DHAVE_STRCASESTR=1 -DHAVE_DYNAMIC=1 +DEFINES += -DHAVE_FILTERS_BUILTIN +DEFINES += -DHAVE_UDEV=1 +DEFINES += -DHAVE_ALSA +DEFINES += -DCC_RESAMPLER_PRECISION=0 + +SDL_DINGUX_CFLAGS := $(shell $(GCW0_SDL_CONFIG) --cflags) +SDL_DINGUX_LIBS := $(shell $(GCW0_SDL_CONFIG) --libs) +FREETYPE_CFLAGS := $(shell $(GCW0_FREETYPE_CONFIG) --cflags) +FREETYPE_LIBS := $(shell $(GCW0_FREETYPE_CONFIG) --libs) +MMAP_LIBS = -lc + +OBJDIR_BASE := obj-unix + +ifeq ($(DEBUG), 1) + OBJDIR := $(OBJDIR_BASE)/debug + DEF_FLAGS += -O0 -g -DDEBUG -D_DEBUG +else + OBJDIR := $(OBJDIR_BASE)/release + DEF_FLAGS += -Ofast -DNDEBUG +endif + +include Makefile.common + +DEF_FLAGS += $(INCLUDE_DIRS) +LDFLAGS += $(CFLAGS) $(CXXFLAGS) $(DEF_FLAGS) +CFLAGS += $(DEF_FLAGS) +CXXFLAGS += $(DEF_FLAGS) + +HEADERS = $(wildcard */*/*.h) $(wildcard */*.h) $(wildcard *.h) + +Q := @ + +RARCH_OBJ := $(addprefix $(OBJDIR)/,$(OBJ)) + +define DESKTOP_ENTRY +[Desktop Entry] +Name=RetroArch +Comment=Frontend for emulators, game engines +Exec=retroarch +Terminal=false +Type=Application +StartupNotify=true +Icon=retroarch +Categories=emulators; +X-OD-NeedsDownscaling=true +endef +export DESKTOP_ENTRY + +all: $(TARGET) opk + +-include $(RARCH_OBJ:.o=.d) + +SYMBOL_MAP := -Wl,-Map=output.map + +$(TARGET): $(RARCH_OBJ) + @$(if $(Q), $(shell echo echo LD $@),) + $(Q)$(LINK) -o $@ $(RARCH_OBJ) $(LIBS) $(LDFLAGS) $(LIBRARY_DIRS) + +$(OBJDIR)/%.o: %.c + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo CC $<),) + $(Q)$(CC) $(CPPFLAGS) $(CFLAGS) $(DEFINES) -c -o $@ $< + +$(OBJDIR)/%.o: %.cpp + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo CXX $<),) + $(Q)$(CXX) $(CPPFLAGS) $(CXXFLAGS) $(DEFINES) -MMD -c -o $@ $< + +$(OBJDIR)/%.o: %.m + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo OBJC $<),) + $(Q)$(CXX) $(OBJCFLAGS) $(DEFINES) -MMD -c -o $@ $< + +$(OBJDIR)/%.o: %.S $(HEADERS) + @mkdir -p $(dir $@) + @$(if $(Q), $(shell echo echo AS $<),) + $(Q)$(CC) $(CFLAGS) $(ASFLAGS) $(DEFINES) -c -o $@ $< + +clean: + rm -rf $(OBJDIR_BASE) + rm -f $(TARGET) + rm -f *.d + rm -rf $(OPK_NAME) + +opk: $(TARGET) + echo "$$DESKTOP_ENTRY" > default.rs90.desktop + rm -f $(OPK_NAME) + cp media/ico_src/icon32.png retroarch.png +ifeq ($STRIP_BIN, 1) + $(STRIP) --strip-unneeded retroarch +endif + $(GCW0_MK_SQUASH_FS) retroarch default.rs90.desktop retroarch.png $(OPK_NAME) -all-root -no-xattrs -noappend -no-exports + rm -f default.rs90.desktop retroarch.png + +.PHONY: all clean opk + +print-%: + @echo '$*=$($*)' diff --git a/Makefile.vita b/Makefile.vita index 74766e1283..c42b7a8ea3 100644 --- a/Makefile.vita +++ b/Makefile.vita @@ -112,7 +112,11 @@ LD := $(CXX) LIBDIRS := -L. -ARCHFLAGS := -march=armv7-a -mfpu=neon -mfloat-abi=hard -DVITA -DSCE_LIBC_SIZE=$(SCE_LIBC_SIZE) +ARCHFLAGS := -march=armv7-a -mfpu=neon -mfloat-abi=hard -DVITA +ifeq ($(HAVE_VITAGLES), 1) + ARCHFLAGS += -DSCE_LIBC_SIZE=$(SCE_LIBC_SIZE) +endif + CFLAGS += $(ARCHFLAGS) -mword-relocations -fno-optimize-sibling-calls ifeq ($(DEBUG), 1) diff --git a/Makefile.wiiu b/Makefile.wiiu index 55a0dd93cc..c565db262c 100644 --- a/Makefile.wiiu +++ b/Makefile.wiiu @@ -102,7 +102,7 @@ endif INCDIRS += -Ilibretro-common/include/compat/zlib # for stb, libfat, iosuhax - INCDIRS += -Ideps -Ideps/libfat/include -Ideps/libiosuhax + INCDIRS += -Ideps -Ideps/libfat/include -Ideps/libiosuhax/include # pad_functions uses wiiu/input.h INCDIRS += -Iinput/include INCDIRS += -Ideps/SPIRV-Cross diff --git a/config.def.h b/config.def.h index d2f2846bf9..2b1fc5824a 100644 --- a/config.def.h +++ b/config.def.h @@ -201,16 +201,21 @@ /* To start in Fullscreen, or not. */ -#if defined(HAVE_STEAM) || defined(DINGUX) -/* Start in fullscreen mode for Steam and - * Dingux builds */ +#if defined(HAVE_STEAM) || defined(DINGUX) || defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +/* Start in fullscreen mode for Steam and Dingux + * WinRT and Winapi Family builds */ #define DEFAULT_FULLSCREEN true #else #define DEFAULT_FULLSCREEN false #endif /* To use windowed mode or not when going fullscreen. */ -#define DEFAULT_WINDOWED_FULLSCREEN true +#if defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +/* Do not use windowed mode for WinRT and Winapi Family builds on the Xbox UWP with fixed resolution shrinks the image into the left top corner of the screen with some libretro cores */ +#define DEFAULT_WINDOWED_FULLSCREEN false +#else +#define DEFAULT_WINDOWED_FULLSCREEN true +#endif /* Which monitor to prefer. 0 is any monitor, 1 and up selects * specific monitors, 1 being the first monitor. */ @@ -227,6 +232,9 @@ #if defined(DINGUX) #define DEFAULT_FULLSCREEN_X 320 #define DEFAULT_FULLSCREEN_Y 240 +#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +#define DEFAULT_FULLSCREEN_X 1920 +#define DEFAULT_FULLSCREEN_Y 1080 #else #define DEFAULT_FULLSCREEN_X 0 #define DEFAULT_FULLSCREEN_Y 0 @@ -380,8 +388,10 @@ /* Only scale in integer steps. * The base size depends on system-reported geometry and aspect ratio. * If video_force_aspect is not set, X/Y will be integer scaled independently. + * Overscale rounds up instead of down, default is downscale. */ #define DEFAULT_SCALE_INTEGER false +#define DEFAULT_SCALE_INTEGER_OVERSCALE false /* Controls aspect ratio handling. */ @@ -410,6 +420,11 @@ * in Dingux devices */ #define DEFAULT_DINGUX_REFRESH_RATE DINGUX_REFRESH_RATE_60HZ #endif +#if defined(RS90) +/* Sets image filtering method on the RS90 + * when integer scaling is disabled */ +#define DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE DINGUX_RS90_SOFTFILTER_POINT +#endif #endif /* Save configuration file on exit. */ @@ -729,7 +744,9 @@ static const bool default_savefiles_in_content_dir = false; static const bool default_systemfiles_in_content_dir = false; static const bool default_screenshots_in_content_dir = false; -#if defined(_XBOX1) || defined(__PS3__) || defined(_XBOX360) || defined(DINGUX) +#if defined(RS90) +#define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_START_SELECT +#elif defined(_XBOX1) || defined(__PS3__) || defined(_XBOX360) || defined(DINGUX) #define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_L3_R3 #elif defined(PS2) || defined(PSP) #define DEFAULT_MENU_TOGGLE_GAMEPAD_COMBO INPUT_TOGGLE_HOLD_START @@ -1312,6 +1329,14 @@ static const unsigned menu_left_thumbnails_default = 0; static const unsigned gfx_thumbnail_upscale_threshold = 0; #ifdef HAVE_MENU +#if defined(RS90) +/* The RS-90 has a hardware clock that is neither + * configurable nor persistent, rendering it useless. + * We therefore hide it in the menu by default. */ +#define DEFAULT_MENU_TIMEDATE_ENABLE false +#else +#define DEFAULT_MENU_TIMEDATE_ENABLE true +#endif #define DEFAULT_MENU_TIMEDATE_STYLE MENU_TIMEDATE_STYLE_DDMM_HM #define DEFAULT_MENU_TIMEDATE_DATE_SEPARATOR MENU_TIMEDATE_DATE_SEPARATOR_HYPHEN #endif diff --git a/configuration.c b/configuration.c index 174894e41b..f16b9fb541 100644 --- a/configuration.c +++ b/configuration.c @@ -70,6 +70,7 @@ enum video_driver_enum VIDEO_SDL, VIDEO_SDL2, VIDEO_SDL_DINGUX, + VIDEO_SDL_RS90, VIDEO_EXT, VIDEO_WII, VIDEO_WIIU, @@ -260,6 +261,9 @@ static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GL; #else static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_METAL; #endif +#elif defined(__WINRT__) || defined(WINAPI_FAMILY) && WINAPI_FAMILY == WINAPI_FAMILY_PHONE_APP +/* Lets default to D3D11 in UWP, even when its compiled with ANGLE, since ANGLE is just calling D3D anyway.*/ +static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_D3D11; #elif defined(HAVE_OPENGL1) && defined(_MSC_VER) && (_MSC_VER <= 1600) /* On Windows XP and earlier, use gl1 by default * (regular opengl has compatibility issues with @@ -308,7 +312,11 @@ static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL; #elif defined(HAVE_SDL2) static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL2; #elif defined(HAVE_SDL_DINGUX) +#if defined(RS90) +static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL_RS90; +#else static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_SDL_DINGUX; +#endif #elif defined(_WIN32) && !defined(_XBOX) static const enum video_driver_enum VIDEO_DEFAULT_DRIVER = VIDEO_GDI; #elif defined(DJGPP) @@ -339,6 +347,10 @@ static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_PS3; static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_CTR; #elif defined(SWITCH) static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_SWITCH; +#elif defined(DINGUX_BETA) && defined(HAVE_ALSA) +static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_ALSA; +#elif defined(DINGUX) && defined(HAVE_AL) +static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_AL; #elif defined(HAVE_PULSE) static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_PULSE; #elif defined(HAVE_ALSA) && defined(HAVE_THREADS) @@ -383,7 +395,9 @@ static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_EXT; static const enum audio_driver_enum AUDIO_DEFAULT_DRIVER = AUDIO_NULL; #endif -#if defined(PSP) || defined(EMSCRIPTEN) +#if defined(RS90) +static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_NEAREST; +#elif defined(PSP) || defined(EMSCRIPTEN) static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_CC; #else static const enum audio_resampler_driver_enum AUDIO_DEFAULT_RESAMPLER_DRIVER = AUDIO_RESAMPLER_SINC; @@ -397,7 +411,7 @@ static const enum record_driver_enum RECORD_DEFAULT_DRIVER = RECORD_NULL; #ifdef HAVE_WINMM static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_WINMM; -#elif defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) +#elif defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) && !defined(DINGUX) static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_ALSA; #else static const enum midi_driver_enum MIDI_DEFAULT_DRIVER = MIDI_NULL; @@ -847,6 +861,8 @@ const char *config_get_default_video(void) return "xvideo"; case VIDEO_SDL_DINGUX: return "sdl_dingux"; + case VIDEO_SDL_RS90: + return "sdl_rs90"; case VIDEO_SDL: return "sdl"; case VIDEO_SDL2: @@ -1530,6 +1546,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("video_windowed_fullscreen", &settings->bools.video_windowed_fullscreen, true, DEFAULT_WINDOWED_FULLSCREEN, false); SETTING_BOOL("video_crop_overscan", &settings->bools.video_crop_overscan, true, DEFAULT_CROP_OVERSCAN, false); SETTING_BOOL("video_scale_integer", &settings->bools.video_scale_integer, true, DEFAULT_SCALE_INTEGER, false); + SETTING_BOOL("video_scale_integer_overscale", &settings->bools.video_scale_integer_overscale, true, DEFAULT_SCALE_INTEGER_OVERSCALE, false); SETTING_BOOL("video_smooth", &settings->bools.video_smooth, true, DEFAULT_VIDEO_SMOOTH, false); SETTING_BOOL("video_ctx_scaling", &settings->bools.video_ctx_scaling, true, DEFAULT_VIDEO_CTX_SCALING, false); SETTING_BOOL("video_force_aspect", &settings->bools.video_force_aspect, true, DEFAULT_FORCE_ASPECT, false); @@ -1610,7 +1627,7 @@ static struct config_bool_setting *populate_settings_bool( SETTING_BOOL("menu_insert_disk_resume", &settings->bools.menu_insert_disk_resume, true, DEFAULT_MENU_INSERT_DISK_RESUME, false); SETTING_BOOL("menu_mouse_enable", &settings->bools.menu_mouse_enable, true, DEFAULT_MOUSE_ENABLE, false); SETTING_BOOL("menu_pointer_enable", &settings->bools.menu_pointer_enable, true, DEFAULT_POINTER_ENABLE, false); - SETTING_BOOL("menu_timedate_enable", &settings->bools.menu_timedate_enable, true, true, false); + SETTING_BOOL("menu_timedate_enable", &settings->bools.menu_timedate_enable, true, DEFAULT_MENU_TIMEDATE_ENABLE, false); SETTING_BOOL("menu_battery_level_enable", &settings->bools.menu_battery_level_enable, true, true, false); SETTING_BOOL("menu_core_enable", &settings->bools.menu_core_enable, true, true, false); SETTING_BOOL("menu_show_sublabels", &settings->bools.menu_show_sublabels, true, menu_show_sublabels, false); @@ -2120,6 +2137,9 @@ static struct config_uint_setting *populate_settings_uint( #if defined(DINGUX_BETA) SETTING_UINT("video_dingux_refresh_rate", &settings->uints.video_dingux_refresh_rate, true, DEFAULT_DINGUX_REFRESH_RATE, false); #endif +#if defined(RS90) + SETTING_UINT("video_dingux_rs90_softfilter_type", &settings->uints.video_dingux_rs90_softfilter_type, true, DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE, false); +#endif #endif #ifdef HAVE_MENU diff --git a/configuration.h b/configuration.h index 29f52bfd2e..b5b326cc9e 100644 --- a/configuration.h +++ b/configuration.h @@ -209,6 +209,7 @@ typedef struct settings unsigned video_3ds_display_mode; unsigned video_dingux_ipu_filter_type; unsigned video_dingux_refresh_rate; + unsigned video_dingux_rs90_softfilter_type; #ifdef HAVE_VIDEO_LAYOUT unsigned video_layout_selected_view; #endif @@ -497,6 +498,7 @@ typedef struct settings bool video_aspect_ratio_auto; bool video_dingux_ipu_keep_aspect; bool video_scale_integer; + bool video_scale_integer_overscale; bool video_shader_enable; bool video_shader_watch_files; bool video_shader_remember_last_dir; diff --git a/core_info.c b/core_info.c index 69075fe98f..ea2ab05201 100644 --- a/core_info.c +++ b/core_info.c @@ -732,17 +732,18 @@ end: return core_info_cache_list; } -static void core_info_cache_write(core_info_cache_list_t *list, const char *info_dir) +static bool core_info_cache_write(core_info_cache_list_t *list, const char *info_dir) { intfstream_t *file = NULL; rjsonwriter_t *writer = NULL; + bool success = false; char file_path[PATH_MAX_LENGTH]; size_t i, j; file_path[0] = '\0'; if (!list) - return; + return false; /* Open info cache file */ if (string_is_empty(info_dir)) @@ -763,7 +764,7 @@ static void core_info_cache_write(core_info_cache_list_t *list, const char *info if (!file) { RARCH_ERR("[Core Info] Failed to write to core info cache file: %s\n", file_path); - return; + return false; } /* Write info cache */ @@ -1068,6 +1069,7 @@ static void core_info_cache_write(core_info_cache_list_t *list, const char *info rjsonwriter_free(writer); RARCH_LOG("[Core Info] Wrote to cache file: %s\n", file_path); + success = true; /* Remove 'force refresh' file, if required */ file_path[0] = '\0'; @@ -1086,6 +1088,7 @@ end: free(file); list->refresh = false; + return success; } static void core_info_check_uninstalled(core_info_cache_list_t *list) @@ -1774,7 +1777,8 @@ static core_info_list_t *core_info_list_new(const char *path, const char *libretro_info_dir, const char *exts, bool dir_show_hidden_files, - bool enable_cache) + bool enable_cache, + bool *cache_supported) { size_t i; core_path_list_t *path_list = NULL; @@ -1906,12 +1910,14 @@ static core_info_list_t *core_info_list_new(const char *path, * a refresh) * > Write new cache to disk if updates are * required */ + *cache_supported = true; if (core_info_cache_list) { core_info_check_uninstalled(core_info_cache_list); if (core_info_cache_list->refresh) - core_info_cache_write(core_info_cache_list, info_dir); + *cache_supported = core_info_cache_write( + core_info_cache_list, info_dir); core_info_cache_list_free(core_info_cache_list); } @@ -2104,14 +2110,16 @@ void core_info_deinit_list(void) } bool core_info_init_list(const char *path_info, const char *dir_cores, - const char *exts, bool dir_show_hidden_files, bool enable_cache) + const char *exts, bool dir_show_hidden_files, + bool enable_cache, bool *cache_supported) { core_info_state_t *p_coreinfo = coreinfo_get_ptr(); if (!(p_coreinfo->curr_list = core_info_list_new(dir_cores, !string_is_empty(path_info) ? path_info : dir_cores, exts, dir_show_hidden_files, - enable_cache))) + enable_cache, + cache_supported))) return false; return true; } diff --git a/core_info.h b/core_info.h index 7cb286abff..ae9a7f28ab 100644 --- a/core_info.h +++ b/core_info.h @@ -157,7 +157,8 @@ bool core_info_get_current_core(core_info_t **core); void core_info_deinit_list(void); bool core_info_init_list(const char *path_info, const char *dir_cores, - const char *exts, bool show_hidden_files, bool enable_cache); + const char *exts, bool show_hidden_files, + bool enable_cache, bool *cache_supported); bool core_info_get_list(core_info_list_t **core); diff --git a/deps/libfat/common.h b/deps/libfat/common.h index b38889ee5f..66ca7bf77e 100644 --- a/deps/libfat/common.h +++ b/deps/libfat/common.h @@ -63,8 +63,8 @@ /* Platform specific options */ #if defined (__wiiu__) - #define DEFAULT_CACHE_PAGES 4 - #define DEFAULT_SECTORS_PAGE 64 + #define DEFAULT_CACHE_PAGES 512 + #define DEFAULT_SECTORS_PAGE 128 #if 0 #define USE_LWP_LOCK #define USE_RTC_TIME diff --git a/deps/libiosuhax/.github/workflows/push_image.yml b/deps/libiosuhax/.github/workflows/push_image.yml new file mode 100644 index 0000000000..9cd7bbdb42 --- /dev/null +++ b/deps/libiosuhax/.github/workflows/push_image.yml @@ -0,0 +1,25 @@ +name: Publish Docker Image +on: + push: + branches: + - master +jobs: + build: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@master + - name: Get release version + id: get_release_tag + run: | + echo RELEASE_VERSION=$(echo $(date '+%Y%m%d')) >> $GITHUB_ENV + echo REPOSITORY_NAME=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $2}' | sed -e "s/:refs//" | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV + echo REPOSITORY_OWNER=$(echo "$GITHUB_REPOSITORY" | awk -F / '{print $1}' | sed 's/[^a-zA-Z0-9]//g' | tr '[:upper:]' '[:lower:]') >> $GITHUB_ENV + - name: Publish to Registry + uses: elgohr/Publish-Docker-Github-Action@master + with: + name: ${{ env.REPOSITORY_OWNER }}/${{ env.REPOSITORY_NAME }} + username: ${{ secrets.DOCKER_USERNAME }} + password: ${{ secrets.DOCKER_PASSWORD }} + snapshot: true + cache: true + tags: "latest, ${{ env.RELEASE_VERSION }}" \ No newline at end of file diff --git a/deps/libiosuhax/.gitignore b/deps/libiosuhax/.gitignore new file mode 100644 index 0000000000..0955c90e6e --- /dev/null +++ b/deps/libiosuhax/.gitignore @@ -0,0 +1,5 @@ +/*.a +/build +*.bz2 +release/ +lib/ diff --git a/deps/libiosuhax/.travis.yml b/deps/libiosuhax/.travis.yml new file mode 100644 index 0000000000..ff1f980eaa --- /dev/null +++ b/deps/libiosuhax/.travis.yml @@ -0,0 +1,29 @@ +language: cpp + +os: linux +sudo: false +dist: trusty + +env: + global: + - DEVKITPRO=/opt/devkitpro + - DEVKITPPC=/opt/devkitpro/devkitPPC + +cache: + directories: + - "$HOME/.local" + - "$DEVKITPRO" + +addons: + apt: + packages: + - p7zip-full + +before_install: + - mkdir -p "${DEVKITPRO}" + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then wget https://github.com/devkitPro/pacman/releases/download/devkitpro-pacman-1.0.1/devkitpro-pacman.deb -O /tmp/devkitpro-pacman.deb; fi + - if [[ "$TRAVIS_OS_NAME" == "linux" ]]; then sudo dpkg -i /tmp/devkitpro-pacman.deb; fi + - yes | sudo dkp-pacman -Syu devkitPPC --needed + +script: + - make && make install \ No newline at end of file diff --git a/deps/libiosuhax/Dockerfile b/deps/libiosuhax/Dockerfile new file mode 100644 index 0000000000..27aa8936e8 --- /dev/null +++ b/deps/libiosuhax/Dockerfile @@ -0,0 +1,9 @@ +FROM wiiuenv/devkitppc:20210101 + +WORKDIR tmp_build +COPY . . +RUN make clean && make && mkdir -p /artifacts/wut/usr && cp -r lib /artifacts/wut/usr && cp -r include /artifacts/wut/usr +WORKDIR /artifacts + +FROM scratch +COPY --from=0 /artifacts /artifacts \ No newline at end of file diff --git a/deps/libiosuhax/Makefile b/deps/libiosuhax/Makefile new file mode 100644 index 0000000000..03af789f3d --- /dev/null +++ b/deps/libiosuhax/Makefile @@ -0,0 +1,157 @@ +#------------------------------------------------------------------------------- +.SUFFIXES: +#------------------------------------------------------------------------------- + +ifeq ($(strip $(DEVKITPRO)),) +$(error "Please set DEVKITPRO in your environment. export DEVKITPRO=/devkitpro") +endif + +TOPDIR ?= $(CURDIR) + +include $(DEVKITPRO)/wut/share/wut_rules + +export VER_MAJOR := 1 +export VER_MINOR := 0 +export VER_PATCH := 0 + +VERSION := $(VER_MAJOR).$(VER_MINOR).$(VER_PATCH) + +#------------------------------------------------------------------------------- +# 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 +#------------------------------------------------------------------------------- +TARGET := $(notdir $(CURDIR)) +BUILD := build +SOURCES := source +DATA := data +INCLUDES := source \ + include \ + +#--------------------------------------------------------------------------------- +# options for code generation +#--------------------------------------------------------------------------------- +CFLAGS := -Wall -Werror -save-temps \ + -ffunction-sections -fdata-sections \ + $(MACHDEP) \ + $(BUILD_CFLAGS) + +CFLAGS += $(INCLUDE) -D__WIIU__ -D__WUT__ + +CXXFLAGS := $(CFLAGS) -std=gnu++17 + +ASFLAGS := $(MACHDEP) + +LDFLAGS = $(ARCH) -Wl,--gc-sections + + +LIBS := + +#--------------------------------------------------------------------------------- +# list of directories containing libraries, this must be the top level containing +# include and lib +#--------------------------------------------------------------------------------- +LIBDIRS := $(PORTLIBS) $(WUT_ROOT) + +#--------------------------------------------------------------------------------- +# 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 TOPDIR := $(CURDIR) + +export VPATH := $(foreach dir,$(SOURCES),$(CURDIR)/$(dir)) \ + $(foreach dir,$(DATA),$(CURDIR)/$(dir)) + +CFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.c))) +CPPFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.cpp))) +SFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.s))) +DEFFILES := $(foreach dir,$(SOURCES),$(notdir $(wildcard $(dir)/*.def))) +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_BIN := $(addsuffix .o,$(BINFILES)) +export OFILES_SRC := $(DEFFILES:.def=.o) $(SFILES:.s=.o) $(CFILES:.c=.o) $(CPPFILES:.cpp=.o) +export OFILES := $(OFILES_BIN) $(OFILES_SRC) +export HFILES := $(addsuffix .h,$(subst .,_,$(BINFILES))) + +export INCLUDE := $(foreach dir,$(INCLUDES),-I$(CURDIR)/$(dir)) \ + $(foreach dir,$(LIBDIRS),-I$(dir)/include) \ + -I. + +.PHONY: all dist-bin dist-src dist install clean + +#--------------------------------------------------------------------------------- +all: lib/libiosuhax.a + +dist-bin: all + @tar --exclude=*~ -cjf libiosuhax-$(VERSION).tar.bz2 include lib + +dist-src: + @tar --exclude=*~ -cjf libiosuhax-src-$(VERSION).tar.bz2 include source Makefile + +dist: dist-src dist-bin + +install: dist-bin + mkdir -p $(DESTDIR)$(DEVKITPRO)/wut/usr + bzip2 -cd libiosuhax-$(VERSION).tar.bz2 | tar -xf - -C $(DESTDIR)$(DEVKITPRO)/wut/usr + +lib: + @[ -d $@ ] || mkdir -p $@ + +release: + @[ -d $@ ] || mkdir -p $@ + +lib/libiosuhax.a :$(SOURCES) $(INCLUDES) | lib release + @$(MAKE) BUILD=release OUTPUT=$(CURDIR)/$@ \ + BUILD_CFLAGS="-DNDEBUG=1 -O2 -s" \ + DEPSDIR=$(CURDIR)/release \ + --no-print-directory -C release \ + -f $(CURDIR)/Makefile + +#--------------------------------------------------------------------------------- +clean: + @echo clean ... + @rm -rf release lib + +#--------------------------------------------------------------------------------- +else + +DEPENDS := $(OFILES:.o=.d) + +#--------------------------------------------------------------------------------- +# main targets +#--------------------------------------------------------------------------------- +$(OUTPUT) : $(OFILES) + +$(OFILES_SRC) : $(HFILES) + +#--------------------------------------------------------------------------------- +%_bin.h %.bin.o : %.bin +#--------------------------------------------------------------------------------- + @echo $(notdir $<) + @$(bin2o) + + +-include $(DEPENDS) + +#--------------------------------------------------------------------------------------- +endif +#--------------------------------------------------------------------------------------- diff --git a/deps/libiosuhax/README.md b/deps/libiosuhax/README.md new file mode 100644 index 0000000000..1fc1235092 --- /dev/null +++ b/deps/libiosuhax/README.md @@ -0,0 +1,10 @@ +[![Build Status](https://travis-ci.org/dimok789/libiosuhax.svg)](https://travis-ci.org/dimok789/libiosuhax) +# libiosuhax +A PPC library to access IOSUHAX from PPC and a devoptab for any device or path. +It's only compatible to RPX-Files. + +## Building +Make you to have [wut](https://github.com/devkitPro/wut/) installed and use the following command for build: +``` +make install +``` diff --git a/deps/libiosuhax/iosuhax.h b/deps/libiosuhax/include/iosuhax.h similarity index 96% rename from deps/libiosuhax/iosuhax.h rename to deps/libiosuhax/include/iosuhax.h index 25b7367cad..9b2350b7fd 100644 --- a/deps/libiosuhax/iosuhax.h +++ b/deps/libiosuhax/include/iosuhax.h @@ -1,109 +1,112 @@ -/*************************************************************************** - * Copyright (C) 2016 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#ifndef _LIB_IOSUHAX_H_ -#define _LIB_IOSUHAX_H_ - -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 -#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 -#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 -#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 -#define IOS_ERROR_NOEXISTS 0xFFFFFFFA - -typedef struct -{ - uint32_t flag; - uint32_t permission; - uint32_t owner_id; - uint32_t group_id; - uint32_t size; // size in bytes - uint32_t physsize; // physical size on disk in bytes - uint32_t unk[3]; - uint32_t id; - uint32_t ctime; - uint32_t mtime; - uint32_t unk2[0x0D]; -}fileStat_s; - -typedef struct -{ - fileStat_s stat; - char name[0x100]; -}directoryEntry_s; - -#define DIR_ENTRY_IS_DIRECTORY 0x80000000 - -#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) -#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) - -int IOSUHAX_Open(const char *dev); // if dev == NULL the default path /dev/iosuhax will be used -int IOSUHAX_Close(void); - -int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size); // IOSU external input -int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size); // IOSU external output -int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size); // IOSU internal memcpy only - -int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt); - -int IOSUHAX_FSA_Open(); -int IOSUHAX_FSA_Close(int fsaFd); - -int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len); -int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags); -int IOSUHAX_FSA_FlushVolume(int fsaFd, const char* volume_path); - -int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data); - -int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags); -int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle); -int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data); -int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle); -int IOSUHAX_FSA_CloseDir(int fsaFd, int handle); -int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path); - -int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle); -int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); -int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); -int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data); -int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle); -int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position); -int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data); -int IOSUHAX_FSA_Remove(int fsaFd, const char *path); -int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode); - -int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle); -int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); -int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); -int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle); - -#ifdef __cplusplus -} -#endif - -#endif +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _LIB_IOSUHAX_H_ +#define _LIB_IOSUHAX_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define IOS_ERROR_UNKNOWN_VALUE 0xFFFFFFD6 +#define IOS_ERROR_INVALID_ARG 0xFFFFFFE3 +#define IOS_ERROR_INVALID_SIZE 0xFFFFFFE9 +#define IOS_ERROR_UNKNOWN 0xFFFFFFF7 +#define IOS_ERROR_NOEXISTS 0xFFFFFFFA + +typedef struct +{ + uint32_t flag; + uint32_t permission; + uint32_t owner_id; + uint32_t group_id; + uint32_t size; // size in bytes + uint32_t physsize; // physical size on disk in bytes + uint32_t unk[3]; + uint32_t id; + uint32_t ctime; + uint32_t mtime; + uint32_t unk2[0x0D]; +}fileStat_s; + +typedef struct +{ + fileStat_s stat; + char name[0x100]; +}directoryEntry_s; + +#define DIR_ENTRY_IS_DIRECTORY 0x80000000 + +#define FSA_MOUNTFLAGS_BINDMOUNT (1 << 0) +#define FSA_MOUNTFLAGS_GLOBAL (1 << 1) + +int IOSUHAX_Open(const char *dev); // if dev == NULL the default path /dev/iosuhax will be used +int IOSUHAX_Close(void); + +int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size); // IOSU external input +int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size); // IOSU external output +int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size); // IOSU internal memcpy only + +int IOSUHAX_kern_write32(uint32_t address, uint32_t value); +int IOSUHAX_kern_read32(uint32_t address, uint32_t* out_buffer, uint32_t count); + +int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt); + +int IOSUHAX_FSA_Open(); +int IOSUHAX_FSA_Close(int fsaFd); + +int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len); +int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags); +int IOSUHAX_FSA_FlushVolume(int fsaFd, const char* volume_path); + +int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data); + +int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags); +int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle); +int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data); +int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle); +int IOSUHAX_FSA_CloseDir(int fsaFd, int handle); +int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path); + +int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle); +int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); +int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags); +int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data); +int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle); +int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position); +int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data); +int IOSUHAX_FSA_Remove(int fsaFd, const char *path); +int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode); + +int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle); +int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); +int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle); +int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle); + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/libiosuhax/iosuhax_devoptab.h b/deps/libiosuhax/include/iosuhax_devoptab.h similarity index 97% rename from deps/libiosuhax/iosuhax_devoptab.h rename to deps/libiosuhax/include/iosuhax_devoptab.h index 2c7d5d227c..18847a683c 100644 --- a/deps/libiosuhax/iosuhax_devoptab.h +++ b/deps/libiosuhax/include/iosuhax_devoptab.h @@ -1,42 +1,42 @@ -/*************************************************************************** - * Copyright (C) 2015 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#ifndef __IOSUHAX_DEVOPTAB_H_ -#define __IOSUHAX_DEVOPTAB_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -//! virtual name example: sd or odd (for sd:/ or odd:/ access) -//! fsaFd: fd received by IOSUHAX_FSA_Open(); -//! dev_path: (optional) if a device should be mounted to the mount_path. If NULL no IOSUHAX_FSA_Mount is not executed. -//! mount_path: path to map to virtual device name -int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path); -int unmount_fs(const char *virt_name); - -#ifdef __cplusplus -} -#endif - -#endif // __IOSUHAX_DEVOPTAB_H_ +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef __IOSUHAX_DEVOPTAB_H_ +#define __IOSUHAX_DEVOPTAB_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +//! virtual name example: sd or odd (for sd:/ or odd:/ access) +//! fsaFd: fd received by IOSUHAX_FSA_Open(); +//! dev_path: (optional) if a device should be mounted to the mount_path. If NULL no IOSUHAX_FSA_Mount is not executed. +//! mount_path: path to map to virtual device name +int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path); +int unmount_fs(const char *virt_name); + +#ifdef __cplusplus +} +#endif + +#endif // __IOSUHAX_DEVOPTAB_H_ diff --git a/deps/libiosuhax/iosuhax_disc_interface.h b/deps/libiosuhax/include/iosuhax_disc_interface.h similarity index 97% rename from deps/libiosuhax/iosuhax_disc_interface.h rename to deps/libiosuhax/include/iosuhax_disc_interface.h index 0ce479547b..c5b703b7bc 100644 --- a/deps/libiosuhax/iosuhax_disc_interface.h +++ b/deps/libiosuhax/include/iosuhax_disc_interface.h @@ -1,73 +1,73 @@ -/*************************************************************************** - * Copyright (C) 2016 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#ifndef _IOSUHAX_DISC_INTERFACE_H_ -#define _IOSUHAX_DISC_INTERFACE_H_ - -#include -#include - -#ifdef __cplusplus -extern "C" { -#endif - -#define DEVICE_TYPE_WII_U_SD (('W'<<24)|('U'<<16)|('S'<<8)|'D') -#define DEVICE_TYPE_WII_U_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B') -#define FEATURE_WII_U_SD 0x00001000 -#define FEATURE_WII_U_USB 0x00002000 - -#ifndef OGC_DISC_IO_INCLUDE -typedef uint32_t sec_t; - -#define FEATURE_MEDIUM_CANREAD 0x00000001 -#define FEATURE_MEDIUM_CANWRITE 0x00000002 - -typedef bool (* FN_MEDIUM_STARTUP)(void) ; -typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; -typedef bool (* FN_MEDIUM_READSECTORS)(uint32_t sector, uint32_t numSectors, void* buffer) ; -typedef bool (* FN_MEDIUM_WRITESECTORS)(uint32_t sector, uint32_t numSectors, const void* buffer) ; -typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; -typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; - -struct DISC_INTERFACE_STRUCT { - unsigned long ioType ; - unsigned long features ; - FN_MEDIUM_STARTUP startup ; - FN_MEDIUM_ISINSERTED isInserted ; - FN_MEDIUM_READSECTORS readSectors ; - FN_MEDIUM_WRITESECTORS writeSectors ; - FN_MEDIUM_CLEARSTATUS clearStatus ; - FN_MEDIUM_SHUTDOWN shutdown ; -} ; - -typedef struct DISC_INTERFACE_STRUCT DISC_INTERFACE ; -#endif - -extern const DISC_INTERFACE IOSUHAX_sdio_disc_interface; -extern const DISC_INTERFACE IOSUHAX_usb_disc_interface; - -#ifdef __cplusplus -} -#endif - -#endif +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#ifndef _IOSUHAX_DISC_INTERFACE_H_ +#define _IOSUHAX_DISC_INTERFACE_H_ + +#include +#include + +#ifdef __cplusplus +extern "C" { +#endif + +#define DEVICE_TYPE_WII_U_SD (('W'<<24)|('U'<<16)|('S'<<8)|'D') +#define DEVICE_TYPE_WII_U_USB (('W'<<24)|('U'<<16)|('S'<<8)|'B') +#define FEATURE_WII_U_SD 0x00001000 +#define FEATURE_WII_U_USB 0x00002000 + +#ifndef OGC_DISC_IO_INCLUDE +typedef uint32_t sec_t; + +#define FEATURE_MEDIUM_CANREAD 0x00000001 +#define FEATURE_MEDIUM_CANWRITE 0x00000002 + +typedef bool (* FN_MEDIUM_STARTUP)(void) ; +typedef bool (* FN_MEDIUM_ISINSERTED)(void) ; +typedef bool (* FN_MEDIUM_READSECTORS)(uint32_t sector, uint32_t numSectors, void* buffer) ; +typedef bool (* FN_MEDIUM_WRITESECTORS)(uint32_t sector, uint32_t numSectors, const void* buffer) ; +typedef bool (* FN_MEDIUM_CLEARSTATUS)(void) ; +typedef bool (* FN_MEDIUM_SHUTDOWN)(void) ; + +struct DISC_INTERFACE_STRUCT { + unsigned long ioType ; + unsigned long features ; + FN_MEDIUM_STARTUP startup ; + FN_MEDIUM_ISINSERTED isInserted ; + FN_MEDIUM_READSECTORS readSectors ; + FN_MEDIUM_WRITESECTORS writeSectors ; + FN_MEDIUM_CLEARSTATUS clearStatus ; + FN_MEDIUM_SHUTDOWN shutdown ; +} ; + +typedef struct DISC_INTERFACE_STRUCT DISC_INTERFACE ; +#endif + +extern const DISC_INTERFACE IOSUHAX_sdio_disc_interface; +extern const DISC_INTERFACE IOSUHAX_usb_disc_interface; + +#ifdef __cplusplus +} +#endif + +#endif diff --git a/deps/libiosuhax/os_functions.h b/deps/libiosuhax/os_functions.h deleted file mode 100644 index 6135236344..0000000000 --- a/deps/libiosuhax/os_functions.h +++ /dev/null @@ -1,51 +0,0 @@ -#ifndef __OS_FUNCTIONS_H_ -#define __OS_FUNCTIONS_H_ - -#ifdef __cplusplus -extern "C" { -#endif - -#define OS_MUTEX_SIZE 44 - -// RetroArch mod: use existing headers; prevents conflicts in griffin -#include -#include -#if 0 - -#ifndef __WUT__ -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -//! Mutex functions -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -extern void (* OSInitMutex)(void* mutex); -extern void (* OSLockMutex)(void* mutex); -extern void (* OSUnlockMutex)(void* mutex); - -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -//! IOS function -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -extern int (*IOS_Ioctl)(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len); -extern int (*IOS_Open)(char *path, unsigned int mode); -extern int (*IOS_Close)(int fd); -#else -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -//! Mutex functions -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -extern void OSInitMutex(void* mutex); -extern void OSLockMutex(void* mutex); -extern void OSUnlockMutex(void* mutex); - -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -//! IOS function -//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- -extern int IOS_Ioctl(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len); -extern int IOS_Open(char *path, unsigned int mode); -extern int IOS_Close(int fd); -#endif // __WUT__ - -#ifdef __cplusplus -} -#endif - -#endif // 0 - -#endif // __OS_FUNCTIONS_H_ diff --git a/deps/libiosuhax/iosuhax.c b/deps/libiosuhax/source/iosuhax.c similarity index 78% rename from deps/libiosuhax/iosuhax.c rename to deps/libiosuhax/source/iosuhax.c index 34a842ce73..bf6032850d 100644 --- a/deps/libiosuhax/iosuhax.c +++ b/deps/libiosuhax/source/iosuhax.c @@ -1,1029 +1,956 @@ -/*************************************************************************** - * Copyright (C) 2016 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#include -#include -#include "os_functions.h" -#include "iosuhax.h" - -#define IOSUHAX_MAGIC_WORD 0x4E696365 - -#define IOCTL_MEM_WRITE 0x00 -#define IOCTL_MEM_READ 0x01 -#define IOCTL_SVC 0x02 -#define IOCTL_MEMCPY 0x04 -#define IOCTL_REPEATED_WRITE 0x05 -#define IOCTL_KERN_READ32 0x06 -#define IOCTL_KERN_WRITE32 0x07 - -#define IOCTL_FSA_OPEN 0x40 -#define IOCTL_FSA_CLOSE 0x41 -#define IOCTL_FSA_MOUNT 0x42 -#define IOCTL_FSA_UNMOUNT 0x43 -#define IOCTL_FSA_GETDEVICEINFO 0x44 -#define IOCTL_FSA_OPENDIR 0x45 -#define IOCTL_FSA_READDIR 0x46 -#define IOCTL_FSA_CLOSEDIR 0x47 -#define IOCTL_FSA_MAKEDIR 0x48 -#define IOCTL_FSA_OPENFILE 0x49 -#define IOCTL_FSA_READFILE 0x4A -#define IOCTL_FSA_WRITEFILE 0x4B -#define IOCTL_FSA_STATFILE 0x4C -#define IOCTL_FSA_CLOSEFILE 0x4D -#define IOCTL_FSA_SETFILEPOS 0x4E -#define IOCTL_FSA_GETSTAT 0x4F -#define IOCTL_FSA_REMOVE 0x50 -#define IOCTL_FSA_REWINDDIR 0x51 -#define IOCTL_FSA_CHDIR 0x52 -#define IOCTL_FSA_RENAME 0x53 -#define IOCTL_FSA_RAW_OPEN 0x54 -#define IOCTL_FSA_RAW_READ 0x55 -#define IOCTL_FSA_RAW_WRITE 0x56 -#define IOCTL_FSA_RAW_CLOSE 0x57 -#define IOCTL_FSA_CHANGEMODE 0x58 -#define IOCTL_FSA_FLUSHVOLUME 0x59 -#define IOCTL_CHECK_IF_IOSUHAX 0x5B - -static int iosuhaxHandle = -1; - -int IOSUHAX_Open(const char *dev) -{ - if(iosuhaxHandle >= 0) - return iosuhaxHandle; - - iosuhaxHandle = IOS_Open((char*)(dev ? dev : "/dev/iosuhax"), 0); - if(iosuhaxHandle >= 0 && dev) /* make sure device is actually iosuhax */ - { - unsigned int res = 0; - IOS_Ioctl(iosuhaxHandle, IOCTL_CHECK_IF_IOSUHAX, (void*)0, 0, &res, 4); - if(res != IOSUHAX_MAGIC_WORD) - { - IOS_Close(iosuhaxHandle); - iosuhaxHandle = -1; - } - } - - return iosuhaxHandle; -} - -int IOSUHAX_Close(void) -{ - if(iosuhaxHandle < 0) - return 0; - - int res = IOS_Close(iosuhaxHandle); - iosuhaxHandle = -1; - return res; -} - -int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!buffer) - return -1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, size + 4); - if(!io_buf) - return -2; - - io_buf[0] = address; - memcpy(io_buf + 1, buffer, size); - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, 0, 0); - - free(io_buf); - return res; -} - -int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!out_buffer || !size) - return -1; - - return IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, &address, sizeof(address), out_buffer, size); -} - -int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!dst || !src || !size) - return -1; - - uint32_t io_buf[3]; - io_buf[0] = dst; - io_buf[1] = src; - io_buf[2] = size; - - return IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, sizeof(io_buf), 0, 0); -} - -int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - uint32_t arguments[9]; - arguments[0] = svc_id; - - if(args && arg_cnt) - { - if(arg_cnt > 8) - arg_cnt = 8; - - memcpy(arguments + 1, args, arg_cnt * 4); - } - - int result; - int ret = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, &result, sizeof(result)); - if(ret < 0) - return ret; - - return result; -} - -int IOSUHAX_FSA_Open(void) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - int fsaFd; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPEN, 0, 0, &fsaFd, sizeof(fsaFd)); - if(res < 0) - return res; - - return fsaFd; -} - -int IOSUHAX_FSA_Close(int fsaFd) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSE, &fsaFd, sizeof(fsaFd), &fsaFd, sizeof(fsaFd)); - if(res < 0) - return res; - - return fsaFd; -} - -int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!device_path || !volume_path || !arg_string) - return -1; - - const int input_cnt = 6; - - int io_buf_size = (sizeof(uint32_t) * input_cnt) + strlen(device_path) + strlen(volume_path) + arg_string_len + 3; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - memset(io_buf, 0, io_buf_size); - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = io_buf[1] + strlen(device_path) + 1; - io_buf[3] = flags; - io_buf[4] = arg_string_len ? ( io_buf[2] + strlen(volume_path) + 1) : 0; - io_buf[5] = arg_string_len; - - strcpy(((char*)io_buf) + io_buf[1], device_path); - strcpy(((char*)io_buf) + io_buf[2], volume_path); - - if(arg_string_len) - memcpy(((char*)io_buf) + io_buf[4], arg_string, arg_string_len); - - int mountRes; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MOUNT, io_buf, io_buf_size, &mountRes, sizeof(mountRes)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return mountRes; -} - -int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = flags; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_UNMOUNT, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!volume_path) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(volume_path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], volume_path); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHVOLUME, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!device_path || !out_data) - return -1; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = type; - strcpy(((char*)io_buf) + io_buf[1], device_path); - - uint32_t out_buf[1 + 0x64 / 4]; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf)); - if(res < 0) - { - free(io_buf); - return res; - } - - memcpy(out_data, out_buf + 1, 0x64); - free(io_buf); - return out_buf[0]; -} - -int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = flags; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result; - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MAKEDIR, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result_vec[2]; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENDIR, io_buf, io_buf_size, result_vec, sizeof(result_vec)); - if(res < 0) - { - free(io_buf); - return res; - } - - *outHandle = result_vec[1]; - free(io_buf); - return result_vec[0]; -} - -int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!out_data) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = handle; - - int result_vec_size = 4 + sizeof(directoryEntry_s); - uint8_t *result_vec = (uint8_t*) memalign(0x20, result_vec_size); - if(!result_vec) - { - free(io_buf); - return -2; - } - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READDIR, io_buf, io_buf_size, result_vec, result_vec_size); - if(res < 0) - { - free(result_vec); - free(io_buf); - return res; - } - - int result = *(int*)result_vec; - memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s)); - free(io_buf); - free(result_vec); - return result; -} - -int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = dirHandle; - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REWINDDIR, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_CloseDir(int fsaFd, int handle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = handle; - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEDIR, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHDIR, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path || !mode || !outHandle) - return -1; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + strlen(mode) + 2; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = io_buf[1] + strlen(path) + 1; - strcpy(((char*)io_buf) + io_buf[1], path); - strcpy(((char*)io_buf) + io_buf[2], mode); - - int result_vec[2]; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENFILE, io_buf, io_buf_size, result_vec, sizeof(result_vec)); - if(res < 0) - { - free(io_buf); - return res; - } - - *outHandle = result_vec[1]; - free(io_buf); - return result_vec[0]; -} - -int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!data) - return -1; - - const int input_cnt = 5; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = size; - io_buf[2] = cnt; - io_buf[3] = fileHandle; - io_buf[4] = flags; - - int out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F; - - uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size); - if(!out_buffer) - { - free(io_buf); - return -2; - } - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILE, io_buf, io_buf_size, out_buffer, out_buf_size); - if(res < 0) - { - free(out_buffer); - free(io_buf); - return res; - } - - /* ! data is put to offset 0x40 to align the buffer output */ - memcpy(data, ((uint8_t*)out_buffer) + 0x40, size * cnt); - - int result = out_buffer[0]; - - free(out_buffer); - free(io_buf); - return result; -} - -int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!data) - return -1; - - const int input_cnt = 5; - - int io_buf_size = ((sizeof(uint32_t) * input_cnt + size * cnt + 0x40) + 0x3F) & ~0x3F; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = size; - io_buf[2] = cnt; - io_buf[3] = fileHandle; - io_buf[4] = flags; - - /* ! data is put to offset 0x40 to align the buffer input */ - memcpy(((uint8_t*)io_buf) + 0x40, data, size * cnt); - - int result; - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - free(io_buf); - return result; -} - -int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!out_data) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = fileHandle; - - int out_buf_size = 4 + sizeof(fileStat_s); - uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); - if(!out_buffer) - { - free(io_buf); - return -2; - } - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size); - if(res < 0) - { - free(io_buf); - free(out_buffer); - return res; - } - - int result = out_buffer[0]; - memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); - - free(io_buf); - free(out_buffer); - return result; -} - -int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = fileHandle; - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = fileHandle; - io_buf[2] = position; - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path || !out_data) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], path); - - int out_buf_size = 4 + sizeof(fileStat_s); - uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); - if(!out_buffer) - { - free(io_buf); - return -2; - } - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, out_buffer, out_buf_size); - if(res < 0) - { - free(io_buf); - free(out_buffer); - return res; - } - - int result = out_buffer[0]; - memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); - - free(io_buf); - free(out_buffer); - return result; -} - -int IOSUHAX_FSA_Remove(int fsaFd, const char *path) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REMOVE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!path) - return -1; - - const int input_cnt = 3; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - io_buf[2] = mode; - strcpy(((char*)io_buf) + io_buf[1], path); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEMODE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - -int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!device_path && !outHandle) - return -1; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = sizeof(uint32_t) * input_cnt; - strcpy(((char*)io_buf) + io_buf[1], device_path); - - int result_vec[2]; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_OPEN, io_buf, io_buf_size, result_vec, sizeof(result_vec)); - if(res < 0) - { - free(io_buf); - return res; - } - - if(outHandle) - *outHandle = result_vec[1]; - - free(io_buf); - return result_vec[0]; -} - -int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!data) - return -1; - - const int input_cnt = 6; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = block_size; - io_buf[2] = block_cnt; - io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; - io_buf[4] = sector_offset & 0xFFFFFFFF; - io_buf[5] = device_handle; - - int out_buf_size = ((block_size * block_cnt + 0x40) + 0x3F) & ~0x3F; - - uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size); - if(!out_buffer) - { - free(io_buf); - return -2; - } - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_READ, io_buf, io_buf_size, out_buffer, out_buf_size); - if(res < 0) - { - free(out_buffer); - free(io_buf); - return res; - } - - /* ! data is put to offset 0x40 to align the buffer output */ - memcpy(data, ((uint8_t*)out_buffer) + 0x40, block_size * block_cnt); - - int result = out_buffer[0]; - - free(out_buffer); - free(io_buf); - return result; -} - -int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - if(!data) - return -1; - - const int input_cnt = 6; - - int io_buf_size = ((sizeof(uint32_t) * input_cnt + block_size * block_cnt + 0x40) + 0x3F) & ~0x3F; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = block_size; - io_buf[2] = block_cnt; - io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; - io_buf[4] = sector_offset & 0xFFFFFFFF; - io_buf[5] = device_handle; - - /* ! data is put to offset 0x40 to align the buffer input */ - memcpy(((uint8_t*)io_buf) + 0x40, data, block_size * block_cnt); - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_WRITE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} - - -int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle) -{ - if(iosuhaxHandle < 0) - return iosuhaxHandle; - - const int input_cnt = 2; - - int io_buf_size = sizeof(uint32_t) * input_cnt; - - uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); - if(!io_buf) - return -2; - - io_buf[0] = fsaFd; - io_buf[1] = device_handle; - - int result; - - int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_CLOSE, io_buf, io_buf_size, &result, sizeof(result)); - if(res < 0) - { - free(io_buf); - return res; - } - - free(io_buf); - return result; -} +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include "os_functions.h" +#include "iosuhax.h" + +#define IOSUHAX_MAGIC_WORD 0x4E696365 + +#define IOCTL_MEM_WRITE 0x00 +#define IOCTL_MEM_READ 0x01 +#define IOCTL_SVC 0x02 +#define IOCTL_MEMCPY 0x04 +#define IOCTL_REPEATED_WRITE 0x05 +#define IOCTL_KERN_READ32 0x06 +#define IOCTL_KERN_WRITE32 0x07 + +#define IOCTL_FSA_OPEN 0x40 +#define IOCTL_FSA_CLOSE 0x41 +#define IOCTL_FSA_MOUNT 0x42 +#define IOCTL_FSA_UNMOUNT 0x43 +#define IOCTL_FSA_GETDEVICEINFO 0x44 +#define IOCTL_FSA_OPENDIR 0x45 +#define IOCTL_FSA_READDIR 0x46 +#define IOCTL_FSA_CLOSEDIR 0x47 +#define IOCTL_FSA_MAKEDIR 0x48 +#define IOCTL_FSA_OPENFILE 0x49 +#define IOCTL_FSA_READFILE 0x4A +#define IOCTL_FSA_WRITEFILE 0x4B +#define IOCTL_FSA_STATFILE 0x4C +#define IOCTL_FSA_CLOSEFILE 0x4D +#define IOCTL_FSA_SETFILEPOS 0x4E +#define IOCTL_FSA_GETSTAT 0x4F +#define IOCTL_FSA_REMOVE 0x50 +#define IOCTL_FSA_REWINDDIR 0x51 +#define IOCTL_FSA_CHDIR 0x52 +#define IOCTL_FSA_RENAME 0x53 +#define IOCTL_FSA_RAW_OPEN 0x54 +#define IOCTL_FSA_RAW_READ 0x55 +#define IOCTL_FSA_RAW_WRITE 0x56 +#define IOCTL_FSA_RAW_CLOSE 0x57 +#define IOCTL_FSA_CHANGEMODE 0x58 +#define IOCTL_FSA_FLUSHVOLUME 0x59 +#define IOCTL_CHECK_IF_IOSUHAX 0x5B + +static int iosuhaxHandle = -1; + +#define ALIGN(align) __attribute__((aligned(align))) +#define ROUNDUP(x, align) (((x) + ((align) - 1)) & ~((align) - 1)) + +int IOSUHAX_Open(const char *dev) +{ + if(iosuhaxHandle >= 0) + return iosuhaxHandle; + + iosuhaxHandle = IOS_Open((char*)(dev ? dev : "/dev/iosuhax"), 0); + if(iosuhaxHandle >= 0 && dev) //make sure device is actually iosuhax + { + ALIGN(0x20) int res[0x20 >> 2]; + *res = 0; + + IOS_Ioctl(iosuhaxHandle, IOCTL_CHECK_IF_IOSUHAX, (void*)0, 0, res, 4); + if(*res != IOSUHAX_MAGIC_WORD) + { + IOS_Close(iosuhaxHandle); + iosuhaxHandle = -1; + } + } + + return iosuhaxHandle; +} + +int IOSUHAX_Close(void) +{ + if(iosuhaxHandle < 0) + return 0; + + int res = IOS_Close(iosuhaxHandle); + iosuhaxHandle = -1; + return res; +} + +int IOSUHAX_memwrite(uint32_t address, const uint8_t * buffer, uint32_t size) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(size + 4, 0x20)); + if(!io_buf) + return -2; + + io_buf[0] = address; + memcpy(io_buf + 1, buffer, size); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_WRITE, io_buf, size + 4, 0, 0); + + free(io_buf); + return res; +} + +int IOSUHAX_memread(uint32_t address, uint8_t * out_buffer, uint32_t size) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) int io_buf[0x20 >> 2]; + io_buf[0] = address; + + void* tmp_buf = NULL; + + if(((uintptr_t)out_buffer & 0x1F) || (size & 0x1F)) + { + tmp_buf = (uint32_t*)memalign(0x20, ROUNDUP(size, 0x20)); + if(!tmp_buf) + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_MEM_READ, io_buf, sizeof(address), tmp_buf ? tmp_buf : out_buffer, size); + + if(res >= 0 && tmp_buf) + memcpy(out_buffer, tmp_buf, size); + + free(tmp_buf); + return res; +} + +int IOSUHAX_memcpy(uint32_t dst, uint32_t src, uint32_t size) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) uint32_t io_buf[0x20 >> 2]; + io_buf[0] = dst; + io_buf[1] = src; + io_buf[2] = size; + + return IOS_Ioctl(iosuhaxHandle, IOCTL_MEMCPY, io_buf, 3 * sizeof(uint32_t), 0, 0); +} + +int IOSUHAX_kern_write32(uint32_t address, uint32_t value) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) uint32_t io_buf[0x20 >> 2]; + io_buf[0] = address; + io_buf[1] = value; + + return IOS_Ioctl(iosuhaxHandle, IOCTL_KERN_WRITE32, io_buf, 2 * sizeof(uint32_t), 0, 0); +} + +int IOSUHAX_kern_read32(uint32_t address, uint32_t* out_buffer, uint32_t count) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) uint32_t io_buf[0x20 >> 2]; + io_buf[0] = address; + + void* tmp_buf = NULL; + + if(((uintptr_t)out_buffer & 0x1F) || ((count * 4) & 0x1F)) + { + tmp_buf = (uint32_t*)memalign(0x20, ROUNDUP((count * 4), 0x20)); + if(!tmp_buf) + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_KERN_READ32, io_buf, sizeof(address), tmp_buf ? tmp_buf : out_buffer, count * 4); + + if(res >= 0 && tmp_buf) + memcpy(out_buffer, tmp_buf, count * 4); + + free(tmp_buf); + return res; +} + +int IOSUHAX_SVC(uint32_t svc_id, uint32_t * args, uint32_t arg_cnt) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) uint32_t arguments[0x40 >> 2]; + arguments[0] = svc_id; + + if(args && arg_cnt) + { + if(arg_cnt > 8) + arg_cnt = 8; + + memcpy(arguments + 1, args, arg_cnt * 4); + } + + ALIGN(0x20) int result[0x20 >> 2]; + int ret = IOS_Ioctl(iosuhaxHandle, IOCTL_SVC, arguments, (1 + arg_cnt) * 4, result, 4); + if(ret < 0) + return ret; + + return *result; +} + +int IOSUHAX_FSA_Open(void) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) int io_buf[0x20 >> 2]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPEN, 0, 0, io_buf, sizeof(int)); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_Close(int fsaFd) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + ALIGN(0x20) int io_buf[0x20 >> 2]; + io_buf[0] = fsaFd; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSE, io_buf, sizeof(fsaFd), io_buf, sizeof(fsaFd)); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_Mount(int fsaFd, const char* device_path, const char* volume_path, uint32_t flags, const char* arg_string, int arg_string_len) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 6; + + int io_buf_size = (sizeof(uint32_t) * input_cnt) + strlen(device_path) + strlen(volume_path) + arg_string_len + 3; + + ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + memset(io_buf, 0, io_buf_size); + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = io_buf[1] + strlen(device_path) + 1; + io_buf[3] = flags; + io_buf[4] = arg_string_len ? ( io_buf[2] + strlen(volume_path) + 1) : 0; + io_buf[5] = arg_string_len; + + strcpy(((char*)io_buf) + io_buf[1], device_path); + strcpy(((char*)io_buf) + io_buf[2], volume_path); + + if(arg_string_len) + memcpy(((char*)io_buf) + io_buf[4], arg_string, arg_string_len); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MOUNT, io_buf, io_buf_size, io_buf, 4); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_Unmount(int fsaFd, const char* path, uint32_t flags) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = flags; + strcpy(((char*)io_buf) + io_buf[1], path); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_UNMOUNT, io_buf, io_buf_size, io_buf, 4); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_FlushVolume(int fsaFd, const char *volume_path) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(volume_path) + 1; + + ALIGN(0x20) int io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], volume_path); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_FLUSHVOLUME, io_buf, io_buf_size, io_buf, 4); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_GetDeviceInfo(int fsaFd, const char* device_path, int type, uint32_t* out_data) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = type; + strcpy(((char*)io_buf) + io_buf[1], device_path); + + uint32_t out_buf[1 + 0x64 / 4]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETDEVICEINFO, io_buf, io_buf_size, out_buf, sizeof(out_buf)); + if(res < 0) + { + free(io_buf); + return res; + } + + memcpy(out_data, out_buf + 1, 0x64); + free(io_buf); + return out_buf[0]; +} + +int IOSUHAX_FSA_MakeDir(int fsaFd, const char* path, uint32_t flags) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = flags; + strcpy(((char*)io_buf) + io_buf[1], path); + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_MAKEDIR, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_OpenDir(int fsaFd, const char* path, int* outHandle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], path); + + int result_vec[2]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENDIR, io_buf, io_buf_size, result_vec, sizeof(result_vec)); + if(res < 0) + { + free(io_buf); + return res; + } + + *outHandle = result_vec[1]; + free(io_buf); + return result_vec[0]; +} + +int IOSUHAX_FSA_ReadDir(int fsaFd, int handle, directoryEntry_s* out_data) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = handle; + + int result_vec_size = 4 + sizeof(directoryEntry_s); + uint8_t *result_vec = (uint8_t*) memalign(0x20, result_vec_size); + if(!result_vec) + { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READDIR, io_buf, io_buf_size, result_vec, result_vec_size); + if(res < 0) + { + free(result_vec); + free(io_buf); + return res; + } + + int result = *(int*)result_vec; + memcpy(out_data, result_vec + 4, sizeof(directoryEntry_s)); + free(io_buf); + free(result_vec); + return result; +} + +int IOSUHAX_FSA_RewindDir(int fsaFd, int dirHandle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = dirHandle; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REWINDDIR, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_CloseDir(int fsaFd, int handle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = handle; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEDIR, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_ChangeDir(int fsaFd, const char *path) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], path); + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHDIR, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_OpenFile(int fsaFd, const char* path, const char* mode, int* outHandle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + strlen(mode) + 2; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = io_buf[1] + strlen(path) + 1; + strcpy(((char*)io_buf) + io_buf[1], path); + strcpy(((char*)io_buf) + io_buf[2], mode); + + int result_vec[2]; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_OPENFILE, io_buf, io_buf_size, result_vec, sizeof(result_vec)); + if(res < 0) + { + free(io_buf); + return res; + } + + *outHandle = result_vec[1]; + free(io_buf); + return result_vec[0]; +} + +int IOSUHAX_FSA_ReadFile(int fsaFd, void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 5; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = fileHandle; + io_buf[4] = flags; + + int out_buf_size = ((size * cnt + 0x40) + 0x3F) & ~0x3F; + + uint32_t *out_buffer = (uint32_t*)memalign(0x40, out_buf_size); + if(!out_buffer) + { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_READFILE, io_buf, io_buf_size, out_buffer, out_buf_size); + if(res < 0) + { + free(out_buffer); + free(io_buf); + return res; + } + + //! data is put to offset 0x40 to align the buffer output + memcpy(data, ((uint8_t*)out_buffer) + 0x40, size * cnt); + + int result = out_buffer[0]; + + free(out_buffer); + free(io_buf); + return result; +} + +int IOSUHAX_FSA_WriteFile(int fsaFd, const void* data, uint32_t size, uint32_t cnt, int fileHandle, uint32_t flags) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 5; + + int io_buf_size = ((sizeof(uint32_t) * input_cnt + size * cnt + 0x40) + 0x3F) & ~0x3F; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = size; + io_buf[2] = cnt; + io_buf[3] = fileHandle; + io_buf[4] = flags; + + //! data is put to offset 0x40 to align the buffer input + memcpy(((uint8_t*)io_buf) + 0x40, data, size * cnt); + + int result; + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_WRITEFILE, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + free(io_buf); + return result; +} + +int IOSUHAX_FSA_StatFile(int fsaFd, int fileHandle, fileStat_s* out_data) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + + int out_buf_size = 4 + sizeof(fileStat_s); + uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); + if(!out_buffer) + { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_STATFILE, io_buf, io_buf_size, out_buffer, out_buf_size); + if(res < 0) + { + free(io_buf); + free(out_buffer); + return res; + } + + int result = out_buffer[0]; + memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); + + free(io_buf); + free(out_buffer); + return result; +} + +int IOSUHAX_FSA_CloseFile(int fsaFd, int fileHandle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CLOSEFILE, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_SetFilePos(int fsaFd, int fileHandle, uint32_t position) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = fileHandle; + io_buf[2] = position; + + int result; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_SETFILEPOS, io_buf, io_buf_size, &result, sizeof(result)); + if(res < 0) + { + free(io_buf); + return res; + } + + free(io_buf); + return result; +} + +int IOSUHAX_FSA_GetStat(int fsaFd, const char *path, fileStat_s* out_data) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], path); + + int out_buf_size = 4 + sizeof(fileStat_s); + uint32_t *out_buffer = (uint32_t*)memalign(0x20, out_buf_size); + if(!out_buffer) + { + free(io_buf); + return -2; + } + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_GETSTAT, io_buf, io_buf_size, out_buffer, out_buf_size); + if(res < 0) + { + free(io_buf); + free(out_buffer); + return res; + } + + int result = out_buffer[0]; + memcpy(out_data, out_buffer + 1, sizeof(fileStat_s)); + + free(io_buf); + free(out_buffer); + return result; +} + +int IOSUHAX_FSA_Remove(int fsaFd, const char *path) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + uint32_t *io_buf = (uint32_t*)memalign(0x20, ROUNDUP(io_buf_size, 0x20)); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], path); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_REMOVE, io_buf, io_buf_size, io_buf, 4); + if(res >= 0) + res = io_buf[0]; + + free(io_buf); + return res; +} + +int IOSUHAX_FSA_ChangeMode(int fsaFd, const char* path, int mode) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 3; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(path) + 1; + + ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + io_buf[2] = mode; + strcpy(((char*)io_buf) + io_buf[1], path); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_CHANGEMODE, io_buf, io_buf_size, io_buf, 4); + if(res < 0) + return res; + + return io_buf[0]; +} + +int IOSUHAX_FSA_RawOpen(int fsaFd, const char* device_path, int* outHandle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt + strlen(device_path) + 1; + + ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + + io_buf[0] = fsaFd; + io_buf[1] = sizeof(uint32_t) * input_cnt; + strcpy(((char*)io_buf) + io_buf[1], device_path); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_OPEN, io_buf, io_buf_size, io_buf, 2 * sizeof(int)); + if(res < 0) + return res; + + if(outHandle) + *outHandle = io_buf[1]; + + return io_buf[0]; +} + +int IOSUHAX_FSA_RawRead(int fsaFd, void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 6; + + int io_buf_size = 0x40 + block_size * block_cnt; + uint32_t *io_buf = (uint32_t*)memalign(0x40, ROUNDUP(io_buf_size, 0x40)); + + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = block_size; + io_buf[2] = block_cnt; + io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; + io_buf[4] = sector_offset & 0xFFFFFFFF; + io_buf[5] = device_handle; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_READ, io_buf, sizeof(uint32_t) * input_cnt, io_buf, io_buf_size); + if(res >= 0) + { + //! data is put to offset 0x40 to align the buffer output + memcpy(data, ((uint8_t*)io_buf) + 0x40, block_size * block_cnt); + + res = io_buf[0]; + } + + free(io_buf); + return res; +} + +int IOSUHAX_FSA_RawWrite(int fsaFd, const void* data, uint32_t block_size, uint32_t block_cnt, uint64_t sector_offset, int device_handle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + int io_buf_size = ROUNDUP(0x40 + block_size * block_cnt, 0x40); + + uint32_t *io_buf = (uint32_t*)memalign(0x40, io_buf_size); + if(!io_buf) + return -2; + + io_buf[0] = fsaFd; + io_buf[1] = block_size; + io_buf[2] = block_cnt; + io_buf[3] = (sector_offset >> 32) & 0xFFFFFFFF; + io_buf[4] = sector_offset & 0xFFFFFFFF; + io_buf[5] = device_handle; + + //! data is put to offset 0x40 to align the buffer input + memcpy(((uint8_t*)io_buf) + 0x40, data, block_size * block_cnt); + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_WRITE, io_buf, io_buf_size, io_buf, 4); + if(res >= 0) + res = io_buf[0]; + + free(io_buf); + return res; +} + + +int IOSUHAX_FSA_RawClose(int fsaFd, int device_handle) +{ + if(iosuhaxHandle < 0) + return iosuhaxHandle; + + const int input_cnt = 2; + + int io_buf_size = sizeof(uint32_t) * input_cnt; + + ALIGN(0x20) uint32_t io_buf[ROUNDUP(io_buf_size, 0x20) >> 2]; + + io_buf[0] = fsaFd; + io_buf[1] = device_handle; + + int res = IOS_Ioctl(iosuhaxHandle, IOCTL_FSA_RAW_CLOSE, io_buf, io_buf_size, io_buf, 4); + if(res < 0) + return res; + + return io_buf[0]; +} diff --git a/deps/libiosuhax/iosuhax_devoptab.c b/deps/libiosuhax/source/iosuhax_devoptab.c similarity index 84% rename from deps/libiosuhax/iosuhax_devoptab.c rename to deps/libiosuhax/source/iosuhax_devoptab.c index 4d59d6ae73..5e945f8ad4 100644 --- a/deps/libiosuhax/iosuhax_devoptab.c +++ b/deps/libiosuhax/source/iosuhax_devoptab.c @@ -1,1134 +1,993 @@ -/*************************************************************************** - * Copyright (C) 2015 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include "os_functions.h" -#include "iosuhax.h" - -typedef struct _fs_dev_private_t { - char *mount_path; - int fsaFd; - int mounted; - void *pMutex; -} fs_dev_private_t; - -typedef struct _fs_dev_file_state_t { - fs_dev_private_t *dev; - int fd; /* File descriptor */ - int flags; /* Opening flags */ - int read; /* True if allowed to read from file */ - int write; /* True if allowed to write to file */ - int append; /* True if allowed to append to file */ - uint32_t pos; /* Current position within the file (in bytes) */ - uint32_t len; /* Total length of the file (in bytes) */ - struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ - struct _fs_dev_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ -} fs_dev_file_state_t; - -typedef struct _fs_dev_dir_entry_t { - fs_dev_private_t *dev; - int dirHandle; -} fs_dev_dir_entry_t; - -static fs_dev_private_t *fs_dev_get_device_data(const char *path) -{ - const devoptab_t *devoptab = NULL; - char name[128] = {0}; - int i; - - if(!path) - return NULL; - - /* Get the device name from the path */ - strncpy(name, path, 127); - strtok(name, ":/"); - - // Search the devoptab table for the specified device name - // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab - // which ignores names with suffixes and causes names - // like "ntfs" and "ntfs1" to be seen as equals - for (i = 3; i < STD_MAX; i++) { - devoptab = devoptab_list[i]; - if (devoptab && devoptab->name) { - if (strcmp(name, devoptab->name) == 0) { - return (fs_dev_private_t *)devoptab->deviceData; - } - } - } - - return NULL; -} - -static char *fs_dev_real_path (const char *path, fs_dev_private_t *dev) -{ - /* Sanity check */ - if (!path || !dev) - return NULL; - - /* Move the path pointer to the start of the actual path */ - if (strchr(path, ':') != NULL) { - path = strchr(path, ':') + 1; - } - - int mount_len = strlen(dev->mount_path); - - char *new_name = (char*)malloc(mount_len + strlen(path) + 1); - if(new_name) { - strcpy(new_name, dev->mount_path); - strcpy(new_name + mount_len, path); - return new_name; - } - return new_name; -} - -static int fs_dev_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fileStruct; - if(!file) { - r->_errno = EINVAL; - return -1; - } - - file->dev = dev; - /* Determine which mode the file is opened for */ - file->flags = flags; - - const char *mode_str; - - if ((flags & 0x03) == O_RDONLY) { - file->read = 1; - file->write = 0; - file->append = 0; - mode_str = "r"; - } else if ((flags & 0x03) == O_WRONLY) { - file->read = 0; - file->write = 1; - file->append = (flags & O_APPEND); - mode_str = file->append ? "a" : "w"; - } else if ((flags & 0x03) == O_RDWR) { - file->read = 1; - file->write = 1; - file->append = (flags & O_APPEND); - mode_str = file->append ? "a+" : "r+"; - } else { - r->_errno = EACCES; - return -1; - } - - int fd = -1; - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(path, dev); - if(!path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, mode_str, &fd); - - free(real_path); - - if(result == 0) - { - fileStat_s stats; - result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats); - if(result != 0) { - IOSUHAX_FSA_CloseFile(dev->fsaFd, fd); - r->_errno = result; - OSUnlockMutex(dev->pMutex); - return -1; - } - file->fd = fd; - file->pos = 0; - file->len = stats.size; - OSUnlockMutex(dev->pMutex); - return (int)file; - } - - r->_errno = result; - OSUnlockMutex(dev->pMutex); - return -1; -} - -static int fs_dev_close_r (struct _reent *r, void *fd) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return -1; - - if(!file) { - r->_errno = EINVAL; - return -1; - } - - if(!file->dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(file->dev->pMutex); - - int result = IOSUHAX_FSA_CloseFile(file->dev->fsaFd, file->fd); - - OSUnlockMutex(file->dev->pMutex); - - if(result < 0) - { - r->_errno = result; - return -1; - } - return 0; -} - -static off_t fs_dev_seek_r (struct _reent *r, void* fd, off_t pos, int dir) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return 0; - - if(!file) { - r->_errno = EINVAL; - return 0; - } - - if(!file->dev) { - r->_errno = ENODEV; - return 0; - } - - OSLockMutex(file->dev->pMutex); - - switch(dir) - { - case SEEK_SET: - file->pos = pos; - break; - case SEEK_CUR: - file->pos += pos; - break; - case SEEK_END: - file->pos = file->len + pos; - break; - default: - r->_errno = EINVAL; - return -1; - } - - int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos); - - OSUnlockMutex(file->dev->pMutex); - - if(result == 0) - { - return file->pos; - } - - return result; -} - -static ssize_t fs_dev_write_r (struct _reent *r, void *fd, const char *ptr, size_t len) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return 0; - - if(!file) { - r->_errno = EINVAL; - return 0; - } - - if(!file->dev) { - r->_errno = ENODEV; - return 0; - } - - if(!file->write) - { - r->_errno = EACCES; - return 0; - } - - OSLockMutex(file->dev->pMutex); - - size_t done = 0; - - while(done < len) - { - size_t write_size = len - done; - - int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0); - if(result < 0) - { - r->_errno = result; - break; - } - else if(result == 0) - { - if(write_size > 0) - done = 0; - break; - } - else - { - done += result; - file->pos += result; - } - } - - OSUnlockMutex(file->dev->pMutex); - return done; -} - -static ssize_t fs_dev_read_r (struct _reent *r, void *fd, char *ptr, size_t len) -{ - if(!r) - return 0; - - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!file) { - r->_errno = EINVAL; - return 0; - } - - if(!file->dev) { - r->_errno = ENODEV; - return 0; - } - - if(!file->read) - { - r->_errno = EACCES; - return 0; - } - - OSLockMutex(file->dev->pMutex); - - size_t done = 0; - - while(done < len) - { - size_t read_size = len - done; - - int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0); - if(result < 0) - { - r->_errno = result; - done = 0; - break; - } - else if(result == 0) - { - /*! TODO: error on read_size > 0 */ - break; - } - else - { - done += result; - file->pos += result; - } - } - - OSUnlockMutex(file->dev->pMutex); - return done; -} - - -static int fs_dev_fstat_r (struct _reent *r, void *fd, struct stat *st) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return -1; - - if(!file) { - r->_errno = EINVAL; - return -1; - } - - if(!file->dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(file->dev->pMutex); - - /* Zero out the stat buffer */ - memset(st, 0, sizeof(struct stat)); - - fileStat_s stats; - int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int)fd, &stats); - if(result != 0) { - r->_errno = result; - OSUnlockMutex(file->dev->pMutex); - return -1; - } - - st->st_mode = S_IFREG; - st->st_size = stats.size; - st->st_blocks = (stats.size + 511) >> 9; - st->st_nlink = 1; - - /* Fill in the generic entry stats */ - st->st_dev = stats.id; - st->st_uid = stats.owner_id; - st->st_gid = stats.group_id; - st->st_ino = stats.id; - st->st_atime = stats.mtime; - st->st_ctime = stats.ctime; - st->st_mtime = stats.mtime; - OSUnlockMutex(file->dev->pMutex); - return 0; -} - -static int fs_dev_ftruncate_r (struct _reent *r, void *fd, off_t len) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return -1; - - if(!file) { - r->_errno = EINVAL; - return -1; - } - - if(!file->dev) { - r->_errno = ENODEV; - return -1; - } - - r->_errno = ENOTSUP; - /* TODO */ - return -1; -} - -static int fs_dev_fsync_r (struct _reent *r, void *fd) -{ - fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; - - if(!r) - return -1; - - if(!file) { - r->_errno = EINVAL; - return -1; - } - - if(!file->dev) { - r->_errno = ENODEV; - return -1; - } - - r->_errno = ENOTSUP; - /* TODO */ - return -1; -} - -static int fs_dev_stat_r (struct _reent *r, const char *path, struct stat *st) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dev->pMutex); - - // Zero out the stat buffer - memset(st, 0, sizeof(struct stat)); - - char *real_path = fs_dev_real_path(path, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - fileStat_s stats; - - int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); - - free(real_path); - - if(result < 0) { - r->_errno = result; - OSUnlockMutex(dev->pMutex); - return -1; - } - - // mark root also as directory - st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; - st->st_nlink = 1; - st->st_size = stats.size; - st->st_blocks = (stats.size + 511) >> 9; - // Fill in the generic entry stats - st->st_dev = stats.id; - st->st_uid = stats.owner_id; - st->st_gid = stats.group_id; - st->st_ino = stats.id; - st->st_atime = stats.mtime; - st->st_ctime = stats.ctime; - st->st_mtime = stats.mtime; - - OSUnlockMutex(dev->pMutex); - - return 0; -} - -static int fs_dev_link_r (struct _reent *r, const char *existing, const char *newLink) -{ - if(!r) - return -1; - - r->_errno = ENOTSUP; - return -1; -} - -static int fs_dev_unlink_r (struct _reent *r, const char *name) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(name); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(name, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path); - - free(real_path); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) { - r->_errno = result; - return -1; - } - - return result; -} - -static int fs_dev_chdir_r (struct _reent *r, const char *name) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(name); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(name, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path); - - free(real_path); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) { - r->_errno = result; - return -1; - } - - return 0; -} - -static int fs_dev_rename_r (struct _reent *r, const char *oldName, const char *newName) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(oldName); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - if(!newName) { - r->_errno = EINVAL; - return -1; - } - - OSLockMutex(dev->pMutex); - - char *real_oldpath = fs_dev_real_path(oldName, dev); - if(!real_oldpath) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - char *real_newpath = fs_dev_real_path(newName, dev); - if(!real_newpath) { - r->_errno = ENOMEM; - free(real_oldpath); - OSUnlockMutex(dev->pMutex); - return -1; - } - - //! TODO - int result = -ENOTSUP; - - free(real_oldpath); - free(real_newpath); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) { - r->_errno = result; - return -1; - } - - return 0; - -} - -static int fs_dev_mkdir_r (struct _reent *r, const char *path, int mode) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(path, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode); - - free(real_path); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) { - r->_errno = result; - return -1; - } - - return 0; -} - -static int fs_dev_chmod_r (struct _reent *r, const char *path, int mode) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(path, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, mode); - - free(real_path); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) { - r->_errno = result; - return -1; - } - - return 0; -} - -static int fs_dev_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return -1; - - if(!dev) { - r->_errno = ENODEV; - return -1; - } - - if(!buf) { - r->_errno = EINVAL; - return -1; - } - - OSLockMutex(dev->pMutex); - - // Zero out the stat buffer - memset(buf, 0, sizeof(struct statvfs)); - - char *real_path = fs_dev_real_path(path, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return -1; - } - - uint64_t size; - - int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (uint32_t*)&size); - - free(real_path); - - if(result < 0) { - r->_errno = result; - OSUnlockMutex(dev->pMutex); - return -1; - } - - // File system block size - buf->f_bsize = 512; - - // Fundamental file system block size - buf->f_frsize = 512; - - // Total number of blocks on file system in units of f_frsize - buf->f_blocks = size >> 9; // this is unknown - - // Free blocks available for all and for non-privileged processes - buf->f_bfree = buf->f_bavail = size >> 9; - - // Number of inodes at this point in time - buf->f_files = 0xffffffff; - - // Free inodes available for all and for non-privileged processes - buf->f_ffree = 0xffffffff; - - // File system id - buf->f_fsid = (int)dev; - - // Bit mask of f_flag values. - buf->f_flag = 0; - - // Maximum length of filenames - buf->f_namemax = 255; - - OSUnlockMutex(dev->pMutex); - - return 0; -} - -static DIR_ITER *fs_dev_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) -{ - fs_dev_private_t *dev = fs_dev_get_device_data(path); - - if(!r) - return NULL; - - if(!dev) { - r->_errno = ENODEV; - return NULL; - } - - if(!dirState) { - r->_errno = EINVAL; - return NULL; - } - - fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; - - OSLockMutex(dev->pMutex); - - char *real_path = fs_dev_real_path(path, dev); - if(!real_path) { - r->_errno = ENOMEM; - OSUnlockMutex(dev->pMutex); - return NULL; - } - - int dirHandle; - - int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle); - - free(real_path); - - OSUnlockMutex(dev->pMutex); - - if(result < 0) - { - r->_errno = result; - return NULL; - } - - dirIter->dev = dev; - dirIter->dirHandle = dirHandle; - - return dirState; -} - -static int fs_dev_dirclose_r (struct _reent *r, DIR_ITER *dirState) -{ - fs_dev_dir_entry_t *dirIter; - - if(!r) - return -1; - - if(!dirState) { - r->_errno = EINVAL; - return -1; - } - - dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; - - if(!dirIter->dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dirIter->dev->pMutex); - - int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle); - - OSUnlockMutex(dirIter->dev->pMutex); - - if(result < 0) - { - r->_errno = result; - return -1; - } - return 0; -} - -static int fs_dev_dirreset_r (struct _reent *r, DIR_ITER *dirState) -{ - fs_dev_dir_entry_t *dirIter; - - if(!r) - return -1; - - if(!dirState) { - r->_errno = EINVAL; - return -1; - } - - dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; - - if(!dirIter->dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dirIter->dev->pMutex); - - int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle); - - OSUnlockMutex(dirIter->dev->pMutex); - - if(result < 0) - { - r->_errno = result; - return -1; - } - return 0; -} - -static int fs_dev_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) -{ - fs_dev_dir_entry_t *dirIter; - - if(!r) - return -1; - - if(!dirState) { - r->_errno = EINVAL; - return -1; - } - - dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; - - if(!dirIter->dev) { - r->_errno = ENODEV; - return -1; - } - - OSLockMutex(dirIter->dev->pMutex); - - directoryEntry_s * dir_entry = malloc(sizeof(directoryEntry_s)); - - int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry); - if(result < 0) - { - free(dir_entry); - r->_errno = result; - OSUnlockMutex(dirIter->dev->pMutex); - return -1; - } - - // Fetch the current entry - strcpy(filename, dir_entry->name); - - if(st) - { - memset(st, 0, sizeof(struct stat)); - st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; - st->st_nlink = 1; - st->st_size = dir_entry->stat.size; - st->st_blocks = (dir_entry->stat.size + 511) >> 9; - st->st_dev = dir_entry->stat.id; - st->st_uid = dir_entry->stat.owner_id; - st->st_gid = dir_entry->stat.group_id; - st->st_ino = dir_entry->stat.id; - st->st_atime = dir_entry->stat.mtime; - st->st_ctime = dir_entry->stat.ctime; - st->st_mtime = dir_entry->stat.mtime; - } - - free(dir_entry); - OSUnlockMutex(dirIter->dev->pMutex); - return 0; -} - -// NTFS device driver devoptab -static const devoptab_t devops_fs = { - NULL, /* Device name */ - sizeof (fs_dev_file_state_t), - fs_dev_open_r, - fs_dev_close_r, - fs_dev_write_r, - fs_dev_read_r, - fs_dev_seek_r, - fs_dev_fstat_r, - fs_dev_stat_r, - fs_dev_link_r, - fs_dev_unlink_r, - fs_dev_chdir_r, - fs_dev_rename_r, - fs_dev_mkdir_r, - sizeof (fs_dev_dir_entry_t), - fs_dev_diropen_r, - fs_dev_dirreset_r, - fs_dev_dirnext_r, - fs_dev_dirclose_r, - fs_dev_statvfs_r, - fs_dev_ftruncate_r, - fs_dev_fsync_r, - fs_dev_chmod_r, - NULL, /* fs_dev_fchmod_r */ - NULL /* Device data */ -}; - -static int fs_dev_add_device (const char *name, const char *mount_path, int fsaFd, int isMounted) -{ - devoptab_t *dev = NULL; - char *devname = NULL; - char *devpath = NULL; - int i; - - // Sanity check - if (!name || !mount_path) { - errno = EINVAL; - return -1; - } - - // Allocate a devoptab for this device - dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); - if (!dev) { - errno = ENOMEM; - return -1; - } - - // Use the space allocated at the end of the devoptab for storing the device name - devname = (char*)(dev + 1); - strcpy(devname, name); - - // create private data - fs_dev_private_t *priv = (fs_dev_private_t *)malloc(sizeof(fs_dev_private_t) + strlen(mount_path) + 1); - if(!priv) { - free(dev); - errno = ENOMEM; - return -1; - } - - devpath = (char*)(priv+1); - strcpy(devpath, mount_path); - - // setup private data - priv->mount_path = devpath; - priv->fsaFd = fsaFd; - priv->mounted = isMounted; - priv->pMutex = malloc(OS_MUTEX_SIZE); - - if(!priv->pMutex) { - free(dev); - free(priv); - errno = ENOMEM; - return -1; - } - - OSInitMutex(priv->pMutex); - - // Setup the devoptab - memcpy(dev, &devops_fs, sizeof(devoptab_t)); - dev->name = devname; - dev->deviceData = priv; - - // Add the device to the devoptab table (if there is a free slot) - for (i = 3; i < STD_MAX; i++) { - if (devoptab_list[i] == devoptab_list[0]) { - devoptab_list[i] = dev; - return 0; - } - } - - // failure, free all memory - free(priv); - free(dev); - - // If we reach here then there are no free slots in the devoptab table for this device - errno = EADDRNOTAVAIL; - return -1; -} - -static int fs_dev_remove_device (const char *path) -{ - const devoptab_t *devoptab = NULL; - char name[128] = {0}; - int i; - - if(!path) - return -1; - - // Get the device name from the path - strncpy(name, path, 127); - strtok(name, ":/"); - - // Find and remove the specified device from the devoptab table - // NOTE: We do this manually due to a 'bug' in RemoveDevice - // which ignores names with suffixes and causes names - // like "ntfs" and "ntfs1" to be seen as equals - for (i = 3; i < STD_MAX; i++) { - devoptab = devoptab_list[i]; - if (devoptab && devoptab->name) { - if (strcmp(name, devoptab->name) == 0) { - devoptab_list[i] = devoptab_list[0]; - - if(devoptab->deviceData) - { - fs_dev_private_t *priv = (fs_dev_private_t *)devoptab->deviceData; - - if(priv->mounted) - IOSUHAX_FSA_Unmount(priv->fsaFd, priv->mount_path, 2); - - if(priv->pMutex) - free(priv->pMutex); - free(devoptab->deviceData); - } - - free((devoptab_t*)devoptab); - return 0; - } - } - } - - return -1; -} - -int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path) -{ - int isMounted = 0; - - if(dev_path) - { - isMounted = 1; - - int res = IOSUHAX_FSA_Mount(fsaFd, dev_path, mount_path, 2, 0, 0); - if(res != 0) - { - return res; - } - } - - return fs_dev_add_device(virt_name, mount_path, fsaFd, isMounted); -} - -int unmount_fs(const char *virt_name) -{ - return fs_dev_remove_device(virt_name); -} +/*************************************************************************** + * Copyright (C) 2015 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "os_functions.h" +#include "iosuhax.h" + +typedef struct _fs_dev_private_t { + char *mount_path; + int fsaFd; + int mounted; + void *pMutex; +} fs_dev_private_t; + +typedef struct _fs_dev_file_state_t { + fs_dev_private_t *dev; + int fd; /* File descriptor */ + int flags; /* Opening flags */ + int read; /* True if allowed to read from file */ + int write; /* True if allowed to write to file */ + int append; /* True if allowed to append to file */ + uint32_t pos; /* Current position within the file (in bytes) */ + uint32_t len; /* Total length of the file (in bytes) */ + struct _fs_dev_file_state_t *prevOpenFile; /* The previous entry in a double-linked FILO list of open files */ + struct _fs_dev_file_state_t *nextOpenFile; /* The next entry in a double-linked FILO list of open files */ +} fs_dev_file_state_t; + +typedef struct _fs_dev_dir_entry_t { + fs_dev_private_t *dev; + int dirHandle; +} fs_dev_dir_entry_t; + +static fs_dev_private_t *fs_dev_get_device_data(const char *path) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Search the devoptab table for the specified device name + // NOTE: We do this manually due to a 'bug' in GetDeviceOpTab + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + return (fs_dev_private_t *)devoptab->deviceData; + } + } + } + + return NULL; +} + +static char *fs_dev_real_path (const char *path, fs_dev_private_t *dev) +{ + // Sanity check + if (!path) + return NULL; + + // Move the path pointer to the start of the actual path + if (strchr(path, ':') != NULL) { + path = strchr(path, ':') + 1; + } + + int mount_len = strlen(dev->mount_path); + + char *new_name = (char*)malloc(mount_len + strlen(path) + 1); + if(new_name) { + strcpy(new_name, dev->mount_path); + strcpy(new_name + mount_len, path); + return new_name; + } + return new_name; +} + +static int fs_dev_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fileStruct; + + file->dev = dev; + // Determine which mode the file is opened for + file->flags = flags; + + const char *fsMode; + + // Map flags to open modes + if (flags == 0) { + file->read = 1; + file->write = 0; + file->append = 0; + fsMode = "r"; + } else if (flags == 2) { + file->read = 1; + file->write = 1; + file->append = 0; + fsMode = "r+"; + } else if (flags == 0x601) { + file->read = 0; + file->write = 1; + file->append = 0; + fsMode = "w"; + } else if(flags == 0x602) { + file->read = 1; + file->write = 1; + file->append = 0; + fsMode = "w+"; + } else if(flags == 0x209) { + file->read = 0; + file->write = 1; + file->append = 1; + fsMode = "a"; + } else if(flags == 0x20A) { + file->read = 1; + file->write = 1; + file->append = 1; + fsMode = "a+"; + } else { + r->_errno = EINVAL; + return -1; + } + + + int fd = -1; + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(path, dev); + if(!path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = IOSUHAX_FSA_OpenFile(dev->fsaFd, real_path, fsMode, &fd); + + free(real_path); + + if(result == 0) + { + fileStat_s stats; + result = IOSUHAX_FSA_StatFile(dev->fsaFd, fd, &stats); + if(result != 0) { + IOSUHAX_FSA_CloseFile(dev->fsaFd, fd); + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + file->fd = fd; + file->pos = 0; + file->len = stats.size; + OSUnlockMutex(dev->pMutex); + return (int)file; + } + + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; +} + + +static int fs_dev_close_r (struct _reent *r, void *fd) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + int result = IOSUHAX_FSA_CloseFile(file->dev->fsaFd, file->fd); + + OSUnlockMutex(file->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static off_t fs_dev_seek_r (struct _reent *r, void *fd, off_t pos, int dir) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + switch(dir) + { + case SEEK_SET: + file->pos = pos; + break; + case SEEK_CUR: + file->pos += pos; + break; + case SEEK_END: + file->pos = file->len + pos; + break; + default: + r->_errno = EINVAL; + return -1; + } + + int result = IOSUHAX_FSA_SetFilePos(file->dev->fsaFd, file->fd, file->pos); + + OSUnlockMutex(file->dev->pMutex); + + if(result == 0) + { + return file->pos; + } + + return result; +} + +static ssize_t fs_dev_write_r (struct _reent *r, void *fd, const char *ptr, size_t len) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->write) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t done = 0; + + while(done < len) + { + size_t write_size = len - done; + + int result = IOSUHAX_FSA_WriteFile(file->dev->fsaFd, ptr + done, 0x01, write_size, file->fd, 0); + if(result < 0) + { + r->_errno = result; + break; + } + else if(result == 0) + { + if(write_size > 0) + done = 0; + break; + } + else + { + done += result; + file->pos += result; + } + } + + OSUnlockMutex(file->dev->pMutex); + return done; +} + +static ssize_t fs_dev_read_r (struct _reent *r, void *fd, char *ptr, size_t len) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return 0; + } + + if(!file->read) + { + r->_errno = EACCES; + return 0; + } + + OSLockMutex(file->dev->pMutex); + + size_t done = 0; + + while(done < len) + { + size_t read_size = len - done; + + int result = IOSUHAX_FSA_ReadFile(file->dev->fsaFd, ptr + done, 0x01, read_size, file->fd, 0); + if(result < 0) + { + r->_errno = result; + done = 0; + break; + } + else if(result == 0) + { + //! TODO: error on read_size > 0 + break; + } + else + { + done += result; + file->pos += result; + } + } + + OSUnlockMutex(file->dev->pMutex); + return done; +} + + +static int fs_dev_fstat_r (struct _reent *r, void *fd, struct stat *st) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(file->dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + fileStat_s stats; + int result = IOSUHAX_FSA_StatFile(file->dev->fsaFd, (int)fd, &stats); + if(result != 0) { + r->_errno = result; + OSUnlockMutex(file->dev->pMutex); + return -1; + } + + st->st_mode = S_IFREG; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + st->st_nlink = 1; + + // Fill in the generic entry stats + st->st_dev = stats.id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + OSUnlockMutex(file->dev->pMutex); + return 0; +} + +static int fs_dev_ftruncate_r (struct _reent *r, void *fd, off_t len) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + r->_errno = ENOTSUP; + // TODO + return -1; +} + +static int fs_dev_fsync_r (struct _reent *r, void *fd) +{ + fs_dev_file_state_t *file = (fs_dev_file_state_t *)fd; + if(!file->dev) { + r->_errno = ENODEV; + return -1; + } + + r->_errno = ENOTSUP; + // TODO + return -1; +} + +static int fs_dev_stat_r (struct _reent *r, const char *path, struct stat *st) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(st, 0, sizeof(struct stat)); + + char *real_path = fs_dev_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + fileStat_s stats; + + int result = IOSUHAX_FSA_GetStat(dev->fsaFd, real_path, &stats); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // mark root also as directory + st->st_mode = ((stats.flag & 0x80000000) || (strlen(dev->mount_path) + 1 == strlen(real_path)))? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = stats.size; + st->st_blocks = (stats.size + 511) >> 9; + // Fill in the generic entry stats + st->st_dev = stats.id; + st->st_uid = stats.owner_id; + st->st_gid = stats.group_id; + st->st_ino = stats.id; + st->st_atime = stats.mtime; + st->st_ctime = stats.ctime; + st->st_mtime = stats.mtime; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static int fs_dev_link_r (struct _reent *r, const char *existing, const char *newLink) +{ + r->_errno = ENOTSUP; + return -1; +} + +static int fs_dev_unlink_r (struct _reent *r, const char *name) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = IOSUHAX_FSA_Remove(dev->fsaFd, real_path); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return result; +} + +static int fs_dev_chdir_r (struct _reent *r, const char *name) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(name); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(name, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = IOSUHAX_FSA_ChangeDir(dev->fsaFd, real_path); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int fs_dev_rename_r (struct _reent *r, const char *oldName, const char *newName) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(oldName); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_oldpath = fs_dev_real_path(oldName, dev); + if(!real_oldpath) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + char *real_newpath = fs_dev_real_path(newName, dev); + if(!real_newpath) { + r->_errno = ENOMEM; + free(real_oldpath); + OSUnlockMutex(dev->pMutex); + return -1; + } + + //! TODO + int result = -ENOTSUP; + + free(real_oldpath); + free(real_newpath); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; + +} + +static int fs_dev_mkdir_r (struct _reent *r, const char *path, int mode) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = IOSUHAX_FSA_MakeDir(dev->fsaFd, real_path, mode); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int fs_dev_chmod_r (struct _reent *r, const char *path, int mode) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + int result = IOSUHAX_FSA_ChangeMode(dev->fsaFd, real_path, mode); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) { + r->_errno = result; + return -1; + } + + return 0; +} + +static int fs_dev_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dev->pMutex); + + // Zero out the stat buffer + memset(buf, 0, sizeof(struct statvfs)); + + char *real_path = fs_dev_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return -1; + } + + uint64_t size; + + int result = IOSUHAX_FSA_GetDeviceInfo(dev->fsaFd, real_path, 0x00, (uint32_t*)&size); + + free(real_path); + + if(result < 0) { + r->_errno = result; + OSUnlockMutex(dev->pMutex); + return -1; + } + + // File system block size + buf->f_bsize = 512; + + // Fundamental file system block size + buf->f_frsize = 512; + + // Total number of blocks on file system in units of f_frsize + buf->f_blocks = size >> 9; // this is unknown + + // Free blocks available for all and for non-privileged processes + buf->f_bfree = buf->f_bavail = size >> 9; + + // Number of inodes at this point in time + buf->f_files = 0xffffffff; + + // Free inodes available for all and for non-privileged processes + buf->f_ffree = 0xffffffff; + + // File system id + buf->f_fsid = (int)dev; + + // Bit mask of f_flag values. + buf->f_flag = 0; + + // Maximum length of filenames + buf->f_namemax = 255; + + OSUnlockMutex(dev->pMutex); + + return 0; +} + +static DIR_ITER *fs_dev_diropen_r (struct _reent *r, DIR_ITER *dirState, const char *path) +{ + fs_dev_private_t *dev = fs_dev_get_device_data(path); + if(!dev) { + r->_errno = ENODEV; + return NULL; + } + + fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; + + OSLockMutex(dev->pMutex); + + char *real_path = fs_dev_real_path(path, dev); + if(!real_path) { + r->_errno = ENOMEM; + OSUnlockMutex(dev->pMutex); + return NULL; + } + + int dirHandle; + + int result = IOSUHAX_FSA_OpenDir(dev->fsaFd, real_path, &dirHandle); + + free(real_path); + + OSUnlockMutex(dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return NULL; + } + + dirIter->dev = dev; + dirIter->dirHandle = dirHandle; + + return dirState; +} + +static int fs_dev_dirclose_r (struct _reent *r, DIR_ITER *dirState) +{ + fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = IOSUHAX_FSA_CloseDir(dirIter->dev->fsaFd, dirIter->dirHandle); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int fs_dev_dirreset_r (struct _reent *r, DIR_ITER *dirState) +{ + fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + int result = IOSUHAX_FSA_RewindDir(dirIter->dev->fsaFd, dirIter->dirHandle); + + OSUnlockMutex(dirIter->dev->pMutex); + + if(result < 0) + { + r->_errno = result; + return -1; + } + return 0; +} + +static int fs_dev_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *st) +{ + fs_dev_dir_entry_t *dirIter = (fs_dev_dir_entry_t *)dirState->dirStruct; + if(!dirIter->dev) { + r->_errno = ENODEV; + return -1; + } + + OSLockMutex(dirIter->dev->pMutex); + + directoryEntry_s * dir_entry = malloc(sizeof(directoryEntry_s)); + + int result = IOSUHAX_FSA_ReadDir(dirIter->dev->fsaFd, dirIter->dirHandle, dir_entry); + if(result < 0) + { + free(dir_entry); + r->_errno = result; + OSUnlockMutex(dirIter->dev->pMutex); + return -1; + } + + // Fetch the current entry + strcpy(filename, dir_entry->name); + + if(st) + { + memset(st, 0, sizeof(struct stat)); + st->st_mode = (dir_entry->stat.flag & 0x80000000) ? S_IFDIR : S_IFREG; + st->st_nlink = 1; + st->st_size = dir_entry->stat.size; + st->st_blocks = (dir_entry->stat.size + 511) >> 9; + st->st_dev = dir_entry->stat.id; + st->st_uid = dir_entry->stat.owner_id; + st->st_gid = dir_entry->stat.group_id; + st->st_ino = dir_entry->stat.id; + st->st_atime = dir_entry->stat.mtime; + st->st_ctime = dir_entry->stat.ctime; + st->st_mtime = dir_entry->stat.mtime; + } + + free(dir_entry); + OSUnlockMutex(dirIter->dev->pMutex); + return 0; +} + +// NTFS device driver devoptab +static const devoptab_t devops_fs = { + NULL, /* Device name */ + sizeof (fs_dev_file_state_t), + fs_dev_open_r, + fs_dev_close_r, + fs_dev_write_r, + fs_dev_read_r, + fs_dev_seek_r, + fs_dev_fstat_r, + fs_dev_stat_r, + fs_dev_link_r, + fs_dev_unlink_r, + fs_dev_chdir_r, + fs_dev_rename_r, + fs_dev_mkdir_r, + sizeof (fs_dev_dir_entry_t), + fs_dev_diropen_r, + fs_dev_dirreset_r, + fs_dev_dirnext_r, + fs_dev_dirclose_r, + fs_dev_statvfs_r, + fs_dev_ftruncate_r, + fs_dev_fsync_r, + fs_dev_chmod_r, + NULL, /* fs_dev_fchmod_r */ + NULL /* Device data */ +}; + +static int fs_dev_add_device (const char *name, const char *mount_path, int fsaFd, int isMounted) +{ + devoptab_t *dev = NULL; + char *devname = NULL; + char *devpath = NULL; + int i; + + // Sanity check + if (!name) { + errno = EINVAL; + return -1; + } + + // Allocate a devoptab for this device + dev = (devoptab_t *) malloc(sizeof(devoptab_t) + strlen(name) + 1); + if (!dev) { + errno = ENOMEM; + return -1; + } + + // Use the space allocated at the end of the devoptab for storing the device name + devname = (char*)(dev + 1); + strcpy(devname, name); + + // create private data + fs_dev_private_t *priv = (fs_dev_private_t *)malloc(sizeof(fs_dev_private_t) + strlen(mount_path) + 1); + if(!priv) { + free(dev); + errno = ENOMEM; + return -1; + } + + devpath = (char*)(priv+1); + strcpy(devpath, mount_path); + + // setup private data + priv->mount_path = devpath; + priv->fsaFd = fsaFd; + priv->mounted = isMounted; + priv->pMutex = malloc(OS_MUTEX_SIZE); + + if(!priv->pMutex) { + free(dev); + free(priv); + errno = ENOMEM; + return -1; + } + + OSInitMutex(priv->pMutex); + + // Setup the devoptab + memcpy(dev, &devops_fs, sizeof(devoptab_t)); + dev->name = devname; + dev->deviceData = priv; + + // Add the device to the devoptab table (if there is a free slot) + for (i = 3; i < STD_MAX; i++) { + if (devoptab_list[i] == devoptab_list[0]) { + devoptab_list[i] = dev; + return 0; + } + } + + // failure, free all memory + free(priv); + free(dev); + + // If we reach here then there are no free slots in the devoptab table for this device + errno = EADDRNOTAVAIL; + return -1; +} + +static int fs_dev_remove_device (const char *path) +{ + const devoptab_t *devoptab = NULL; + char name[128] = {0}; + int i; + + // Get the device name from the path + strncpy(name, path, 127); + strtok(name, ":/"); + + // Find and remove the specified device from the devoptab table + // NOTE: We do this manually due to a 'bug' in RemoveDevice + // which ignores names with suffixes and causes names + // like "ntfs" and "ntfs1" to be seen as equals + for (i = 3; i < STD_MAX; i++) { + devoptab = devoptab_list[i]; + if (devoptab && devoptab->name) { + if (strcmp(name, devoptab->name) == 0) { + devoptab_list[i] = devoptab_list[0]; + + if(devoptab->deviceData) + { + fs_dev_private_t *priv = (fs_dev_private_t *)devoptab->deviceData; + + if(priv->mounted) + IOSUHAX_FSA_Unmount(priv->fsaFd, priv->mount_path, 2); + + if(priv->pMutex) + free(priv->pMutex); + free(devoptab->deviceData); + } + + free((devoptab_t*)devoptab); + return 0; + } + } + } + + return -1; +} + +int mount_fs(const char *virt_name, int fsaFd, const char *dev_path, const char *mount_path) +{ + int isMounted = 0; + + if(dev_path) + { + isMounted = 1; + + int res = IOSUHAX_FSA_Mount(fsaFd, dev_path, mount_path, 2, 0, 0); + if(res != 0) + { + return res; + } + } + + return fs_dev_add_device(virt_name, mount_path, fsaFd, isMounted); +} + +int unmount_fs(const char *virt_name) +{ + return fs_dev_remove_device(virt_name); +} diff --git a/deps/libiosuhax/iosuhax_disc_interface.c b/deps/libiosuhax/source/iosuhax_disc_interface.c similarity index 92% rename from deps/libiosuhax/iosuhax_disc_interface.c rename to deps/libiosuhax/source/iosuhax_disc_interface.c index dd1291ec27..1160fc1924 100644 --- a/deps/libiosuhax/iosuhax_disc_interface.c +++ b/deps/libiosuhax/source/iosuhax_disc_interface.c @@ -1,262 +1,262 @@ -/*************************************************************************** - * Copyright (C) 2016 - * by Dimok - * - * This software is provided 'as-is', without any express or implied - * warranty. In no event will the authors be held liable for any - * damages arising from the use of this software. - * - * Permission is granted to anyone to use this software for any - * purpose, including commercial applications, and to alter it and - * redistribute it freely, subject to the following restrictions: - * - * 1. The origin of this software must not be misrepresented; you - * must not claim that you wrote the original software. If you use - * this software in a product, an acknowledgment in the product - * documentation would be appreciated but is not required. - * - * 2. Altered source versions must be plainly marked as such, and - * must not be misrepresented as being the original software. - * - * 3. This notice may not be removed or altered from any source - * distribution. - ***************************************************************************/ -#include -#include -#include "iosuhax.h" -#include "iosuhax_disc_interface.h" - -#define FSA_REF_SD 0x01 -#define FSA_REF_USB 0x02 - -static int initialized = 0; - -static int fsaFdSd = 0; -static int fsaFdUsb = 0; -static int sdioFd = 0; -static int usbFd = 0; - -static void IOSUHAX_disc_io_initialize(void) -{ - if(initialized == 0) - { - initialized = 1; - fsaFdSd = -1; - fsaFdUsb = -1; - sdioFd = -1; - usbFd = -1; - } -} - -static bool IOSUHAX_disc_io_fsa_open(int fsaFd) -{ - IOSUHAX_disc_io_initialize(); - - if(IOSUHAX_Open(NULL) < 0) - return false; - - if(fsaFd == FSA_REF_SD) - { - if(fsaFdSd < 0) - { - fsaFdSd = IOSUHAX_FSA_Open(); - } - - if(fsaFdSd >= 0) - return true; - } - else if(fsaFd == FSA_REF_USB) - { - if(fsaFdUsb < 0) - { - fsaFdUsb = IOSUHAX_FSA_Open(); - } - - if(fsaFdUsb >= 0) - return true; - } - - return false; -} - -static void IOSUHAX_disc_io_fsa_close(int fsaFd) -{ - if(fsaFd == FSA_REF_SD) - { - if(fsaFdSd >= 0) - { - IOSUHAX_FSA_Close(fsaFdSd); - fsaFdSd = -1; - } - } - else if(fsaFd == FSA_REF_USB) - { - if(fsaFdUsb >= 0) - { - IOSUHAX_FSA_Close(fsaFdUsb); - fsaFdUsb = -1; - } - } -} - -static bool IOSUHAX_sdio_startup(void) -{ - if(!IOSUHAX_disc_io_fsa_open(FSA_REF_SD)) - return false; - - if(sdioFd < 0) - { - int res = IOSUHAX_FSA_RawOpen(fsaFdSd, "/dev/sdcard01", &sdioFd); - if(res < 0) - { - IOSUHAX_disc_io_fsa_close(FSA_REF_SD); - sdioFd = -1; - } - } - - return (sdioFd >= 0); -} - -static bool IOSUHAX_sdio_isInserted(void) -{ - //! TODO: check for SD card inserted with IOSUHAX_FSA_GetDeviceInfo() - return initialized && (fsaFdSd >= 0) && (sdioFd >= 0); -} - -static bool IOSUHAX_sdio_clearStatus(void) -{ - return true; -} - -static bool IOSUHAX_sdio_shutdown(void) -{ - if(!IOSUHAX_sdio_isInserted()) - return false; - - IOSUHAX_FSA_RawClose(fsaFdSd, sdioFd); - IOSUHAX_disc_io_fsa_close(FSA_REF_SD); - sdioFd = -1; - return true; -} - -static bool IOSUHAX_sdio_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) -{ - if(!IOSUHAX_sdio_isInserted() || !buffer) - return false; - - int res = IOSUHAX_FSA_RawRead(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); - if(res < 0) - { - return false; - } - - return true; -} - -static bool IOSUHAX_sdio_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) -{ - if(!IOSUHAX_sdio_isInserted() || !buffer) - return false; - - int res = IOSUHAX_FSA_RawWrite(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); - if(res < 0) - { - return false; - } - - return true; -} - -const DISC_INTERFACE IOSUHAX_sdio_disc_interface = -{ - DEVICE_TYPE_WII_U_SD, - FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD, - IOSUHAX_sdio_startup, - IOSUHAX_sdio_isInserted, - IOSUHAX_sdio_readSectors, - IOSUHAX_sdio_writeSectors, - IOSUHAX_sdio_clearStatus, - IOSUHAX_sdio_shutdown -}; - -static bool IOSUHAX_usb_startup(void) -{ - if(!IOSUHAX_disc_io_fsa_open(FSA_REF_USB)) - return false; - - if(usbFd < 0) - { - int res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb01", &usbFd); - if(res < 0) - { - res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb02", &usbFd); - if(res < 0) - { - IOSUHAX_disc_io_fsa_close(FSA_REF_USB); - usbFd = -1; - } - } - } - return (usbFd >= 0); -} - -static bool IOSUHAX_usb_isInserted(void) -{ - return initialized && (fsaFdUsb >= 0) && (usbFd >= 0); -} - -static bool IOSUHAX_usb_clearStatus(void) -{ - return true; -} - -static bool IOSUHAX_usb_shutdown(void) -{ - if(!IOSUHAX_usb_isInserted()) - return false; - - IOSUHAX_FSA_RawClose(fsaFdUsb, usbFd); - IOSUHAX_disc_io_fsa_close(FSA_REF_USB); - usbFd = -1; - return true; -} - -static bool IOSUHAX_usb_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) -{ - if(!IOSUHAX_usb_isInserted() || !buffer) - return false; - - int res = IOSUHAX_FSA_RawRead(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); - if(res < 0) - { - return false; - } - - return true; -} - -static bool IOSUHAX_usb_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) -{ - if(!IOSUHAX_usb_isInserted() || !buffer) - return false; - - int res = IOSUHAX_FSA_RawWrite(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); - if(res < 0) - { - return false; - } - - return true; -} - -const DISC_INTERFACE IOSUHAX_usb_disc_interface = -{ - DEVICE_TYPE_WII_U_USB, - FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB, - IOSUHAX_usb_startup, - IOSUHAX_usb_isInserted, - IOSUHAX_usb_readSectors, - IOSUHAX_usb_writeSectors, - IOSUHAX_usb_clearStatus, - IOSUHAX_usb_shutdown -}; +/*************************************************************************** + * Copyright (C) 2016 + * by Dimok + * + * This software is provided 'as-is', without any express or implied + * warranty. In no event will the authors be held liable for any + * damages arising from the use of this software. + * + * Permission is granted to anyone to use this software for any + * purpose, including commercial applications, and to alter it and + * redistribute it freely, subject to the following restrictions: + * + * 1. The origin of this software must not be misrepresented; you + * must not claim that you wrote the original software. If you use + * this software in a product, an acknowledgment in the product + * documentation would be appreciated but is not required. + * + * 2. Altered source versions must be plainly marked as such, and + * must not be misrepresented as being the original software. + * + * 3. This notice may not be removed or altered from any source + * distribution. + ***************************************************************************/ +#include +#include +#include "iosuhax.h" +#include "iosuhax_disc_interface.h" + +#define FSA_REF_SD 0x01 +#define FSA_REF_USB 0x02 + +static int initialized = 0; + +static int fsaFdSd = 0; +static int fsaFdUsb = 0; +static int sdioFd = 0; +static int usbFd = 0; + +static void IOSUHAX_disc_io_initialize(void) +{ + if(initialized == 0) + { + initialized = 1; + fsaFdSd = -1; + fsaFdUsb = -1; + sdioFd = -1; + usbFd = -1; + } +} + +static bool IOSUHAX_disc_io_fsa_open(int fsaFd) +{ + IOSUHAX_disc_io_initialize(); + + if(IOSUHAX_Open(NULL) < 0) + return false; + + if(fsaFd == FSA_REF_SD) + { + if(fsaFdSd < 0) + { + fsaFdSd = IOSUHAX_FSA_Open(); + } + + if(fsaFdSd >= 0) + return true; + } + else if(fsaFd == FSA_REF_USB) + { + if(fsaFdUsb < 0) + { + fsaFdUsb = IOSUHAX_FSA_Open(); + } + + if(fsaFdUsb >= 0) + return true; + } + + return false; +} + +static void IOSUHAX_disc_io_fsa_close(int fsaFd) +{ + if(fsaFd == FSA_REF_SD) + { + if(fsaFdSd >= 0) + { + IOSUHAX_FSA_Close(fsaFdSd); + fsaFdSd = -1; + } + } + else if(fsaFd == FSA_REF_USB) + { + if(fsaFdUsb >= 0) + { + IOSUHAX_FSA_Close(fsaFdUsb); + fsaFdUsb = -1; + } + } +} + +static bool IOSUHAX_sdio_startup(void) +{ + if(!IOSUHAX_disc_io_fsa_open(FSA_REF_SD)) + return false; + + if(sdioFd < 0) + { + int res = IOSUHAX_FSA_RawOpen(fsaFdSd, "/dev/sdcard01", &sdioFd); + if(res < 0) + { + IOSUHAX_disc_io_fsa_close(FSA_REF_SD); + sdioFd = -1; + } + } + + return (sdioFd >= 0); +} + +static bool IOSUHAX_sdio_isInserted(void) +{ + //! TODO: check for SD card inserted with IOSUHAX_FSA_GetDeviceInfo() + return initialized && (fsaFdSd >= 0) && (sdioFd >= 0); +} + +static bool IOSUHAX_sdio_clearStatus(void) +{ + return true; +} + +static bool IOSUHAX_sdio_shutdown(void) +{ + if(!IOSUHAX_sdio_isInserted()) + return false; + + IOSUHAX_FSA_RawClose(fsaFdSd, sdioFd); + IOSUHAX_disc_io_fsa_close(FSA_REF_SD); + sdioFd = -1; + return true; +} + +static bool IOSUHAX_sdio_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) +{ + if(!IOSUHAX_sdio_isInserted()) + return false; + + int res = IOSUHAX_FSA_RawRead(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); + if(res < 0) + { + return false; + } + + return true; +} + +static bool IOSUHAX_sdio_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) +{ + if(!IOSUHAX_sdio_isInserted()) + return false; + + int res = IOSUHAX_FSA_RawWrite(fsaFdSd, buffer, 512, numSectors, sector, sdioFd); + if(res < 0) + { + return false; + } + + return true; +} + +const DISC_INTERFACE IOSUHAX_sdio_disc_interface = +{ + DEVICE_TYPE_WII_U_SD, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_SD, + IOSUHAX_sdio_startup, + IOSUHAX_sdio_isInserted, + IOSUHAX_sdio_readSectors, + IOSUHAX_sdio_writeSectors, + IOSUHAX_sdio_clearStatus, + IOSUHAX_sdio_shutdown +}; + +static bool IOSUHAX_usb_startup(void) +{ + if(!IOSUHAX_disc_io_fsa_open(FSA_REF_USB)) + return false; + + if(usbFd < 0) + { + int res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb01", &usbFd); + if(res < 0) + { + res = IOSUHAX_FSA_RawOpen(fsaFdUsb, "/dev/usb02", &usbFd); + if(res < 0) + { + IOSUHAX_disc_io_fsa_close(FSA_REF_USB); + usbFd = -1; + } + } + } + return (usbFd >= 0); +} + +static bool IOSUHAX_usb_isInserted(void) +{ + return initialized && (fsaFdUsb >= 0) && (usbFd >= 0); +} + +static bool IOSUHAX_usb_clearStatus(void) +{ + return true; +} + +static bool IOSUHAX_usb_shutdown(void) +{ + if(!IOSUHAX_usb_isInserted()) + return false; + + IOSUHAX_FSA_RawClose(fsaFdUsb, usbFd); + IOSUHAX_disc_io_fsa_close(FSA_REF_USB); + usbFd = -1; + return true; +} + +static bool IOSUHAX_usb_readSectors(uint32_t sector, uint32_t numSectors, void* buffer) +{ + if(!IOSUHAX_usb_isInserted()) + return false; + + int res = IOSUHAX_FSA_RawRead(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); + if(res < 0) + { + return false; + } + + return true; +} + +static bool IOSUHAX_usb_writeSectors(uint32_t sector, uint32_t numSectors, const void* buffer) +{ + if(!IOSUHAX_usb_isInserted()) + return false; + + int res = IOSUHAX_FSA_RawWrite(fsaFdUsb, buffer, 512, numSectors, sector, usbFd); + if(res < 0) + { + return false; + } + + return true; +} + +const DISC_INTERFACE IOSUHAX_usb_disc_interface = +{ + DEVICE_TYPE_WII_U_USB, + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE | FEATURE_WII_U_USB, + IOSUHAX_usb_startup, + IOSUHAX_usb_isInserted, + IOSUHAX_usb_readSectors, + IOSUHAX_usb_writeSectors, + IOSUHAX_usb_clearStatus, + IOSUHAX_usb_shutdown +}; diff --git a/deps/libiosuhax/source/os_functions.h b/deps/libiosuhax/source/os_functions.h new file mode 100644 index 0000000000..a9d9d00317 --- /dev/null +++ b/deps/libiosuhax/source/os_functions.h @@ -0,0 +1,28 @@ +#ifndef __OS_FUNCTIONS_H_ +#define __OS_FUNCTIONS_H_ + +#ifdef __cplusplus +extern "C" { +#endif + +#define OS_MUTEX_SIZE 44 + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! Mutex functions +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern void OSInitMutex(void* mutex); +extern void OSLockMutex(void* mutex); +extern void OSUnlockMutex(void* mutex); + +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +//! IOS function +//!---------------------------------------------------------------------------------------------------------------------------------------------------------------------------- +extern int IOS_Ioctl(int fd, unsigned int request, void *input_buffer,unsigned int input_buffer_len, void *output_buffer, unsigned int output_buffer_len); +extern int IOS_Open(char *path, unsigned int mode); +extern int IOS_Close(int fd); + +#ifdef __cplusplus +} +#endif + +#endif // __OS_FUNCTIONS_H_ diff --git a/deps/switchres/display_windows.cpp b/deps/switchres/display_windows.cpp index 0372ccc916..f8186a972a 100644 --- a/deps/switchres/display_windows.cpp +++ b/deps/switchres/display_windows.cpp @@ -16,6 +16,11 @@ #include "display_windows.h" #include "log.h" +typedef struct ENUM_INFO +{ + int index; + HMONITOR h_monitor; +} ENUM_INFO; //============================================================ // windows_display::windows_display @@ -41,8 +46,54 @@ windows_display::~windows_display() // windows_display::init //============================================================ +int CALLBACK monitor_by_index(HMONITOR h_monitor, HDC, LPRECT, LPARAM data) +{ + ENUM_INFO *mon_info = (ENUM_INFO*) data; + if (--mon_info->index < 0) + { + mon_info->h_monitor = h_monitor; + return false; + } + return true; +} + bool windows_display::init() { + char display[32] = {}; + + // If monitor is passed by index, find the matching device + if (strlen(m_ds.screen) == 1) + { + int monitor_index = m_ds.screen[0] - '0'; + if (monitor_index < 0 || monitor_index > 9) + { + log_error("Switchres: bad monitor index %d\n", monitor_index); + return false; + } + + ENUM_INFO mon_info; + mon_info.index = monitor_index; + mon_info.h_monitor = NULL; + + EnumDisplayMonitors(NULL, NULL, monitor_by_index, (LPARAM)&mon_info); + if (mon_info.h_monitor != NULL) + { + MONITORINFOEXA info = {}; + info.cbSize = sizeof(info); + GetMonitorInfoA(mon_info.h_monitor, &info); + snprintf(display, sizeof(display) -1, "%s", info.szDevice); + log_info("display %s\n", display); + } + else + { + log_error("Swichres: couldn't find handle for monitor index %d\n", monitor_index); + return false; + } + } + else + strncpy(display, m_ds.screen, sizeof(display)-1); + + // Find the display by device name, or "auto" for primary display DISPLAY_DEVICEA lpDisplayDevice[DISPLAY_MAX]; int idev = 0; int found = -1; @@ -55,8 +106,8 @@ bool windows_display::init() if (EnumDisplayDevicesA(NULL, idev, &lpDisplayDevice[idev], 0) == FALSE) break; - if ((!strcmp(m_ds.screen, "auto") && (lpDisplayDevice[idev].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) - || !strcmp(m_ds.screen, lpDisplayDevice[idev].DeviceName) || m_ds.screen[0] - '0' == idev) + if ((!strcmp(display, "auto") && (lpDisplayDevice[idev].StateFlags & DISPLAY_DEVICE_PRIMARY_DEVICE)) + || !strcmp(display, lpDisplayDevice[idev].DeviceName)) found = idev; idev++; diff --git a/deps/switchres/log.cpp b/deps/switchres/log.cpp index fd990422f2..3749af33d9 100644 --- a/deps/switchres/log.cpp +++ b/deps/switchres/log.cpp @@ -14,8 +14,8 @@ #include "log.h" -enum log_verbosity { NONE, ERROR, INFO, DBG }; -static log_verbosity log_level = INFO; +enum log_verbosity { NONE, SR_ERROR, SR_INFO, SR_DEBUG }; +static log_verbosity log_level = SR_INFO; void log_dummy(const char *, ...) {} @@ -36,21 +36,21 @@ LOG_ERROR log_error_bak = &log_dummy; void set_log_verbose(void *func_ptr) { - if (log_level >= DBG) + if (log_level >= SR_DEBUG) log_verbose = (LOG_VERBOSE)func_ptr; log_verbose_bak = (LOG_VERBOSE)func_ptr; } void set_log_info(void *func_ptr) { - if (log_level >= INFO) + if (log_level >= SR_INFO) log_info = (LOG_INFO)func_ptr; log_info_bak = (LOG_INFO)func_ptr; } void set_log_error(void *func_ptr) { - if (log_level >= ERROR) + if (log_level >= SR_ERROR) log_error = (LOG_ERROR)func_ptr; log_error_bak = (LOG_ERROR)func_ptr; } @@ -60,19 +60,19 @@ void set_log_verbosity(int level) // Keep the log in the enum bounds if (level < NONE) level = NONE; - if(level > DBG) - level = DBG; + if(level > SR_DEBUG) + level = SR_DEBUG; log_error = &log_dummy; log_info = &log_dummy; log_verbose = &log_dummy; - if (level >= ERROR) + if (level >= SR_ERROR) log_error = log_error_bak; - if (level >= INFO) + if (level >= SR_INFO) log_info = log_info_bak; - if (level >= DBG) + if (level >= SR_DEBUG) log_verbose = log_verbose_bak; -} +} \ No newline at end of file diff --git a/deps/switchres/switchres.cpp b/deps/switchres/switchres.cpp index b5721d9b39..527aa35aea 100644 --- a/deps/switchres/switchres.cpp +++ b/deps/switchres/switchres.cpp @@ -23,8 +23,10 @@ const string WHITESPACE = " \n\r\t\f\v"; #if defined(_WIN32) #define SR_CONFIG_PATHS ";.\\;.\\ini\\;" -#else +#elif defined(__linux__) #define SR_CONFIG_PATHS ";./;./ini/;/etc/;" +#else + #define SR_CONFIG_PATHS ";./" #endif //============================================================ diff --git a/dingux/dingux_utils.c b/dingux/dingux_utils.c index c13649d1b5..ec4eca19f1 100644 --- a/dingux/dingux_utils.c +++ b/dingux/dingux_utils.c @@ -17,12 +17,13 @@ #include #include - -#if defined(DINGUX_BETA) #include -#include +#if defined(RS90) +#include #endif +#include + #include "dingux_utils.h" #define DINGUX_ALLOW_DOWNSCALING_FILE "/sys/devices/platform/jz-lcd.0/allow_downscaling" @@ -32,6 +33,14 @@ #define DINGUX_SHARPNESS_DOWNSCALING_FILE "/sys/devices/platform/jz-lcd.0/sharpness_downscaling" #define DINGUX_BATTERY_CAPACITY_FILE "/sys/class/power_supply/battery/capacity" +/* Base path defines */ +#define DINGUX_HOME_ENVAR "HOME" +#define DINGUX_BASE_DIR "retroarch" +#define DINGUX_BASE_DIR_HIDDEN ".retroarch" +#define DINGUX_RS90_MEDIA_PATH "/media" +#define DINGUX_RS90_DEFAULT_SD_PATH "/media/mmcblk0p1" +#define DINGUX_RS90_DATA_PATH "/media/data" + /* OpenDingux Beta defines */ #define DINGUX_BATTERY_VOLTAGE_MIN "/sys/class/power_supply/jz-battery/voltage_min_design" #define DINGUX_BATTERY_VOLTAGE_MAX "/sys/class/power_supply/jz-battery/voltage_max_design" @@ -302,3 +311,80 @@ int dingux_get_battery_level(void) return dingux_read_battery_sys_file(DINGUX_BATTERY_CAPACITY_FILE); #endif } + +/* Fetches the path of the base 'retroarch' + * directory */ +void dingux_get_base_path(char *path, size_t len) +{ + const char *home = NULL; +#if defined(RS90) + struct string_list *dir_list = NULL; +#endif + + if (!path || (len < 1)) + return; + +#if defined(RS90) + /* The RS-90 home directory is located on the + * device's internal storage. This has limited + * space (a total of only 256MB), such that it + * is impractical to store cores and user files + * here. We therefore attempt to use a base + * path on the external microsd card */ + + /* Get list of directories in /media */ + dir_list = dir_list_new(DINGUX_RS90_MEDIA_PATH, + NULL, true, true, false, false); + + if (dir_list) + { + size_t i; + bool path_found = false; + + for (i = 0; i < dir_list->size; i++) + { + const char *dir_path = dir_list->elems[i].data; + int dir_type = dir_list->elems[i].attr.i; + + /* Skip files and invalid entries */ + if ((dir_type != RARCH_DIRECTORY) || + string_is_empty(dir_path) || + string_is_equal(dir_path, DINGUX_RS90_DATA_PATH)) + continue; + + /* Build 'retroarch' subdirectory path */ + snprintf(path, len, "%s%c%s", dir_path, + PATH_DEFAULT_SLASH_C(), DINGUX_BASE_DIR); + + /* We can use this subdirectory path if: + * - Directory corresponds to an unlabelled + * microsd card + * - Subdirectory already exists */ + if (string_is_equal(dir_path, DINGUX_RS90_DEFAULT_SD_PATH) || + path_is_directory(path)) + { + path_found = true; + break; + } + } + + dir_list_free(dir_list); + + if (path_found) + return; + } +#endif + /* Get home directory */ + home = getenv(DINGUX_HOME_ENVAR); + + /* If a home directory is found (which should + * always be the case), base path is "$HOME/.retroarch" + * > If home path is unset, use existing UNIX frontend + * driver default of "retroarch" (this will ultimately + * fail, but there is nothing else we can do...) */ + if (home) + snprintf(path, len, "%s%c%s", home, + PATH_DEFAULT_SLASH_C(), DINGUX_BASE_DIR_HIDDEN); + else + strlcpy(path, DINGUX_BASE_DIR, len); +} diff --git a/dingux/dingux_utils.h b/dingux/dingux_utils.h index bf13140fca..4aa71b578a 100644 --- a/dingux/dingux_utils.h +++ b/dingux/dingux_utils.h @@ -101,6 +101,10 @@ bool dingux_ipu_reset(void); /* Fetches internal battery level */ int dingux_get_battery_level(void); +/* Fetches the path of the base 'retroarch' + * directory */ +void dingux_get_base_path(char *path, size_t len); + RETRO_END_DECLS #endif diff --git a/disk_index_file.c b/disk_index_file.c index 236bbf5ae6..0ebd122db2 100644 --- a/disk_index_file.c +++ b/disk_index_file.c @@ -47,11 +47,9 @@ static bool DCifJSONObjectMemberHandler(void* context, const char *pValue, size_ { DCifJSONContext *pCtx = (DCifJSONContext*)context; + /* something went wrong */ if (pCtx->current_entry_str_val) - { - /* something went wrong */ return false; - } if (length) { diff --git a/file_path_special.c b/file_path_special.c index 9b5b7d567b..e23ae4287e 100644 --- a/file_path_special.c +++ b/file_path_special.c @@ -37,6 +37,10 @@ #include #endif +#if defined(DINGUX) +#include "dingux/dingux_utils.h" +#endif + #include #include #include @@ -104,13 +108,8 @@ bool fill_pathname_application_data(char *s, size_t len) return true; } #elif defined(DINGUX) - const char *appdata = getenv("HOME"); - - if (appdata) - { - fill_pathname_join(s, appdata, "/.retroarch", len); - return true; - } + dingux_get_base_path(s, len); + return true; #elif !defined(RARCH_CONSOLE) const char *xdg = getenv("XDG_CONFIG_HOME"); const char *appdata = getenv("HOME"); @@ -305,6 +304,21 @@ void fill_pathname_application_special(char *s, strlcpy(s, dir_assets, len); fill_pathname_slash(s, len); +#if defined(WIIU) || defined(VITA) + /* Smaller 46x46 icons look better on low-dpi devices */ + /* ozone */ + strlcat(s, "ozone", len); + fill_pathname_slash(s, len); + + /* png */ + strlcat(s, "png", len); + fill_pathname_slash(s, len); + + /* Icons path */ + strlcat(s, "icons", len); + fill_pathname_slash(s, len); +#else + /* Otherwise, use large 256x256 icons */ /* xmb */ strlcat(s, "xmb", len); fill_pathname_slash(s, len); @@ -316,6 +330,7 @@ void fill_pathname_application_special(char *s, /* Icons path */ strlcat(s, "png", len); fill_pathname_slash(s, len); +#endif } #endif break; diff --git a/frontend/drivers/platform_ps2.c b/frontend/drivers/platform_ps2.c index 9014416bf3..40059c6687 100644 --- a/frontend/drivers/platform_ps2.c +++ b/frontend/drivers/platform_ps2.c @@ -127,7 +127,9 @@ static void load_modules() /* USB */ SifExecModuleBuffer(&usbd_irx, size_usbd_irx, 0, NULL, NULL); - SifExecModuleBuffer(&usbhdfsd_irx, size_usbhdfsd_irx, 0, NULL, NULL); + SifExecModuleBuffer(&bdm_irx, size_bdm_irx, 0, NULL, NULL); + SifExecModuleBuffer(&bdmfs_vfat_irx, size_bdmfs_vfat_irx, 0, NULL, NULL); + SifExecModuleBuffer(&usbmass_bd_irx, size_usbmass_bd_irx, 0, NULL, NULL); #if !defined(DEBUG) /* CDFS */ diff --git a/frontend/drivers/platform_unix.c b/frontend/drivers/platform_unix.c index 8cc3231c2c..44946f9c93 100644 --- a/frontend/drivers/platform_unix.c +++ b/frontend/drivers/platform_unix.c @@ -1349,15 +1349,15 @@ static void frontend_unix_set_screen_brightness(int value) char *buffer = NULL; char svalue[16] = {0}; unsigned int max_brightness = 100; - #if !defined(HAVE_LAKKA_SWITCH) - filestream_read_file("/sys/devices/platform/backlight/backlight/backlight/max_brightness", + + /* Device tree should have 'label = "backlight";' if control is desirable */ + filestream_read_file("/sys/class/backlight/backlight/max_brightness", &buffer, NULL); if (buffer) { sscanf(buffer, "%u", &max_brightness); free(buffer); } - #endif /* Calculate the brightness */ value = (value * max_brightness) / 100; @@ -1792,6 +1792,9 @@ static void frontend_unix_get_env(int *argc, } #else char base_path[PATH_MAX] = {0}; +#if defined(DINGUX) + dingux_get_base_path(base_path, sizeof(base_path)); +#else const char *xdg = getenv("XDG_CONFIG_HOME"); const char *home = getenv("HOME"); @@ -1803,14 +1806,11 @@ static void frontend_unix_get_env(int *argc, else if (home) { strlcpy(base_path, home, sizeof(base_path)); -#if defined(DINGUX) - strlcat(base_path, "/.retroarch", sizeof(base_path)); -#else strlcat(base_path, "/.config/retroarch", sizeof(base_path)); -#endif } else strcpy_literal(base_path, "retroarch"); +#endif fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE], base_path, "cores", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE])); @@ -2154,10 +2154,14 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content) #else char base_path[PATH_MAX] = {0}; char udisks_media_path[PATH_MAX] = {0}; - const char *xdg = getenv("XDG_CONFIG_HOME"); const char *home = getenv("HOME"); const char *user = getenv("USER"); +#if defined(DINGUX) + dingux_get_base_path(base_path, sizeof(base_path)); +#else + const char *xdg = getenv("XDG_CONFIG_HOME"); + if (xdg) { strlcpy(base_path, xdg, sizeof(base_path)); @@ -2166,12 +2170,9 @@ static int frontend_unix_parse_drive_list(void *data, bool load_content) else if (home) { strlcpy(base_path, home, sizeof(base_path)); -#if defined(DINGUX) - strlcat(base_path, "/.retroarch", sizeof(base_path)); -#else strlcat(base_path, "/.config/retroarch", sizeof(base_path)); -#endif } +#endif strlcpy(udisks_media_path, "/run/media", sizeof(udisks_media_path)); if (user) @@ -2827,7 +2828,7 @@ frontend_ctx_driver_t frontend_ctx_unix = { #endif #if defined(HAVE_LAKKA_SWITCH) || (defined(HAVE_LAKKA) && defined(HAVE_ODROIDGO2)) frontend_unix_set_screen_brightness,/* set_screen_brightness */ -#else +#else NULL, /* set_screen_brightness */ #endif frontend_unix_watch_path_for_changes, diff --git a/gfx/common/x11_common.c b/gfx/common/x11_common.c index 9c804be1f8..f9aebf5040 100644 --- a/gfx/common/x11_common.c +++ b/gfx/common/x11_common.c @@ -199,11 +199,27 @@ static void xdg_screensaver_inhibit(Window wnd) { int ret; char cmd[64]; + char title[128]; cmd[0] = '\0'; + title[0] = '\0'; RARCH_LOG("[X11]: Suspending screensaver (X11, xdg-screensaver).\n"); + if (g_x11_dpy && g_x11_win) + { + /* Make sure the window has a title, even if it's a bogus one, otherwise + * xdg-screensaver will fail and report to stderr, framing RA for its bug. + * A single space character is used so that the title bar stays visibly + * the same, as if there's no title at all. */ + video_driver_get_window_title(title, sizeof(title)); + if (strlen(title) == 0) + snprintf(title, sizeof(title), " "); + XChangeProperty(g_x11_dpy, g_x11_win, XA_WM_NAME, XA_STRING, + 8, PropModeReplace, (const unsigned char*) title, + strlen(title)); + } + snprintf(cmd, sizeof(cmd), "xdg-screensaver suspend 0x%x", (int)wnd); ret = system(cmd); diff --git a/gfx/drivers/rsx_gfx.c b/gfx/drivers/rsx_gfx.c index 1fa86f06a1..01ea8183e7 100644 --- a/gfx/drivers/rsx_gfx.c +++ b/gfx/drivers/rsx_gfx.c @@ -65,6 +65,10 @@ #define MAX_BUFFERS 2 +#define rsx_context_bind_hw_render(rsx, enable) \ + if (rsx->shared_context_use) \ + rsx->ctx_driver->bind_hw_render(rsx->ctx_data, enable) + typedef struct { int height; @@ -81,21 +85,20 @@ typedef struct float u; float y; float x; -} gcm_scale_vector_t; +} rsx_scale_vector_t; typedef struct { s16 x0, y0, x1, y1; s16 u0, v0, u1, v1; -} gcm_vertex_t; +} rsx_vertex_t; -typedef struct gcm_video -{ +typedef struct { video_viewport_t vp; rsxBuffer buffers[MAX_BUFFERS]; rsxBuffer menuBuffers[MAX_BUFFERS]; int currentBuffer, menuBuffer; - gcmContextData *context; + gcmContextData* context; u16 width; u16 height; bool menu_frame_enable; @@ -103,24 +106,62 @@ typedef struct gcm_video bool vsync; u32 depth_pitch; u32 depth_offset; - u32 *depth_buffer; + u32* depth_buffer; bool smooth; unsigned rotation; bool keep_aspect; bool should_resize; bool msg_rendering_enabled; -} gcm_video_t; + + const shader_backend_t* shader; + void* shader_data; + void* renderchain_data; + void* ctx_data; + const gfx_ctx_driver_t* ctx_driver; + bool shared_context_use; + + video_info_t video_info; + struct video_tex_info tex_info; /* unsigned int alignment */ + struct video_tex_info prev_info[GFX_MAX_TEXTURES]; /* unsigned alignment */ + struct video_fbo_rect fbo_rect[GFX_MAX_SHADERS]; /* unsigned alignment */ +} rsx_t; + +static const gfx_ctx_driver_t* rsx_get_context(rsx_t* rsx) +{ + const gfx_ctx_driver_t* gfx_ctx = NULL; + void* ctx_data = NULL; + settings_t* settings = config_get_ptr(); + struct retro_hw_render_callback* hwr = video_driver_get_hw_context(); + + bool video_shared_context = settings->bools.video_shared_context; + enum gfx_ctx_api api = GFX_CTX_RSX_API; + + rsx->shared_context_use = video_shared_context && hwr->context_type != RETRO_HW_CONTEXT_NONE; + + if ((libretro_get_shared_context()) + && (hwr->context_type != RETRO_HW_CONTEXT_NONE)) + rsx->shared_context_use = true; + + gfx_ctx = video_context_driver_init_first(rsx, + settings->arrays.video_context_driver, + api, 1, 0, rsx->shared_context_use, &ctx_data); + + if (ctx_data) + rsx->ctx_data = ctx_data; + + return gfx_ctx; +} #ifndef HAVE_THREADS -static bool gcm_tasks_finder(retro_task_t *task,void *userdata) +static bool rsx_tasks_finder(retro_task_t *task,void *userdata) { return task; } -task_finder_data_t gcm_tasks_finder_data = {gcm_tasks_finder, NULL}; +task_finder_data_t rsx_tasks_finder_data = {rsx_tasks_finder, NULL}; #endif -static int gcm_make_buffer(rsxBuffer * buffer, u16 width, u16 height, int id) +static int rsx_make_buffer(rsxBuffer * buffer, u16 width, u16 height, int id) { int depth = sizeof(u32); int pitch = depth * width; @@ -150,7 +191,7 @@ error: return FALSE; } -static int gcm_flip(gcmContextData *context, s32 buffer) +static int rsx_flip(gcmContextData *context, s32 buffer) { if (gcmSetFlip(context, buffer) == 0) { @@ -165,16 +206,16 @@ static int gcm_flip(gcmContextData *context, s32 buffer) #define GCM_LABEL_INDEX 255 -static void gcm_wait_rsx_idle(gcmContextData *context); +static void rsx_wait_rsx_idle(gcmContextData *context); -static void gcm_wait_flip(void) +static void rsx_wait_flip(void) { while (gcmGetFlipStatus() != 0) usleep (200); /* Sleep, to not stress the cpu. */ gcmResetFlipStatus(); } -static gcmContextData *gcm_init_screen(gcm_video_t* gcm) +static gcmContextData *rsx_init_screen(rsx_t* gcm) { /* Context to keep track of the RSX buffer. */ gcmContextData *context = NULL; @@ -230,7 +271,7 @@ static gcmContextData *gcm_init_screen(gcm_video_t* gcm) gcm->width = res.width; gcm->height = res.height; - gcm_wait_rsx_idle(context); + rsx_wait_rsx_idle(context); if (videoConfigure (0, &vconfig, NULL, 0) != 0) goto error; @@ -241,7 +282,8 @@ static gcmContextData *gcm_init_screen(gcm_video_t* gcm) gcmSetFlipMode (GCM_FLIP_VSYNC); /* Wait for VSYNC to flip */ gcm->depth_pitch = res.width * sizeof(u32); - gcm->depth_buffer = (u32 *) rsxMemalign (64, (res.height * gcm->depth_pitch)* 2); + gcm->depth_buffer = (u32 *) rsxMemalign (64, (res.height * gcm->depth_pitch)); //Beware, if was (res.height * gcm->depth_pitch)*2 + rsxAddressToOffset (gcm->depth_buffer, &gcm->depth_offset); gcmResetFlipStatus(); @@ -273,7 +315,7 @@ static void waitFinish(gcmContextData *context, u32 sLabelVal) sLabelVal++; } -static void gcm_wait_rsx_idle(gcmContextData *context) +static void rsx_wait_rsx_idle(gcmContextData *context) { u32 sLabelVal = 1; @@ -285,35 +327,43 @@ static void gcm_wait_rsx_idle(gcmContextData *context) waitFinish(context, sLabelVal); } -static void* gcm_init(const video_info_t* video, +static void* rsx_init(const video_info_t* video, input_driver_t** input, void** input_data) { int i; - gcm_video_t* gcm = malloc(sizeof(gcm_video_t)); + rsx_t* rsx = malloc(sizeof(rsx_t)); - if (!gcm) + if (!rsx) return NULL; - memset(gcm, 0, sizeof(gcm_video_t)); + memset(rsx, 0, sizeof(rsx_t)); - gcm->context = gcm_init_screen(gcm); + rsx->context = rsx_init_screen(rsx); + const gfx_ctx_driver_t* ctx_driver = rsx_get_context(rsx); + + if (!ctx_driver) + return NULL; + + video_context_driver_set((const gfx_ctx_driver_t*)ctx_driver); + rsx->ctx_driver = ctx_driver; + rsx->video_info = *video; for (i = 0; i < MAX_BUFFERS; i++) - gcm_make_buffer(&gcm->buffers[i], gcm->width, gcm->height, i); + rsx_make_buffer(&rsx->buffers[i], rsx->width, rsx->height, i); for (i = 0; i < MAX_BUFFERS; i++) - gcm_make_buffer(&gcm->menuBuffers[i], gcm->width, gcm->height, i + MAX_BUFFERS); + rsx_make_buffer(&rsx->menuBuffers[i], rsx->width, rsx->height, i + MAX_BUFFERS); - gcm_flip(gcm->context, MAX_BUFFERS - 1); + rsx_flip(rsx->context, MAX_BUFFERS - 1); - gcm->vp.x = 0; - gcm->vp.y = 0; - gcm->vp.width = gcm->width; - gcm->vp.height = gcm->height; - gcm->vp.full_width = gcm->width; - gcm->vp.full_height = gcm->height; - gcm->rgb32 = video->rgb32; - video_driver_set_size(gcm->vp.width, gcm->vp.height); + rsx->vp.x = 0; + rsx->vp.y = 0; + rsx->vp.width = rsx->width; + rsx->vp.height = rsx->height; + rsx->vp.full_width = rsx->width; + rsx->vp.full_height = rsx->height; + rsx->rgb32 = video->rgb32; + video_driver_set_size(rsx->vp.width, rsx->vp.height); if (input && input_data) { @@ -322,17 +372,19 @@ static void* gcm_init(const video_info_t* video, *input_data = ps3input; } - return gcm; + rsx_context_bind_hw_render(rsx, true); + + return rsx; } -static void gcm_fill_black(uint32_t *dst, uint32_t *dst_end, size_t sz) +static void rsx_fill_black(uint32_t *dst, uint32_t *dst_end, size_t sz) { if (sz > dst_end - dst) sz = dst_end - dst; memset (dst, 0, sz * 4); } -static void gcm_blit_buffer( +static void rsx_blit_buffer( rsxBuffer *buffer, const void *frame, unsigned width, unsigned height, unsigned pitch, int rgb32, bool do_scaling) { @@ -379,7 +431,7 @@ static void gcm_blit_buffer( for (i = 0; i < height; i++) { memcpy(dst, src, width * 4); - gcm_fill_black(dst + width, dst_end, buffer->width - width); + rsx_fill_black(dst + width, dst_end, buffer->width - width); dst += buffer->width; src += pitch; } @@ -397,7 +449,7 @@ static void gcm_blit_buffer( u8 b = ((rgb565 << 3) & 0xfc); *dst = (r<<16) | (g<<8) | b; } - gcm_fill_black(dst, dst_end, buffer->width - width); + rsx_fill_black(dst, dst_end, buffer->width - width); dst += buffer->width - width; src += pitch / 2 - width; @@ -419,7 +471,7 @@ static void gcm_blit_buffer( dst[l * buffer->width] = c; } for (int l = 0; l < scale; l++) - gcm_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale); + rsx_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale); dst += buffer->width * scale - width * scale; src += pitch / 4 - width; @@ -440,7 +492,7 @@ static void gcm_blit_buffer( dst[l * buffer->width] = c; } for (int l = 0; l < scale; l++) - gcm_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale); + rsx_fill_black(dst + l * buffer->width, dst_end, buffer->width - width * scale); dst += buffer->width * scale - width * scale; src += pitch / 2 - width; @@ -452,25 +504,25 @@ static void gcm_blit_buffer( memset(dst, 0, 4 * (dst_end - dst)); } -static void gcm_update_screen(gcm_video_t *gcm) +static void rsx_update_screen(rsx_t* gcm) { rsxBuffer *buffer = gcm->menu_frame_enable ? &gcm->menuBuffers[gcm->menuBuffer] : &gcm->buffers[gcm->currentBuffer]; - gcm_flip(gcm->context, buffer->id); + rsx_flip(gcm->context, buffer->id); if (gcm->vsync) - gcm_wait_flip(); + rsx_wait_flip(); #ifdef HAVE_SYSUTILS cellSysutilCheckCallback(); #endif } -static bool gcm_frame(void* data, const void* frame, +static bool rsx_frame(void* data, const void* frame, unsigned width, unsigned height, uint64_t frame_count, unsigned pitch, const char* msg, video_frame_info_t *video_info) { - gcm_video_t *gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; #ifdef HAVE_MENU bool statistics_show = video_info->statistics_show; struct font_params *osd_params = (struct font_params*) @@ -482,13 +534,13 @@ static bool gcm_frame(void* data, const void* frame, gcm->currentBuffer++; if (gcm->currentBuffer >= MAX_BUFFERS) gcm->currentBuffer = 0; - gcm_blit_buffer( + rsx_blit_buffer( &gcm->buffers[gcm->currentBuffer], frame, width, height, pitch, gcm->rgb32, true); } /* TODO: translucid menu */ - gcm_update_screen(gcm); + rsx_update_screen(gcm); return true; @@ -505,38 +557,38 @@ static bool gcm_frame(void* data, const void* frame, return true; } -static void gcm_set_nonblock_state(void* data, bool toggle, +static void rsx_set_nonblock_state(void* data, bool toggle, bool a, unsigned b) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (gcm) gcm->vsync = !toggle; } -static bool gcm_alive(void* data) +static bool rsx_alive(void* data) { (void)data; return true; } -static bool gcm_focus(void* data) +static bool rsx_focus(void* data) { (void)data; return true; } -static bool gcm_suppress_screensaver(void* data, bool enable) +static bool rsx_suppress_screensaver(void* data, bool enable) { (void)data; (void)enable; return false; } -static void gcm_free(void* data) +static void rsx_free(void* data) { int i; - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (!gcm) return; @@ -554,38 +606,38 @@ static void gcm_free(void* data) free (gcm); } -static void gcm_set_texture_frame(void* data, const void* frame, bool rgb32, +static void rsx_set_texture_frame(void* data, const void* frame, bool rgb32, unsigned width, unsigned height, float alpha) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; int newBuffer = gcm->menuBuffer + 1; if (newBuffer >= MAX_BUFFERS) newBuffer = 0; /* TODO: respect alpha */ - gcm_blit_buffer(&gcm->menuBuffers[newBuffer], frame, width, height, + rsx_blit_buffer(&gcm->menuBuffers[newBuffer], frame, width, height, width * (rgb32 ? 4 : 2), rgb32, true); gcm->menuBuffer = newBuffer; - gcm_update_screen(gcm); + rsx_update_screen(gcm); } -static void gcm_set_texture_enable(void* data, bool state, bool full_screen) +static void rsx_set_texture_enable(void* data, bool state, bool full_screen) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (!gcm) return; gcm->menu_frame_enable = state; - gcm_update_screen(gcm); + rsx_update_screen(gcm); } -static void gcm_set_rotation(void* data, unsigned rotation) +static void rsx_set_rotation(void* data, unsigned rotation) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (!gcm) return; @@ -593,17 +645,17 @@ static void gcm_set_rotation(void* data, unsigned rotation) gcm->rotation = rotation; gcm->should_resize = true; } -static void gcm_set_filtering(void* data, unsigned index, bool smooth) +static void rsx_set_filtering(void* data, unsigned index, bool smooth) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (gcm) gcm->smooth = smooth; } -static void gcm_set_aspect_ratio(void* data, unsigned aspect_ratio_idx) +static void rsx_set_aspect_ratio(void* data, unsigned aspect_ratio_idx) { - gcm_video_t *gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if(!gcm) return; @@ -612,58 +664,58 @@ static void gcm_set_aspect_ratio(void* data, unsigned aspect_ratio_idx) gcm->should_resize = true; } -static void gcm_apply_state_changes(void* data) +static void rsx_apply_state_changes(void* data) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (gcm) gcm->should_resize = true; } -static void gcm_viewport_info(void* data, struct video_viewport* vp) +static void rsx_viewport_info(void* data, struct video_viewport* vp) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (gcm) *vp = gcm->vp; } -static void gcm_set_osd_msg(void *data, +static void rsx_set_osd_msg(void *data, video_frame_info_t *video_info, const char *msg, const void *params, void *font) { - gcm_video_t* gcm = (gcm_video_t*)data; + rsx_t* gcm = (rsx_t*)data; if (gcm && gcm->msg_rendering_enabled) font_driver_render_msg(data, msg, params, font); } -static uint32_t gcm_get_flags(void *data) +static uint32_t rsx_get_flags(void *data) { uint32_t flags = 0; return flags; } -static const video_poke_interface_t gcm_poke_interface = { - gcm_get_flags, +static const video_poke_interface_t rsx_poke_interface = { + rsx_get_flags, NULL, /* load_texture */ NULL, /* unload_texture */ NULL, NULL, - gcm_set_filtering, + rsx_set_filtering, NULL, /* get_video_output_size */ NULL, /* get_video_output_prev */ NULL, /* get_video_output_next */ NULL, /* get_current_framebuffer */ NULL, - gcm_set_aspect_ratio, - gcm_apply_state_changes, - gcm_set_texture_frame, - gcm_set_texture_enable, - gcm_set_osd_msg, + rsx_set_aspect_ratio, + rsx_apply_state_changes, + rsx_set_texture_frame, + rsx_set_texture_enable, + rsx_set_osd_msg, NULL, /* show_mouse */ NULL, /* grab_mouse_toggle */ NULL, /* get_current_shader */ @@ -671,14 +723,14 @@ static const video_poke_interface_t gcm_poke_interface = { NULL /* get_hw_render_interface */ }; -static void gcm_get_poke_interface(void* data, +static void rsx_get_poke_interface(void* data, const video_poke_interface_t** iface) { (void)data; - *iface = &gcm_poke_interface; + *iface = &rsx_poke_interface; } -static bool gcm_set_shader(void* data, +static bool rsx_set_shader(void* data, enum rarch_shader_type type, const char* path) { (void)data; @@ -690,19 +742,19 @@ static bool gcm_set_shader(void* data, video_driver_t video_gcm = { - gcm_init, - gcm_frame, - gcm_set_nonblock_state, - gcm_alive, - gcm_focus, - gcm_suppress_screensaver, + rsx_init, + rsx_frame, + rsx_set_nonblock_state, + rsx_alive, + rsx_focus, + rsx_suppress_screensaver, NULL, /* has_windowed */ - gcm_set_shader, - gcm_free, - "gcm", + rsx_set_shader, + rsx_free, + "rsx", NULL, /* set_viewport */ - gcm_set_rotation, - gcm_viewport_info, + rsx_set_rotation, + rsx_viewport_info, NULL, /* read_viewport */ NULL, /* read_frame_raw */ #ifdef HAVE_OVERLAY @@ -711,5 +763,5 @@ video_driver_t video_gcm = #ifdef HAVE_VIDEO_LAYOUT NULL, #endif - gcm_get_poke_interface + rsx_get_poke_interface }; diff --git a/gfx/drivers/sdl_dingux_gfx.c b/gfx/drivers/sdl_dingux_gfx.c index 865c16f478..607e3de340 100644 --- a/gfx/drivers/sdl_dingux_gfx.c +++ b/gfx/drivers/sdl_dingux_gfx.c @@ -2,6 +2,7 @@ * Copyright (C) 2010-2014 - Hans-Kristian Arntzen * Copyright (C) 2011-2017 - Daniel De Matteis * Copyright (C) 2011-2017 - Higor Euripedes + * Copyright (C) 2019-2021 - James Leaver * * RetroArch is free software: you can redistribute it and/or modify it under the terms * of the GNU General Public License as published by the Free Software Found- @@ -580,6 +581,12 @@ static void sdl_dingux_sanitize_frame_dimensions( /* GB/GBC/GG (x3) @ 480x432 */ else if ((width == 480) && (height == 432)) *sanitized_width = 496; + /* SNES/Genesis @ 256x224 */ + else if ((width == 256) && (height == 224)) + *sanitized_width = 288; + /* SNES/Genesis (x2) @ 512x448 */ + else if ((width == 512) && (height == 448)) + *sanitized_width = 560; } #endif @@ -761,7 +768,13 @@ static bool sdl_dingux_gfx_frame(void *data, const void *frame, { sdl_dingux_video_t* vid = (sdl_dingux_video_t*)data; - if (unlikely(!vid)) + /* Return early if: + * - Input sdl_dingux_video_t struct is NULL + * (cannot realistically happen) + * - Menu is inactive and input 'content' frame + * data is NULL (may happen when e.g. a running + * core skips a frame) */ + if (unlikely(!vid || (!frame && !vid->menu_active))) return true; /* If fast forward is currently active, we may @@ -805,16 +818,13 @@ static bool sdl_dingux_gfx_frame(void *data, const void *frame, if (likely(vid->mode_valid)) { - if (likely(frame)) - { - /* Blit frame to SDL surface */ - if (vid->rgb32) - sdl_dingux_blit_frame32(vid, (uint32_t*)frame, - width, height, pitch); - else - sdl_dingux_blit_frame16(vid, (uint16_t*)frame, - width, height, pitch); - } + /* Blit frame to SDL surface */ + if (vid->rgb32) + sdl_dingux_blit_frame32(vid, (uint32_t*)frame, + width, height, pitch); + else + sdl_dingux_blit_frame16(vid, (uint16_t*)frame, + width, height, pitch); } /* If current display mode is invalid, * just display an error message */ diff --git a/gfx/drivers/sdl_rs90_gfx.c b/gfx/drivers/sdl_rs90_gfx.c new file mode 100644 index 0000000000..0da790ebd0 --- /dev/null +++ b/gfx/drivers/sdl_rs90_gfx.c @@ -0,0 +1,1433 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * Copyright (C) 2011-2017 - Higor Euripedes + * Copyright (C) 2019-2021 - James Leaver + * Copyright (C) 2021 - John Parton + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include + +#ifdef HAVE_CONFIG_H +#include "../../config.h" +#endif + +#ifdef HAVE_MENU +#include "../../menu/menu_driver.h" +#endif + +#include "../../dingux/dingux_utils.h" + +#include "../../verbosity.h" +#include "../../gfx/drivers_font_renderer/bitmap.h" +#include "../../configuration.h" +#include "../../retroarch.h" +#if defined(DINGUX_BETA) +#include "../../driver.h" +#endif + +#define likely(x) __builtin_expect(!!(x), 1) +#define unlikely(x) __builtin_expect(!!(x), 0) + +#define SDL_RS90_WIDTH 240 +#define SDL_RS90_HEIGHT 160 + +#define SDL_RS90_NUM_FONT_GLYPHS 256 + +typedef struct sdl_rs90_video sdl_rs90_video_t; +struct sdl_rs90_video +{ + retro_time_t last_frame_time; + retro_time_t ff_frame_time_min; + SDL_Surface *screen; + void (*scale_frame16)(sdl_rs90_video_t *vid, + uint16_t *src, unsigned width, unsigned height, + unsigned src_pitch); + void (*scale_frame32)(sdl_rs90_video_t *vid, + uint32_t *src, unsigned width, unsigned height, + unsigned src_pitch); + bitmapfont_lut_t *osd_font; + /* Scaling/padding/cropping parameters */ + unsigned content_width; + unsigned content_height; + unsigned frame_width; + unsigned frame_height; + unsigned frame_padding_x; + unsigned frame_padding_y; + unsigned frame_crop_x; + unsigned frame_crop_y; + enum dingux_rs90_softfilter_type softfilter_type; +#if defined(DINGUX_BETA) + enum dingux_refresh_rate refresh_rate; +#endif + uint32_t font_colour32; + uint16_t font_colour16; + uint16_t menu_texture[SDL_RS90_WIDTH * SDL_RS90_HEIGHT]; + bool rgb32; + bool vsync; + bool keep_aspect; + bool scale_integer; + bool menu_active; + bool was_in_menu; + bool quitting; + bool mode_valid; +}; + +/* Image interpolation START */ + +static void sdl_rs90_scale_frame16_integer(sdl_rs90_video_t *vid, + uint16_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 16 bit - divide pitch by 2 */ + size_t in_stride = (size_t)(src_pitch >> 1); + size_t out_stride = (size_t)(vid->screen->pitch >> 1); + + /* Manipulate offsets so that padding/crop + * are applied correctly */ + uint16_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride; + uint16_t *out_ptr = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + size_t y = vid->frame_height; + + /* TODO/FIXME: Optimize this loop */ + do + { + memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint16_t)); + in_ptr += in_stride; + out_ptr += out_stride; + } + while (--y); +} + +static void sdl_rs90_scale_frame32_integer(sdl_rs90_video_t *vid, + uint32_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 32 bit - divide pitch by 4 */ + size_t in_stride = (size_t)(src_pitch >> 2); + size_t out_stride = (size_t)(vid->screen->pitch >> 2); + + /* Manipulate offsets so that padding/crop + * are applied correctly */ + uint32_t *in_ptr = src + vid->frame_crop_x + vid->frame_crop_y * in_stride; + uint32_t *out_ptr = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + size_t y = vid->frame_height; + + /* TODO/FIXME: Optimize this loop */ + do + { + memcpy(out_ptr, in_ptr, vid->frame_width * sizeof(uint32_t)); + in_ptr += in_stride; + out_ptr += out_stride; + } + while (--y); +} + +/* Approximate nearest-neighbour scaling using + * bitshifts and integer math */ +static void sdl_rs90_scale_frame16_point(sdl_rs90_video_t *vid, + uint16_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width; + uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height; + + /* 16 bit - divide pitch by 2 */ + size_t in_stride = (size_t)(src_pitch >> 1); + size_t out_stride = (size_t)(vid->screen->pitch >> 1); + + /* Apply x/y padding offset */ + uint16_t *top_corner = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + /* Temporary pointers */ + uint16_t *in_ptr = NULL; + uint16_t *out_ptr = NULL; + + uint32_t y = 0; + size_t row; + + /* TODO/FIXME: Optimize these loops further. + * Consider saving these computations in an array + * and indexing over them. + * Would likely be slower due to cache (non-)locality, + * but it's worth a shot. + * Tons of -> operations. */ + for (row = 0; row < vid->frame_height; row++) + { + size_t col = vid->frame_width; + uint32_t x = 0; + + out_ptr = top_corner + out_stride * row; + in_ptr = src + (y >> 16) * in_stride; + + do + { + *(out_ptr++) = in_ptr[x >> 16]; + x += x_step; + } + while (--col); + + y += y_step; + } +} + +static void sdl_rs90_scale_frame32_point(sdl_rs90_video_t *vid, + uint32_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + uint32_t x_step = (((uint32_t)(width) << 16) + 1) / vid->frame_width; + uint32_t y_step = (((uint32_t)(height) << 16) + 1) / vid->frame_height; + + /* 32 bit - divide pitch by 4 */ + size_t in_stride = (size_t)(src_pitch >> 2); + size_t out_stride = (size_t)(vid->screen->pitch >> 2); + + /* Apply x/y padding offset */ + uint32_t *top_corner = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x + + out_stride * vid->frame_padding_y; + + /* Temporary pointers */ + uint32_t *in_ptr = NULL; + uint32_t *out_ptr = NULL; + + uint32_t y = 0; + size_t row; + + /* TODO/FIXME: Optimize these loops further. + * Consider saving these computations in an array + * and indexing over them. + * Would likely be slower due to cache (non-)locality, + * but it's worth a shot. + * Tons of -> operations. */ + for (row = 0; row < vid->frame_height; row++) + { + size_t col = vid->frame_width; + uint32_t x = 0; + + out_ptr = top_corner + out_stride * row; + in_ptr = src + (y >> 16) * in_stride; + + do + { + *(out_ptr++) = in_ptr[x >> 16]; + x += x_step; + } + while (--col); + + y += y_step; + } +} + +/* Produces a 50:50 mix of pixels a and b + * > c.f. "Mixing Packed RGB Pixels Efficiently" + * http://blargg.8bitalley.com/info/rgb_mixing.html */ +#define SDL_RS90_PIXEL_AVERAGE_16(a, b) (((a) + (b) + (((a) ^ (b)) & 0x821)) >> 1) +#define SDL_RS90_PIXEL_AVERAGE_32(a, b) (((a) + (b) + (((a) ^ (b)) & 0x10101)) >> 1) + +/* Scales a single horizontal line using approximate + * linear scaling + * > c.f. "Image Scaling with Bresenham" + * https://www.drdobbs.com/image-scaling-with-bresenham/184405045 */ +static void sdl_rs90_scale_line_bresenham16(uint16_t *target, uint16_t *src, + unsigned src_width, unsigned target_width, + unsigned int_part, unsigned fract_part, unsigned midpoint) +{ + unsigned num_pixels = target_width; + unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */ + + /* If source and target have the same width, + * can perform a fast copy of raw pixel data */ + if (src_width == target_width) + { + memcpy(target, src, target_width * sizeof(uint16_t)); + return; + } + else if (target_width > src_width) + num_pixels--; + + do + { + *(target++) = (E >= midpoint) ? + SDL_RS90_PIXEL_AVERAGE_16(*src, *(src + 1)) : *src; + + src += int_part; + E += fract_part; + + if (E >= target_width) + { + E -= target_width; + src++; + } + } + while (--num_pixels); + + if (target_width > src_width) + *target = *src; +} + +static void sdl_rs90_scale_frame16_bresenham_horz(sdl_rs90_video_t *vid, + uint16_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 16 bit - divide pitch by 2 */ + size_t in_stride = (size_t)(src_pitch >> 1); + size_t out_stride = (size_t)(vid->screen->pitch >> 1); + + uint16_t *prev_src = NULL; + + /* Account for x/y padding */ + uint16_t *target = (uint16_t*)(vid->screen->pixels) + vid->frame_padding_x + + (out_stride * vid->frame_padding_y); + unsigned target_width = vid->frame_width; + unsigned target_height = vid->frame_height; + + unsigned num_lines = target_height; + unsigned int_part = (height / target_height) * in_stride; + unsigned fract_part = height % target_height; + unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */ + + unsigned col_int_part = width / target_width; + unsigned col_fract_part = width % target_width; + /* Enhance midpoint selection as described in + * https://www.compuphase.com/graphic/scale1errata.htm */ + int col_midpoint = (target_width > width) ? + ((int)target_width - 3 * ((int)target_width - (int)width)) >> 1 : + (int)(target_width << 1) - (int)width; + /* Clamp lower bound to (target_width / 2) */ + if (col_midpoint < (int)(target_width >> 1)) + col_midpoint = (int)(target_width >> 1); + + while (num_lines--) + { + /* If line is supposed to be identical to + * previous line, just copy it */ + if (src == prev_src) + memcpy(target, target - out_stride, target_width * sizeof(uint16_t)); + else + { + sdl_rs90_scale_line_bresenham16(target, src, width, target_width, + col_int_part, col_fract_part, (unsigned)col_midpoint); + prev_src = src; + } + + target += out_stride; + src += int_part; + E += fract_part; + + if (E >= target_height) + { + E -= target_height; + src += in_stride; + } + } +} + +static void sdl_rs90_scale_line_bresenham32(uint32_t *target, uint32_t *src, + unsigned src_width, unsigned target_width, + unsigned int_part, unsigned fract_part, unsigned midpoint) +{ + unsigned num_pixels = target_width; + unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */ + + /* If source and target have the same width, + * can perform a fast copy of raw pixel data */ + if (src_width == target_width) + { + memcpy(target, src, target_width * sizeof(uint32_t)); + return; + } + else if (target_width > src_width) + num_pixels--; + + do + { + *(target++) = (E >= midpoint) ? + SDL_RS90_PIXEL_AVERAGE_32(*src, *(src + 1)) : *src; + + src += int_part; + E += fract_part; + + if (E >= target_width) + { + E -= target_width; + src++; + } + } + while (--num_pixels); + + if (target_width > src_width) + *target = *src; +} + +static void sdl_rs90_scale_frame32_bresenham_horz(sdl_rs90_video_t *vid, + uint32_t *src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* 32 bit - divide pitch by 4 */ + size_t in_stride = (size_t)(src_pitch >> 2); + size_t out_stride = (size_t)(vid->screen->pitch >> 2); + + uint32_t *prev_src = NULL; + + /* Account for x/y padding */ + uint32_t *target = (uint32_t*)(vid->screen->pixels) + vid->frame_padding_x + + (out_stride * vid->frame_padding_y); + unsigned target_width = vid->frame_width; + unsigned target_height = vid->frame_height; + + unsigned num_lines = target_height; + unsigned int_part = (height / target_height) * in_stride; + unsigned fract_part = height % target_height; + unsigned E = 0; /* TODO/FIXME: Determine better variable name - 'error'? */ + + unsigned col_int_part = width / target_width; + unsigned col_fract_part = width % target_width; + /* Enhance midpoint selection as described in + * https://www.compuphase.com/graphic/scale1errata.htm */ + int col_midpoint = (target_width > width) ? + ((int)target_width - 3 * ((int)target_width - (int)width)) >> 1 : + (int)(target_width << 1) - (int)width; + /* Clamp lower bound to (target_width / 2) */ + if (col_midpoint < (int)(target_width >> 1)) + col_midpoint = (int)(target_width >> 1); + + while (num_lines--) + { + /* If line is supposed to be identical to + * previous line, just copy it */ + if (src == prev_src) + memcpy(target, target - out_stride, target_width * sizeof(uint32_t)); + else + { + sdl_rs90_scale_line_bresenham32(target, src, width, target_width, + col_int_part, col_fract_part, (unsigned)col_midpoint); + prev_src = src; + } + + target += out_stride; + src += int_part; + E += fract_part; + + if (E >= target_height) + { + E -= target_height; + src += in_stride; + } + } +} + +static void sdl_rs90_set_scale_frame_functions(sdl_rs90_video_t *vid) +{ + /* Set integer scaling by default */ + vid->scale_frame16 = sdl_rs90_scale_frame16_integer; + vid->scale_frame32 = sdl_rs90_scale_frame32_integer; + + if (!vid->scale_integer) + { + switch (vid->softfilter_type) + { + case DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ: + vid->scale_frame16 = sdl_rs90_scale_frame16_bresenham_horz; + vid->scale_frame32 = sdl_rs90_scale_frame32_bresenham_horz; + break; + case DINGUX_RS90_SOFTFILTER_POINT: + default: + vid->scale_frame16 = sdl_rs90_scale_frame16_point; + vid->scale_frame32 = sdl_rs90_scale_frame32_point; + break; + } + } +} + +/* Image interpolation END */ + +static void sdl_rs90_init_font_color(sdl_rs90_video_t *vid) +{ + settings_t *settings = config_get_ptr(); + uint32_t red = 0xFF; + uint32_t green = 0xFF; + uint32_t blue = 0xFF; + + if (settings) + { + red = (uint32_t)((settings->floats.video_msg_color_r * 255.0f) + 0.5f) & 0xFF; + green = (uint32_t)((settings->floats.video_msg_color_g * 255.0f) + 0.5f) & 0xFF; + blue = (uint32_t)((settings->floats.video_msg_color_b * 255.0f) + 0.5f) & 0xFF; + } + + /* Convert to XRGB8888 */ + vid->font_colour32 = (red << 16) | (green << 8) | blue; + + /* Convert to RGB565 */ + red = red >> 3; + green = green >> 3; + blue = blue >> 3; + + vid->font_colour16 = (red << 11) | (green << 6) | blue; +} + +static void sdl_rs90_blit_text16( + sdl_rs90_video_t *vid, + unsigned x, unsigned y, + const char *str) +{ + /* Note: Cannot draw text in padding region + * (padding region is never cleared, so + * any text pixels would remain as garbage) */ + uint16_t *screen_buf = (uint16_t*)vid->screen->pixels; + bool **font_lut = vid->osd_font->lut; + /* 16 bit - divide pitch by 2 */ + uint16_t screen_stride = (uint16_t)(vid->screen->pitch >> 1); + uint16_t screen_width = vid->screen->w; + uint16_t screen_height = vid->screen->h; + unsigned x_pos = x + vid->frame_padding_x; + unsigned y_pos = (y > (screen_height >> 1)) ? + (y - vid->frame_padding_y) : (y + vid->frame_padding_y); + uint16_t shadow_color_buf[2] = {0}; + uint16_t color_buf[2]; + + color_buf[0] = vid->font_colour16; + color_buf[1] = 0; + + /* Check for out of bounds y coordinates */ + if (y_pos + FONT_HEIGHT + 1 >= + screen_height - vid->frame_padding_y) + return; + + while (!string_is_empty(str)) + { + /* Check for out of bounds x coordinates */ + if (x_pos + FONT_WIDTH_STRIDE + 1 >= + screen_width - vid->frame_padding_x) + return; + + /* Deal with spaces first, for efficiency */ + if (*str == ' ') + str++; + else + { + uint16_t i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&str); + + /* Stupid hack: 'oe' ligatures are not really + * standard extended ASCII, so we have to waste + * CPU cycles performing a conversion from the + * unicode values... */ + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + if (symbol >= SDL_RS90_NUM_FONT_GLYPHS) + continue; + + symbol_lut = font_lut[symbol]; + + for (j = 0; j < FONT_HEIGHT; j++) + { + uint32_t buff_offset = ((y_pos + j) * screen_stride) + x_pos; + + for (i = 0; i < FONT_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_WIDTH))) + { + uint16_t *screen_buf_ptr = screen_buf + buff_offset + i; + + /* Text pixel + right shadow */ + memcpy(screen_buf_ptr, color_buf, sizeof(uint16_t)); + + /* Bottom shadow */ + screen_buf_ptr += screen_stride; + memcpy(screen_buf_ptr, shadow_color_buf, sizeof(uint16_t)); + } + } + } + } + + x_pos += FONT_WIDTH_STRIDE; + } +} + +static void sdl_rs90_blit_text32( + sdl_rs90_video_t *vid, + unsigned x, unsigned y, + const char *str) +{ + /* Note: Cannot draw text in padding region + * (padding region is never cleared, so + * any text pixels would remain as garbage) */ + uint32_t *screen_buf = (uint32_t*)vid->screen->pixels; + bool **font_lut = vid->osd_font->lut; + /* 32 bit - divide pitch by 4 */ + uint32_t screen_stride = (uint32_t)(vid->screen->pitch >> 2); + uint32_t screen_width = vid->screen->w; + uint32_t screen_height = vid->screen->h; + unsigned x_pos = x + vid->frame_padding_x; + unsigned y_pos = (y > (screen_height >> 1)) ? + (y - vid->frame_padding_y) : (y + vid->frame_padding_y); + uint32_t shadow_color_buf[2] = {0}; + uint32_t color_buf[2]; + + color_buf[0] = vid->font_colour32; + color_buf[1] = 0; + + /* Check for out of bounds y coordinates */ + if (y_pos + FONT_HEIGHT + 1 >= + screen_height - vid->frame_padding_y) + return; + + while (!string_is_empty(str)) + { + /* Check for out of bounds x coordinates */ + if (x_pos + FONT_WIDTH_STRIDE + 1 >= + screen_width - vid->frame_padding_x) + return; + + /* Deal with spaces first, for efficiency */ + if (*str == ' ') + str++; + else + { + uint32_t i, j; + bool *symbol_lut; + uint32_t symbol = utf8_walk(&str); + + /* Stupid hack: 'oe' ligatures are not really + * standard extended ASCII, so we have to waste + * CPU cycles performing a conversion from the + * unicode values... */ + if (symbol == 339) /* Latin small ligature oe */ + symbol = 156; + if (symbol == 338) /* Latin capital ligature oe */ + symbol = 140; + + if (symbol >= SDL_RS90_NUM_FONT_GLYPHS) + continue; + + symbol_lut = font_lut[symbol]; + + for (j = 0; j < FONT_HEIGHT; j++) + { + uint32_t buff_offset = ((y_pos + j) * screen_stride) + x_pos; + + for (i = 0; i < FONT_WIDTH; i++) + { + if (*(symbol_lut + i + (j * FONT_WIDTH))) + { + uint32_t *screen_buf_ptr = screen_buf + buff_offset + i; + + /* Text pixel + right shadow */ + memcpy(screen_buf_ptr, color_buf, sizeof(uint32_t)); + + /* Bottom shadow */ + screen_buf_ptr += screen_stride; + memcpy(screen_buf_ptr, shadow_color_buf, sizeof(uint32_t)); + } + } + } + } + + x_pos += FONT_WIDTH_STRIDE; + } +} + +static void sdl_rs90_blit_video_mode_error_msg(sdl_rs90_video_t *vid) +{ + const char *error_msg = msg_hash_to_str(MSG_UNSUPPORTED_VIDEO_MODE); + char display_mode[64]; + + display_mode[0] = '\0'; + + /* Zero out pixel buffer */ + memset(vid->screen->pixels, 0, + vid->screen->pitch * vid->screen->h); + + /* Generate display mode string */ + snprintf(display_mode, sizeof(display_mode), "> %ux%u, %s", + vid->frame_width, vid->frame_height, + vid->rgb32 ? "XRGB8888" : "RGB565"); + + /* Print error message */ + if (vid->rgb32) + { + sdl_rs90_blit_text32(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE, + error_msg); + + sdl_rs90_blit_text32(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE + FONT_HEIGHT_STRIDE, + display_mode); + } + else + { + sdl_rs90_blit_text16(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE, + error_msg); + + sdl_rs90_blit_text16(vid, + FONT_WIDTH_STRIDE, FONT_WIDTH_STRIDE + FONT_HEIGHT_STRIDE, + display_mode); + } +} + +static void sdl_rs90_gfx_free(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (!vid) + return; + + if (vid->osd_font) + bitmapfont_free_lut(vid->osd_font); + + free(vid); +} + +static void sdl_rs90_input_driver_init( + const char *input_driver_name, const char *joypad_driver_name, + input_driver_t **input, void **input_data) +{ + /* Sanity check */ + if (!input || !input_data) + return; + + *input = NULL; + *input_data = NULL; + + /* If input driver name is empty, cannot + * initialise anything... */ + if (string_is_empty(input_driver_name)) + return; + + if (string_is_equal(input_driver_name, "sdl_dingux")) + { + *input_data = input_driver_init_wrap(&input_sdl_dingux, + joypad_driver_name); + + if (*input_data) + *input = &input_sdl_dingux; + + return; + } + +#if defined(HAVE_SDL) || defined(HAVE_SDL2) + if (string_is_equal(input_driver_name, "sdl")) + { + *input_data = input_driver_init_wrap(&input_sdl, + joypad_driver_name); + + if (*input_data) + *input = &input_sdl; + + return; + } +#endif + +#if defined(HAVE_UDEV) + if (string_is_equal(input_driver_name, "udev")) + { + *input_data = input_driver_init_wrap(&input_udev, + joypad_driver_name); + + if (*input_data) + *input = &input_udev; + + return; + } +#endif + +#if defined(__linux__) + if (string_is_equal(input_driver_name, "linuxraw")) + { + *input_data = input_driver_init_wrap(&input_linuxraw, + joypad_driver_name); + + if (*input_data) + *input = &input_linuxraw; + + return; + } +#endif +} + +static void *sdl_rs90_gfx_init(const video_info_t *video, + input_driver_t **input, void **input_data) +{ + sdl_rs90_video_t *vid = NULL; + uint32_t sdl_subsystem_flags = SDL_WasInit(0); + settings_t *settings = config_get_ptr(); +#if defined(DINGUX_BETA) + enum dingux_refresh_rate current_refresh_rate = DINGUX_REFRESH_RATE_60HZ; + enum dingux_refresh_rate target_refresh_rate = (enum dingux_refresh_rate) + settings->uints.video_dingux_refresh_rate; + bool refresh_rate_valid = false; + float hw_refresh_rate = 0.0f; +#endif + const char *input_driver_name = settings->arrays.input_driver; + const char *joypad_driver_name = settings->arrays.input_joypad_driver; + uint32_t surface_flags = (video->vsync) ? + (SDL_HWSURFACE | SDL_TRIPLEBUF | SDL_FULLSCREEN) : + (SDL_HWSURFACE | SDL_FULLSCREEN); + + /* Initialise graphics subsystem, if required */ + if (sdl_subsystem_flags == 0) + { + if (SDL_Init(SDL_INIT_VIDEO) < 0) + return NULL; + } + else if ((sdl_subsystem_flags & SDL_INIT_VIDEO) == 0) + { + if (SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) + return NULL; + } + + vid = (sdl_rs90_video_t*)calloc(1, sizeof(*vid)); + if (!vid) + return NULL; + +#if defined(DINGUX_BETA) + /* Get current refresh rate */ + refresh_rate_valid = dingux_get_video_refresh_rate(¤t_refresh_rate); + + /* Check if refresh rate needs to be updated */ + if (!refresh_rate_valid || + (current_refresh_rate != target_refresh_rate)) + hw_refresh_rate = dingux_set_video_refresh_rate(target_refresh_rate); + else + { + /* Correct refresh rate is already set, + * just convert to float */ + switch (current_refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + hw_refresh_rate = 50.0f; + break; + default: + hw_refresh_rate = 60.0f; + break; + } + } + + if (hw_refresh_rate == 0.0f) + { + RARCH_ERR("[SDL1]: Failed to set video refresh rate\n"); + goto error; + } + + vid->refresh_rate = target_refresh_rate; + switch (target_refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + vid->ff_frame_time_min = 20000; + break; + default: + vid->ff_frame_time_min = 16667; + break; + } + + driver_ctl(RARCH_DRIVER_CTL_SET_REFRESH_RATE, &hw_refresh_rate); +#else + vid->ff_frame_time_min = 16667; +#endif + + vid->screen = SDL_SetVideoMode( + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + video->rgb32 ? 32 : 16, + surface_flags); + + if (!vid->screen) + { + RARCH_ERR("[SDL1]: Failed to init SDL surface: %s\n", SDL_GetError()); + goto error; + } + + vid->content_width = SDL_RS90_WIDTH; + vid->content_height = SDL_RS90_HEIGHT; + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = SDL_RS90_HEIGHT; + vid->rgb32 = video->rgb32; + vid->vsync = video->vsync; + vid->keep_aspect = settings->bools.video_dingux_ipu_keep_aspect; + vid->scale_integer = settings->bools.video_scale_integer; + vid->softfilter_type = (enum dingux_rs90_softfilter_type) + settings->uints.video_dingux_rs90_softfilter_type; + vid->menu_active = false; + vid->was_in_menu = false; + vid->quitting = false; + vid->mode_valid = true; + vid->last_frame_time = 0; + + SDL_ShowCursor(SDL_DISABLE); + + sdl_rs90_input_driver_init(input_driver_name, + joypad_driver_name, input, input_data); + + /* Initialise OSD font */ + sdl_rs90_init_font_color(vid); + + vid->osd_font = bitmapfont_get_lut(); + + if (!vid->osd_font || + vid->osd_font->glyph_max < + (SDL_RS90_NUM_FONT_GLYPHS - 1)) + { + RARCH_ERR("[SDL1]: Failed to init OSD font\n"); + goto error; + } + + /* Assign frame scaling function pointers */ + sdl_rs90_set_scale_frame_functions(vid); + + return vid; + +error: + sdl_rs90_gfx_free(vid); + return NULL; +} + +static void sdl_rs90_set_output( + sdl_rs90_video_t* vid, + unsigned width, unsigned height, bool rgb32) +{ + uint32_t surface_flags = (vid->vsync) ? + (SDL_HWSURFACE | SDL_TRIPLEBUF | SDL_FULLSCREEN) : + (SDL_HWSURFACE | SDL_FULLSCREEN); + + vid->content_width = width; + vid->content_height = height; + + /* Technically, "scale_integer" here just means "do not scale" + * If the content is larger, we crop, otherwise we just centre + * it in the frame. + * If we want to support a core with an absolutely tiny screen + * (i.e. less than 120x80), we should do actual integer scaling + * (PokeMini @ 96x64 and VeMUlator @ 48x32 are probably the + * only cores where this is an issue, but PokeMini at least + * offers internal upscaling...) */ + if (vid->scale_integer) + { + if (width > SDL_RS90_WIDTH) + { + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_crop_x = (width - SDL_RS90_WIDTH) >> 1; + vid->frame_padding_x = 0; + } + else + { + vid->frame_width = width; + vid->frame_crop_x = 0; + vid->frame_padding_x = (SDL_RS90_WIDTH - width) >> 1; + } + + if (height > SDL_RS90_HEIGHT) + { + vid->frame_height = SDL_RS90_HEIGHT; + vid->frame_crop_y = (height - SDL_RS90_HEIGHT) >> 1; + vid->frame_padding_y = 0; + } + else + { + vid->frame_height = height; + vid->frame_crop_y = 0; + vid->frame_padding_y = (SDL_RS90_HEIGHT - height) >> 1; + } + } + else + { + /* Normal scaling */ + if (vid->keep_aspect) + { + if (height * SDL_RS90_WIDTH > width * SDL_RS90_HEIGHT) + { + /* Integer math is fine */ + vid->frame_width = (width * SDL_RS90_HEIGHT) / height; + vid->frame_height = SDL_RS90_HEIGHT; + } + else + { + /* Integer math is fine */ + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = (height * SDL_RS90_WIDTH) / width; + } + } + else + { + vid->frame_width = SDL_RS90_WIDTH; + vid->frame_height = SDL_RS90_HEIGHT; + } + + vid->frame_crop_x = 0; + vid->frame_padding_x = (SDL_RS90_WIDTH - vid->frame_width) >> 1; + vid->frame_crop_y = 0; + vid->frame_padding_y = (SDL_RS90_HEIGHT - vid->frame_height) >> 1; + } + + /* Attempt to change video mode */ + vid->screen = SDL_SetVideoMode( + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + rgb32 ? 32 : 16, + surface_flags); + + /* Check whether selected display mode is valid */ + if (unlikely(!vid->screen)) + { + RARCH_ERR("[SDL1]: Failed to init SDL surface: %s\n", SDL_GetError()); + vid->mode_valid = false; + } + else + { + /* Determine whether frame padding is required */ + if ((vid->frame_padding_x > 0) || + (vid->frame_padding_y > 0)) + { + /* To prevent garbage pixels in the padding + * region, must zero out pixel buffer */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + memset(vid->screen->pixels, 0, + vid->screen->pitch * vid->screen->h); + + if (SDL_MUSTLOCK(vid->screen)) + SDL_UnlockSurface(vid->screen); + } + + vid->mode_valid = true; + } +} + +static void sdl_rs90_blit_frame16(sdl_rs90_video_t *vid, + uint16_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* If source and destination buffers have the + * same pitch, perform fast copy of raw pixel data */ + /* TODO/FIXME: Make sure this code path is used for + * GBA content */ + if (src_pitch == vid->screen->pitch && + height == SDL_RS90_HEIGHT) + memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT); + else + vid->scale_frame16(vid, src, width, height, src_pitch); +} + +static void sdl_rs90_blit_frame32(sdl_rs90_video_t *vid, + uint32_t* src, unsigned width, unsigned height, + unsigned src_pitch) +{ + /* If source and destination buffers have the + * same pitch, perform fast copy of raw pixel data */ + /* TODO/FIXME: Make sure this code path is used for + * GBA content */ + if ((src_pitch == vid->screen->pitch) && + (height == SDL_RS90_HEIGHT)) + memcpy(vid->screen->pixels, src, src_pitch * SDL_RS90_HEIGHT); + else + vid->scale_frame32(vid, src, width, height, src_pitch); +} + +static bool sdl_rs90_gfx_frame(void *data, const void *frame, + unsigned width, unsigned height, uint64_t frame_count, + unsigned pitch, const char *msg, video_frame_info_t *video_info) +{ + sdl_rs90_video_t* vid = (sdl_rs90_video_t*)data; + + /* Return early if: + * - Input sdl_rs90_video_t struct is NULL + * (cannot realistically happen) + * - Menu is inactive and input 'content' frame + * data is NULL (may happen when e.g. a running + * core skips a frame) */ + if (unlikely(!vid || (!frame && !vid->menu_active))) + return true; + + /* If fast forward is currently active, we may + * push frames at an 'unlimited' rate. Since the + * display has a fixed refresh rate of 60 Hz (or + * potentially 50 Hz on OpenDingux Beta), this + * represents wasted effort. We therefore drop any + * 'excess' frames in this case. + * (Note that we *only* do this when fast forwarding. + * Attempting this trick while running content normally + * will cause bad frame pacing) */ + if (unlikely(video_info->input_driver_nonblock_state)) + { + retro_time_t current_time = cpu_features_get_time_usec(); + + if ((current_time - vid->last_frame_time) < + vid->ff_frame_time_min) + return true; + + vid->last_frame_time = current_time; + } + +#ifdef HAVE_MENU + menu_driver_frame(video_info->menu_is_alive, video_info); +#endif + + if (likely(!vid->menu_active)) + { + /* Update video mode if we were in the menu on + * the previous frame, or width/height have changed */ + if (unlikely( + vid->was_in_menu || + (vid->content_width != width) || + (vid->content_height != height))) + sdl_rs90_set_output(vid, width, height, vid->rgb32); + + /* Must always lock SDL surface before + * manipulating raw pixel buffer */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + if (likely(vid->mode_valid)) + { + /* Blit frame to SDL surface */ + if (vid->rgb32) + sdl_rs90_blit_frame32(vid, (uint32_t*)frame, + width, height, pitch); + else + sdl_rs90_blit_frame16(vid, (uint16_t*)frame, + width, height, pitch); + } + /* If current display mode is invalid, + * just display an error message */ + else + sdl_rs90_blit_video_mode_error_msg(vid); + + vid->was_in_menu = false; + } + else + { + /* If this is the first frame that the menu + * is active, update video mode */ + if (!vid->was_in_menu) + { + sdl_rs90_set_output(vid, + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, false); + + vid->was_in_menu = true; + } + + if (SDL_MUSTLOCK(vid->screen)) + SDL_LockSurface(vid->screen); + + /* Blit menu texture to SDL surface */ + sdl_rs90_blit_frame16(vid, vid->menu_texture, + SDL_RS90_WIDTH, SDL_RS90_HEIGHT, + SDL_RS90_WIDTH * sizeof(uint16_t)); + } + + /* Print OSD text, if required */ + if (msg) + { + /* If menu is active, colour depth is overridden + * to 16 bit */ + if (vid->rgb32 && !vid->menu_active) + sdl_rs90_blit_text32(vid, FONT_WIDTH_STRIDE, + vid->screen->h - (FONT_HEIGHT + FONT_WIDTH_STRIDE), msg); + else + sdl_rs90_blit_text16(vid, FONT_WIDTH_STRIDE, + vid->screen->h - (FONT_HEIGHT + FONT_WIDTH_STRIDE), msg); + } + + /* Pixel manipulation complete - unlock + * SDL surface */ + if (SDL_MUSTLOCK(vid->screen)) + SDL_UnlockSurface(vid->screen); + + SDL_Flip(vid->screen); + + return true; +} + +static void sdl_rs90_set_texture_enable(void *data, bool state, bool full_screen) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return; + + vid->menu_active = state; +} + +static void sdl_rs90_set_texture_frame(void *data, const void *frame, bool rgb32, + unsigned width, unsigned height, float alpha) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely( + !vid || + rgb32 || + (width > SDL_RS90_WIDTH) || + (height > SDL_RS90_HEIGHT))) + return; + + memcpy(vid->menu_texture, frame, width * height * sizeof(uint16_t)); +} + +static void sdl_rs90_gfx_set_nonblock_state(void *data, bool toggle, + bool adaptive_vsync_enabled, unsigned swap_interval) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + bool vsync = !toggle; + + if (unlikely(!vid)) + return; + + /* Check whether vsync status has changed */ + if (vid->vsync != vsync) + { + unsigned current_width = vid->content_width; + unsigned current_height = vid->content_height; + vid->vsync = vsync; + + /* Update video mode */ + + /* TODO/FIXME: The following workaround is required + * on GCW0 devices; check whether it is required on + * the RS-90, and remove if not */ + + /* Note that a tedious workaround is required... + * - Calling SDL_SetVideoMode() with the currently + * set width, height and pixel format can randomly + * become a noop even if the surface flags change. + * - Since all we are doing here is changing the VSYNC + * parameter (which just modifies surface flags), this + * means the VSYNC toggle may not be registered... + * - This is a huge problem when enabling fast forward, + * because VSYNC ON effectively limits maximum frame + * rate - if we push frames too rapidly, the OS chokes + * and the display freezes. + * We have to ensure that the VSYNC state change is + * applied in all cases. We can only do this by forcing + * a 'real' video mode update, which means adjusting the + * video resolution. We therefore end up calling + * sdl_rs90_set_output() *twice*, setting the dimensions + * to an arbitrary value before restoring the actual + * desired width/height */ + sdl_rs90_set_output(vid, + current_width, + (current_height > 4) ? (current_height - 2) : 16, + vid->rgb32); + + sdl_rs90_set_output(vid, + current_width, current_height, vid->rgb32); + } +} + +static void sdl_rs90_gfx_check_window(sdl_rs90_video_t *vid) +{ + SDL_Event event; + + SDL_PumpEvents(); + while (SDL_PeepEvents(&event, 1, SDL_GETEVENT, SDL_QUITMASK)) + { + if (event.type != SDL_QUIT) + continue; + + vid->quitting = true; + break; + } +} + +static bool sdl_rs90_gfx_alive(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return false; + + sdl_rs90_gfx_check_window(vid); + return !vid->quitting; +} + +static bool sdl_rs90_gfx_focus(void *data) +{ + return true; +} + +static bool sdl_rs90_gfx_suppress_screensaver(void *data, bool enable) +{ + return false; +} + +static bool sdl_rs90_gfx_has_windowed(void *data) +{ + return false; +} + +static void sdl_rs90_gfx_viewport_info(void *data, struct video_viewport *vp) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (unlikely(!vid)) + return; + + vp->x = 0; + vp->y = 0; + vp->width = vp->full_width = vid->frame_width; + vp->height = vp->full_height = vid->frame_height; +} + +static float sdl_rs90_get_refresh_rate(void *data) +{ +#if defined(DINGUX_BETA) + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + + if (!vid) + return 0.0f; + + switch (vid->refresh_rate) + { + case DINGUX_REFRESH_RATE_50HZ: + return 50.0f; + default: + break; + } +#endif + + return 60.0f; +} + +static void sdl_rs90_set_filtering(void *data, unsigned index, bool smooth, bool ctx_scaling) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + settings_t *settings = config_get_ptr(); + enum dingux_rs90_softfilter_type softfilter_type = (settings) ? + (enum dingux_rs90_softfilter_type)settings->uints.video_dingux_rs90_softfilter_type : + DINGUX_RS90_SOFTFILTER_POINT; + + if (!vid || !settings) + return; + + /* Update software filter setting, if required */ + if (vid->softfilter_type != softfilter_type) + { + vid->softfilter_type = softfilter_type; + sdl_rs90_set_scale_frame_functions(vid); + } +} + +static void sdl_rs90_apply_state_changes(void *data) +{ + sdl_rs90_video_t *vid = (sdl_rs90_video_t*)data; + settings_t *settings = config_get_ptr(); + bool keep_aspect = (settings) ? settings->bools.video_dingux_ipu_keep_aspect : true; + bool integer_scaling = (settings) ? settings->bools.video_scale_integer : false; + + if (!vid || !settings) + return; + + if ((vid->keep_aspect != keep_aspect) || + (vid->scale_integer != integer_scaling)) + { + vid->keep_aspect = keep_aspect; + vid->scale_integer = integer_scaling; + + /* Reassign frame scaling function pointers */ + sdl_rs90_set_scale_frame_functions(vid); + + /* Aspect/scaling changes require all frame + * dimension/padding/cropping parameters to + * be recalculated. Easiest method is to just + * (re-)set the current output video mode + * Note: If menu is active, colour depth is + * overridden to 16 bit */ + sdl_rs90_set_output(vid, vid->content_width, + vid->content_height, vid->menu_active ? false : vid->rgb32); + } +} + +static uint32_t sdl_rs90_get_flags(void *data) +{ + return 0; +} + +static const video_poke_interface_t sdl_rs90_poke_interface = { + sdl_rs90_get_flags, + NULL, + NULL, + NULL, + sdl_rs90_get_refresh_rate, + sdl_rs90_set_filtering, + NULL, /* get_video_output_size */ + NULL, /* get_video_output_prev */ + NULL, /* get_video_output_next */ + NULL, /* get_current_framebuffer */ + NULL, /* get_proc_address */ + NULL, + sdl_rs90_apply_state_changes, + sdl_rs90_set_texture_frame, + sdl_rs90_set_texture_enable, + NULL, + NULL, /* sdl_show_mouse */ + NULL, /* sdl_grab_mouse_toggle */ + NULL, /* get_current_shader */ + NULL, /* get_current_software_framebuffer */ + NULL /* get_hw_render_interface */ +}; + +static void sdl_rs90_get_poke_interface(void *data, const video_poke_interface_t **iface) +{ + *iface = &sdl_rs90_poke_interface; +} + +static bool sdl_rs90_gfx_set_shader(void *data, + enum rarch_shader_type type, const char *path) +{ + return false; +} + +video_driver_t video_sdl_rs90 = { + sdl_rs90_gfx_init, + sdl_rs90_gfx_frame, + sdl_rs90_gfx_set_nonblock_state, + sdl_rs90_gfx_alive, + sdl_rs90_gfx_focus, + sdl_rs90_gfx_suppress_screensaver, + sdl_rs90_gfx_has_windowed, + sdl_rs90_gfx_set_shader, + sdl_rs90_gfx_free, + "sdl_rs90", + NULL, + NULL, /* set_rotation */ + sdl_rs90_gfx_viewport_info, + NULL, /* read_viewport */ + NULL, /* read_frame_raw */ +#ifdef HAVE_OVERLAY + NULL, +#endif +#ifdef HAVE_VIDEO_LAYOUT + NULL, +#endif + sdl_rs90_get_poke_interface +}; diff --git a/gfx/drivers_context/psl1ght_ctx.c b/gfx/drivers_context/psl1ght_ctx.c new file mode 100755 index 0000000000..bb56e4ade3 --- /dev/null +++ b/gfx/drivers_context/psl1ght_ctx.c @@ -0,0 +1,351 @@ +/* RetroArch - A frontend for libretro. + * Copyright (C) 2010-2014 - Hans-Kristian Arntzen + * Copyright (C) 2011-2017 - Daniel De Matteis + * + * RetroArch is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software Found- + * ation, either version 3 of the License, or (at your option) any later version. + * + * RetroArch is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; + * without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR + * PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with RetroArch. + * If not, see . + */ + +#include + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include + +#include "../../configuration.h" +#include "../../retroarch.h" +#include "../../verbosity.h" +#include +#include "../../frontend/frontend_driver.h" +#include + +typedef struct gfx_ctx_psl1ght_data +{ +#if defined(HAVE_PSGL) + PSGLdevice* gl_device; + PSGLcontext* gl_context; +#else + gcmContextData *rx_context; +#endif +} gfx_ctx_psl1ght_data_t; + +/* TODO/FIXME - static global */ +static enum gfx_ctx_api ps3_api = GFX_CTX_RSX_API; + +static void gfx_ctx_psl1ght_get_resolution(unsigned idx, + unsigned *width, unsigned *height) +{ + CellVideoOutResolution resolution; + cellVideoOutGetResolution(idx, &resolution); + + *width = resolution.width; + *height = resolution.height; +} + +static float gfx_ctx_psl1ght_get_aspect_ratio(void *data) +{ + CellVideoOutState videoState; + + cellVideoOutGetState(CELL_VIDEO_OUT_PRIMARY, 0, &videoState); + + switch (videoState.displayMode.aspect) + { + case CELL_VIDEO_OUT_ASPECT_4_3: + return 4.0f/3.0f; + case CELL_VIDEO_OUT_ASPECT_16_9: + break; + } + + return 16.0f/9.0f; +} + +static void gfx_ctx_psl1ght_get_available_resolutions(void) +{ + unsigned i; + uint32_t videomode[] = { + CELL_VIDEO_OUT_RESOLUTION_480, + CELL_VIDEO_OUT_RESOLUTION_576, + CELL_VIDEO_OUT_RESOLUTION_960x1080, + CELL_VIDEO_OUT_RESOLUTION_720, + CELL_VIDEO_OUT_RESOLUTION_1280x1080, + CELL_VIDEO_OUT_RESOLUTION_1440x1080, + CELL_VIDEO_OUT_RESOLUTION_1600x1080, + CELL_VIDEO_OUT_RESOLUTION_1080 + }; + uint32_t resolution_count = 0; + bool defaultresolution = true; + uint16_t num_videomodes = sizeof(videomode) / sizeof(uint32_t); + global_t *global = global_get_ptr(); + + if (global->console.screen.resolutions.check) + return; + + for (i = 0; i < num_videomodes; i++) + { + if (cellVideoOutGetResolutionAvailability( + CELL_VIDEO_OUT_PRIMARY, videomode[i], + CELL_VIDEO_OUT_ASPECT_AUTO, 0)) + resolution_count++; + } + + global->console.screen.resolutions.count = 0; + global->console.screen.resolutions.list = + malloc(resolution_count * sizeof(uint32_t)); + + for (i = 0; i < num_videomodes; i++) + { + if (cellVideoOutGetResolutionAvailability( + CELL_VIDEO_OUT_PRIMARY, + videomode[i], + CELL_VIDEO_OUT_ASPECT_AUTO, 0)) + { + global->console.screen.resolutions.list[ + global->console.screen.resolutions.count++] = videomode[i]; + global->console.screen.resolutions.initial.id = videomode[i]; + + if (global->console.screen.resolutions.current.id == videomode[i]) + { + defaultresolution = false; + global->console.screen.resolutions.current.idx = + global->console.screen.resolutions.count-1; + } + } + } + + /* In case we didn't specify a resolution - + * make the last resolution + that was added to the list (the highest resolution) + the default resolution */ + if (global->console.screen.resolutions.current.id > num_videomodes || defaultresolution) + { + global->console.screen.resolutions.current.idx = resolution_count - 1; + global->console.screen.resolutions.current.id = global->console.screen.resolutions.list[global->console.screen.resolutions.current.idx]; + } + + global->console.screen.resolutions.check = true; +} + +static void gfx_ctx_psl1ght_set_swap_interval(void *data, int interval) +{ +#if defined(HAVE_PSGL) + if (interval == 1) + glEnable(GL_VSYNC_SCE); + else + glDisable(GL_VSYNC_SCE); +#endif +} + +static void gfx_ctx_psl1ght_check_window(void *data, bool *quit, + bool *resize, unsigned *width, unsigned *height) +{ + +} + +static bool gfx_ctx_psl1ght_has_focus(void *data) { return true; } +static bool gfx_ctx_psl1ght_suppress_screensaver(void *data, bool enable) { return false; } + +static void gfx_ctx_psl1ght_swap_buffers(void *data) +{ +#ifdef HAVE_PSGL + psglSwap(); +#endif +#ifdef HAVE_SYSUTILS + cellSysutilCheckCallback(); +#endif +} + +static void gfx_ctx_psl1ght_get_video_size(void *data, + unsigned *width, unsigned *height) +{ + gfx_ctx_psl1ght_data_t *psl1ght = (gfx_ctx_psl1ght_data_t*)data; + +#if defined(HAVE_PSGL) + if (psl1ght) + psglGetDeviceDimensions(ps3->gl_device, width, height); +#endif +} + +static void *gfx_ctx_psl1ght_init(void *video_driver) +{ + printf("gfx_ctx_psl1ght_init: %p\n", video_driver); + global_t *global = global_get_ptr(); + gfx_ctx_psl1ght_data_t *psl1ght = (gfx_ctx_psl1ght_data_t*) + calloc(1, sizeof(gfx_ctx_psl1ght_data_t)); + + if (!psl1ght) + return NULL; + + + + global->console.screen.pal_enable = + cellVideoOutGetResolutionAvailability( + CELL_VIDEO_OUT_PRIMARY, CELL_VIDEO_OUT_RESOLUTION_576, + CELL_VIDEO_OUT_ASPECT_AUTO, 0); + + gfx_ctx_psl1ght_get_available_resolutions(); + + return psl1ght; +} + +static bool gfx_ctx_psl1ght_set_video_mode(void *data, + unsigned width, unsigned height, + bool fullscreen) { return true; } + +static void gfx_ctx_psl1ght_destroy_resources(gfx_ctx_psl1ght_data_t *ps3) +{ + if (!ps3) + return; + +#if defined(HAVE_PSGL) + psglDestroyContext(ps3->gl_context); + psglDestroyDevice(ps3->gl_device); + + psglExit(); +#endif +} + +static void gfx_ctx_psl1ght_destroy(void *data) +{ + gfx_ctx_psl1ght_data_t *ps3 = (gfx_ctx_psl1ght_data_t*)data; + + if (!ps3) + return; + + gfx_ctx_psl1ght_destroy_resources(ps3); + free(data); +} + +static void gfx_ctx_psl1ght_input_driver(void *data, + const char *joypad_name, + input_driver_t **input, void **input_data) +{ + void *ps3input = input_driver_init_wrap(&input_ps3, joypad_name); + + *input = ps3input ? &input_ps3 : NULL; + *input_data = ps3input; +} + +static enum gfx_ctx_api gfx_ctx_psl1ght_get_api(void *data) { return ps3_api; } + +static bool gfx_ctx_psl1ght_bind_api(void *data, + enum gfx_ctx_api api, unsigned major, unsigned minor) +{ + ps3_api = api; + + if (api == GFX_CTX_RSX_API) + return true; + + return false; +} + +static void gfx_ctx_psl1ght_get_video_output_size(void *data, + unsigned *width, unsigned *height) +{ + global_t *global = global_get_ptr(); + + if (!global) + return; + + gfx_ctx_psl1ght_get_resolution(global->console.screen.resolutions.current.id, + width, height); + + if (*width == 720 && *height == 576) + { + if (global->console.screen.pal_enable) + global->console.screen.pal60_enable = true; + } + else + { + global->console.screen.pal_enable = false; + global->console.screen.pal60_enable = false; + } +} + +static void gfx_ctx_psl1ght_get_video_output_prev(void *data) +{ + global_t *global = global_get_ptr(); + + if (!global) + return; + + if (global->console.screen.resolutions.current.idx) + { + global->console.screen.resolutions.current.idx--; + global->console.screen.resolutions.current.id = + global->console.screen.resolutions.list + [global->console.screen.resolutions.current.idx]; + } +} + +static void gfx_ctx_psl1ght_get_video_output_next(void *data) +{ + global_t *global = global_get_ptr(); + + if (!global) + return; + + if (global->console.screen.resolutions.current.idx + 1 < + global->console.screen.resolutions.count) + { + global->console.screen.resolutions.current.idx++; + global->console.screen.resolutions.current.id = + global->console.screen.resolutions.list + [global->console.screen.resolutions.current.idx]; + } +} + +static uint32_t gfx_ctx_psl1ght_get_flags(void *data) +{ + uint32_t flags = 0; + +#ifdef HAVE_CG + BIT32_SET(flags, GFX_CTX_FLAGS_SHADERS_CG); +#endif + + return flags; +} + +static void gfx_ctx_psl1ght_set_flags(void *data, uint32_t flags) { } + +const gfx_ctx_driver_t gfx_ctx_psl1ght = { + gfx_ctx_psl1ght_init, + gfx_ctx_psl1ght_destroy, + gfx_ctx_psl1ght_get_api, + gfx_ctx_psl1ght_bind_api, + gfx_ctx_psl1ght_set_swap_interval, + gfx_ctx_psl1ght_set_video_mode, + gfx_ctx_psl1ght_get_video_size, + NULL, /* get_refresh_rate */ + gfx_ctx_psl1ght_get_video_output_size, + gfx_ctx_psl1ght_get_video_output_prev, + gfx_ctx_psl1ght_get_video_output_next, + NULL, /* get_metrics */ + NULL, + NULL, /* update_title */ + gfx_ctx_psl1ght_check_window, + NULL, /* set_resize */ + gfx_ctx_psl1ght_has_focus, + gfx_ctx_psl1ght_suppress_screensaver, + false, /* has_windowed */ + gfx_ctx_psl1ght_swap_buffers, + gfx_ctx_psl1ght_input_driver, + NULL, + NULL, + NULL, + NULL, + "psl1ght", + gfx_ctx_psl1ght_get_flags, + gfx_ctx_psl1ght_set_flags, + NULL, + NULL +}; diff --git a/gfx/drivers_display/gfx_display_wiiu.c b/gfx/drivers_display/gfx_display_wiiu.c index b11870c322..0abcd6b75e 100644 --- a/gfx/drivers_display/gfx_display_wiiu.c +++ b/gfx/drivers_display/gfx_display_wiiu.c @@ -283,7 +283,7 @@ static void gfx_display_wiiu_scissor_begin( int x, int y, unsigned width, unsigned height) { - GX2SetScissor(MAX(x, 0), MAX(video_height - y - height, 0), MIN(width, video_width), MIN(height, video_height)); + GX2SetScissor(MAX(x, 0), MAX(y, 0), MIN(width, video_width), MIN(height, video_height)); } static void gfx_display_wiiu_scissor_end( diff --git a/gfx/drivers_font/wiiu_font.c b/gfx/drivers_font/wiiu_font.c index b9ba5369bc..3bbd111b01 100644 --- a/gfx/drivers_font/wiiu_font.c +++ b/gfx/drivers_font/wiiu_font.c @@ -65,7 +65,7 @@ static void* wiiu_font_init_font(void* data, const char* font_path, font->texture.viewNumSlices = 1; font->texture.surface.format = GX2_SURFACE_FORMAT_UNORM_R8; - font->texture.compMap = GX2_COMP_SEL(_R, _R, _R, _R); + font->texture.compMap = GX2_COMP_SEL(_1, _1, _1, _R); GX2CalcSurfaceSizeAndAlignment(&font->texture.surface); GX2InitTextureRegs(&font->texture); @@ -258,7 +258,7 @@ static void wiiu_font_render_message( return; } - line_height = scale / line_metrics->height; + line_height = line_metrics->height * scale / wiiu->vp.height; for (;;) { diff --git a/gfx/gfx_widgets.c b/gfx/gfx_widgets.c index f3a650f9e3..bdcbe2a08a 100644 --- a/gfx/gfx_widgets.c +++ b/gfx/gfx_widgets.c @@ -1037,9 +1037,15 @@ void gfx_widgets_iterate( { size_t i; dispgfx_widget_t *p_dispwidget = (dispgfx_widget_t*)data; - /* Check whether screen dimensions or menu scale - * factor have changed */ - float scale_factor = 0.0f; + /* c.f. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + * On some platforms (e.g. 32-bit x86 without SSE), + * gcc can produce inconsistent floating point results + * depending upon optimisation level. This can break + * floating point variable comparisons. A workaround is + * to declare the affected variable as 'volatile', which + * disables optimisations and removes excess precision + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c87) */ + volatile float scale_factor = 0.0f; gfx_display_t *p_disp = (gfx_display_t*)data_disp; settings_t *settings = (settings_t*)settings_data; #ifdef HAVE_XMB @@ -1051,6 +1057,8 @@ void gfx_widgets_iterate( scale_factor = gfx_display_get_widget_dpi_scale(p_disp, settings, width, height, fullscreen); + /* Check whether screen dimensions or menu scale + * factor have changed */ if ((scale_factor != p_dispwidget->last_scale_factor) || (width != p_dispwidget->last_video_width) || (height != p_dispwidget->last_video_height)) diff --git a/gfx/video_crt_switch.c b/gfx/video_crt_switch.c index 9d7cd0ffba..bf6c403941 100644 --- a/gfx/video_crt_switch.c +++ b/gfx/video_crt_switch.c @@ -87,36 +87,45 @@ static void crt_aspect_ratio_switch( videocrt_switch_t *p_switch, unsigned width, unsigned height, unsigned srm_width, unsigned srm_height) { - /* send aspect float to video_driver */ - RARCH_LOG("[CRT]: Setting Video Screen Size to: %dx%d \n", width, height); - video_driver_set_size(srm_width , srm_height); - video_driver_set_viewport(srm_width , srm_height,1,1); - p_switch->fly_aspect = (float)width / (float)height; video_driver_set_aspect_ratio_value((float)p_switch->fly_aspect); RARCH_LOG("[CRT]: Setting Aspect Ratio: %f \n", (float)p_switch->fly_aspect); + RARCH_LOG("[CRT]: Setting Video Screen Size to: %dx%d \n", width, height); + video_driver_set_size(width , height); + video_driver_set_viewport(width , height,1,1); + video_driver_apply_state_changes(); } static void set_aspect(videocrt_switch_t *p_switch, unsigned int width, unsigned int height, unsigned int srm_width, unsigned srm_height, - unsigned int srm_xscale, unsigned srm_yscale) + unsigned int srm_xscale, unsigned srm_yscale, bool srm_isstretched ) { unsigned int patched_width = 0; unsigned int patched_height = 0; int scaled_width = 0; int scaled_height = 0; - /* used to fix aspect shoule SR not find a resolution */ + + /* used to fix aspect should SR not find a resolution */ if (srm_width == 0) { video_driver_get_size(&patched_width, &patched_height); + srm_xscale = 1; + srm_yscale = 1; }else{ + /* use native values as we will be multiplying by srm scale later. */ patched_width = width; patched_height = height; } + if (srm_isstretched && srm_width > 0) + { + srm_xscale = srm_width/width; + srm_yscale = srm_height/height; + } + scaled_width = roundf(patched_width*srm_xscale); scaled_height = roundf(patched_height*srm_yscale); @@ -127,22 +136,19 @@ static bool crt_sr2_init(videocrt_switch_t *p_switch, int monitor_index, unsigne { const char* err_msg; char* mode; - char index = 0; - char mindex[1]; + char index[10]; + if (monitor_index+1 >= 0 && monitor_index+1 < 10) - index = monitor_index+48; + sprintf(index, "%d", monitor_index); else - index = '0'; - - mindex[0] = index; + sprintf(index, "%s", "0"); if (!p_switch->sr2_active) { RARCH_LOG("[CRT]: SR init \n"); - sr_init(); #if (__STDC_VERSION__ >= 199409L) /* no logs for C98 or less */ sr_set_log_callback_info(RARCH_LOG); @@ -167,23 +173,22 @@ static bool crt_sr2_init(videocrt_switch_t *p_switch, int monitor_index, unsigne RARCH_LOG("[CRT]: CRT Mode: %d - Selected from ini \n", crt_mode) ; } - if (super_width >2 ) sr_set_user_mode(super_width, 0, 0); RARCH_LOG("[CRT]: SR init_disp \n"); if (monitor_index+1 > 0) { - RARCH_LOG("SRobj: RA Monitor Index: %s\n",mindex); - p_switch->rtn = sr_init_disp(mindex); - RARCH_LOG("[CRT]: SR Disp Monitor Index: %s \n", mindex); + RARCH_LOG("[CRT]: RA Monitor Index Manual: %s\n", &index[0]); + p_switch->rtn = sr_init_disp(index); + RARCH_LOG("[CRT]: SR Disp Monitor Index Manual: %s \n", &index[0]); } if (monitor_index == -1) { - RARCH_LOG("SRobj: RA Monitor Index: %s\n",NULL); - p_switch->rtn = sr_init_disp(NULL); - RARCH_LOG("[CRT]: SR Disp Monitor Index: Auto \n"); + RARCH_LOG("[CRT]: RA Monitor Index Auto: %s\n","auto"); + p_switch->rtn = sr_init_disp("auto"); + RARCH_LOG("[CRT]: SR Disp Monitor Index Auto: Auto \n"); } RARCH_LOG("[CRT]: SR rtn %d \n", p_switch->rtn); @@ -247,12 +252,12 @@ static void switch_res_crt( } p_switch->sr_core_hz = srm.refresh; - set_aspect(p_switch, w , h, srm.width, srm.height, srm.x_scale, srm.y_scale); + set_aspect(p_switch, w , h, srm.width, srm.height, srm.x_scale, srm.y_scale, srm.is_stretched); RARCH_LOG("[CRT]: SR scaled X:%d Y:%d \n",srm.x_scale, srm.y_scale); }else { - set_aspect(p_switch, width , height, width, height ,1,1); + set_aspect(p_switch, width , height, width, height ,1,1, false); video_driver_set_size(width , height); video_driver_apply_state_changes(); @@ -305,7 +310,7 @@ static void crt_fix_hh_res(videocrt_switch_t *p_switch, int native_width, int wi int corrected_height = 240; switch_res_crt(p_switch, corrected_width, corrected_height , crt_mode, corrected_width, monitor_index-1, super_width); - set_aspect(p_switch, native_width , height, native_width, height ,1,1); + set_aspect(p_switch, native_width , height, native_width, height ,1,1, false); video_driver_set_size(native_width , height); @@ -484,7 +489,7 @@ static void crt_rpi_switch(videocrt_switch_t *p_switch, int width, int height, f set_aspect(p_switch, width, height, width, height, - 1, 1); + 1, 1, false); int w = width; while (w < 1920) { diff --git a/gfx/video_defines.h b/gfx/video_defines.h index 2a1dd62a39..33f94d584b 100644 --- a/gfx/video_defines.h +++ b/gfx/video_defines.h @@ -55,6 +55,7 @@ enum aspect_ratio ASPECT_RATIO_SQUARE, ASPECT_RATIO_CORE, ASPECT_RATIO_CUSTOM, + ASPECT_RATIO_FULL, ASPECT_RATIO_END }; @@ -116,7 +117,7 @@ enum text_alignment #define COLOR_ABGR(r, g, b, a) (((unsigned)(a) << 24) | ((b) << 16) | ((g) << 8) | ((r) << 0)) #endif -#define LAST_ASPECT_RATIO ASPECT_RATIO_CUSTOM +#define LAST_ASPECT_RATIO ASPECT_RATIO_FULL /* ABGR color format defines */ diff --git a/gfx/video_shader_parse.h b/gfx/video_shader_parse.h index 5399f35f7a..4e41c35e08 100644 --- a/gfx/video_shader_parse.h +++ b/gfx/video_shader_parse.h @@ -34,7 +34,7 @@ RETRO_BEGIN_DECLS #endif #ifndef GFX_MAX_PARAMETERS -#define GFX_MAX_PARAMETERS 512 +#define GFX_MAX_PARAMETERS 1024 #endif #ifndef GFX_MAX_FRAME_HISTORY diff --git a/griffin/griffin.c b/griffin/griffin.c index 9b342331dd..5d295cf2e3 100644 --- a/griffin/griffin.c +++ b/griffin/griffin.c @@ -272,7 +272,9 @@ VIDEO CONTEXT #include "../gfx/drivers_context/qnx_ctx.c" #elif defined(EMSCRIPTEN) #include "../gfx/drivers_context/emscriptenegl_ctx.c" -#elif defined(__PS3__) && !defined(__PSL1GHT__) +#elif defined(__PSL1GHT__) +#include "../gfx/drivers_context/psl1ght_ctx.c" +#elif defined(__PS3__) #include "../gfx/drivers_context/ps3_ctx.c" #endif @@ -469,6 +471,14 @@ VIDEO DRIVER #include "../gfx/common/sdl2_common.c" #endif +#if defined(DINGUX) && defined(HAVE_SDL_DINGUX) +#if defined(RS90) +#include "../gfx/drivers/sdl_rs90_gfx.c" +#else +#include "../gfx/drivers/sdl_dingux_gfx.c" +#endif +#endif + #ifdef HAVE_VG #include "../gfx/drivers/vg.c" #endif @@ -1509,9 +1519,9 @@ DEPENDENCIES #endif #ifdef WANT_IOSUHAX -#include "../deps/libiosuhax/iosuhax.c" -#include "../deps/libiosuhax/iosuhax_devoptab.c" -#include "../deps/libiosuhax/iosuhax_disc_interface.c" +#include "../deps/libiosuhax/source/iosuhax.c" +#include "../deps/libiosuhax/source/iosuhax_devoptab.c" +#include "../deps/libiosuhax/source/iosuhax_disc_interface.c" #endif /*============================================================ diff --git a/input/drivers/rwebinput_input.c b/input/drivers/rwebinput_input.c index be4b631bde..58ae91b6ab 100644 --- a/input/drivers/rwebinput_input.c +++ b/input/drivers/rwebinput_input.c @@ -315,7 +315,7 @@ static void *rwebinput_input_init(const char *joypad_driver) if (r != EMSCRIPTEN_RESULT_SUCCESS) { RARCH_ERR( - "[EMSCRIPTEN/INPUT] failed to create keydown callback: %d\n", r); + "[EMSCRIPTEN/INPUT] failed to create keyup callback: %d\n", r); } r = emscripten_set_keypress_callback( diff --git a/input/drivers/udev_input.c b/input/drivers/udev_input.c index ad65ddd125..979425f69c 100644 --- a/input/drivers/udev_input.c +++ b/input/drivers/udev_input.c @@ -112,6 +112,7 @@ typedef struct int32_t x_rel, y_rel; bool l, r, m, b4, b5; bool wu, wd, whu, whd; + bool pp; } udev_input_mouse_t; struct udev_input_device @@ -252,7 +253,7 @@ static udev_input_mouse_t *udev_get_mouse( static void udev_mouse_set_x(udev_input_mouse_t *mouse, int32_t x, bool abs) { - video_viewport_t vp; + video_viewport_t vp; if (abs) { @@ -427,7 +428,9 @@ static void udev_handle_mouse(void *data, case BTN_MIDDLE: mouse->m = event->value; break; - + case BTN_TOUCH: + mouse->pp = event->value; + break; /*case BTN_??: mouse->b4 = event->value; break;*/ @@ -478,11 +481,14 @@ static void udev_handle_mouse(void *data, break; } } +#define test_bit(array, bit) (array[bit/8] & (1<<(bit%8))) static int udev_input_add_device(udev_input_t *udev, enum udev_input_dev_type type, const char *devnode, device_handle_cb cb) { unsigned char keycaps[(KEY_MAX / 8) + 1]; + unsigned char abscaps[(ABS_MAX / 8) + 1]; + int has_absolutes = 0; int fd; struct stat st; #if defined(HAVE_EPOLL) @@ -494,6 +500,9 @@ static int udev_input_add_device(udev_input_t *udev, udev_input_device_t **tmp; udev_input_device_t *device = NULL; + memset(keycaps, '\0', sizeof (keycaps)); + memset(keycaps, '\0', sizeof (abscaps)); + st.st_dev = 0; if (stat(devnode, &st) < 0) @@ -520,33 +529,36 @@ static int udev_input_add_device(udev_input_t *udev, if (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof (keycaps)), keycaps) == -1) return -1; /* gotta have some buttons! return -1 to skip error logging for this:) */ - if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) >= 0) - { - if (absinfo.minimum >= absinfo.maximum ) - { - device->mouse.x_min = -1; - device->mouse.x_max = -1; - } - else - { - device->mouse.x_min = absinfo.minimum; - device->mouse.x_max = absinfo.maximum; - } - } - if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) >= 0) + + if (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof (abscaps)), abscaps) != -1) { - if (absinfo.minimum >= absinfo.maximum ) - { - device->mouse.y_min = -1; - device->mouse.y_max = -1; - } - else - { - device->mouse.y_min = absinfo.minimum; - device->mouse.y_max = absinfo.maximum; - } - } + if ( (test_bit(abscaps, ABS_X)) && (test_bit(abscaps, ABS_Y)) ) + { + /* might be a touchpad... */ + if (test_bit(keycaps, BTN_TOUCH)) + { + /* touchpad, touchscreen, or tablet. */ + has_absolutes = 1; + } + } + } + device->mouse.x_min = device->mouse.y_min = device->mouse.x_max = device->mouse.y_max = 0; + + if (has_absolutes) + { + struct input_absinfo absinfo; + if (ioctl(fd, EVIOCGABS(ABS_X), &absinfo) == -1) + return 0; + device->mouse.x_min = absinfo.minimum; + device->mouse.x_max = absinfo.maximum; + + if (ioctl(fd, EVIOCGABS(ABS_Y), &absinfo) == -1) + return 0; + device->mouse.y_min = absinfo.minimum; + device->mouse.y_max = absinfo.maximum; + } + } tmp = ( udev_input_device_t**)realloc(udev->devices, @@ -944,7 +956,7 @@ static int16_t udev_pointer_state(udev_input_t *udev, case RETRO_DEVICE_ID_POINTER_Y: return udev_mouse_get_pointer_y(mouse, screen); case RETRO_DEVICE_ID_POINTER_PRESSED: - return mouse->l; + return mouse->pp; } return 0; @@ -1241,10 +1253,10 @@ static bool open_devices(udev_input_t *udev, if (fd != -1) { int check = udev_input_add_device(udev, type, devnode, cb); - if (!check && check != -1 ) - RARCH_DBG("[udev] udev_input_add_device error : %s (%s).\n", + if (check == 0) + RARCH_LOG("[udev] udev_input_add_device error : %s (%s).\n", devnode, strerror(errno)); - else if (check != -1 && check != 0) + else if (check == 1 ) { char ident[255]; if (ioctl(fd, EVIOCGNAME(sizeof(ident)), ident) < 0) @@ -1257,7 +1269,7 @@ static bool open_devices(udev_input_t *udev, devnode); device_keyboard++; } - else + else if (type == UDEV_INPUT_MOUSE || type== UDEV_INPUT_TOUCHPAD) { RARCH_LOG("[udev]: Added Device mouse#%d %s (%s) .\n", device_mouse, diff --git a/input/drivers_joypad/sdl_dingux_joypad.c b/input/drivers_joypad/sdl_dingux_joypad.c index 4b74166a40..8406390660 100644 --- a/input/drivers_joypad/sdl_dingux_joypad.c +++ b/input/drivers_joypad/sdl_dingux_joypad.c @@ -31,6 +31,11 @@ #include "../../configuration.h" #endif +#if !defined(RS90) +#define SDL_DINGUX_HAS_ANALOG 1 +#define SDL_DINGUX_HAS_MENU_TOGGLE 1 +#endif + /* Simple joypad driver designed to rationalise * the bizarre keyboard/gamepad hybrid setup * of OpenDingux devices */ @@ -66,7 +71,9 @@ typedef struct typedef struct { +#if defined(SDL_DINGUX_HAS_ANALOG) SDL_Joystick *device; +#endif #if defined(HAVE_LIBSHAKE) dingux_joypad_rumble_t rumble; #endif @@ -74,11 +81,15 @@ typedef struct uint16_t pad_state; int16_t analog_state[2][2]; bool connected; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) bool menu_toggle; +#endif } dingux_joypad_t; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) /* TODO/FIXME - global referenced outside */ extern uint64_t lifecycle_state; +#endif static dingux_joypad_t dingux_joypad; @@ -259,6 +270,7 @@ static void sdl_dingux_joypad_connect(void) { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; +#if defined(SDL_DINGUX_HAS_ANALOG) /* Open joypad device */ if (SDL_NumJoysticks() > 0) joypad->device = SDL_JoystickOpen(0); @@ -266,6 +278,7 @@ static void sdl_dingux_joypad_connect(void) /* If joypad exists, get number of axes */ if (joypad->device) joypad->num_axes = SDL_JoystickNumAxes(joypad->device); +#endif #if defined(HAVE_LIBSHAKE) /* Configure rumble interface */ @@ -289,8 +302,10 @@ static void sdl_dingux_joypad_disconnect(void) { dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; +#if defined(SDL_DINGUX_HAS_ANALOG) if (joypad->device) SDL_JoystickClose(joypad->device); +#endif if (joypad->connected) input_autoconfigure_disconnect(0, sdl_dingux_joypad.ident); @@ -329,7 +344,9 @@ static void sdl_dingux_joypad_destroy(void) Shake_Quit(); #endif +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); +#endif } static void *sdl_dingux_joypad_init(void *data) @@ -338,8 +355,11 @@ static void *sdl_dingux_joypad_init(void *data) uint32_t sdl_subsystem_flags = SDL_WasInit(0); memset(joypad, 0, sizeof(dingux_joypad_t)); +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); +#endif +#if defined(SDL_DINGUX_HAS_ANALOG) /* Initialise joystick subsystem, if required */ if (sdl_subsystem_flags == 0) { @@ -351,6 +371,7 @@ static void *sdl_dingux_joypad_init(void *data) if (SDL_InitSubSystem(SDL_INIT_JOYSTICK) < 0) return NULL; } +#endif #if defined(HAVE_LIBSHAKE) /* Initialise rumble interface */ @@ -397,6 +418,7 @@ static void sdl_dingux_joypad_get_buttons(unsigned port, input_bits_t *state) static int16_t sdl_dingux_joypad_axis_state(unsigned port, uint32_t joyaxis) { +#if defined(SDL_DINGUX_HAS_ANALOG) dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; int val = 0; int axis = -1; @@ -437,6 +459,9 @@ static int16_t sdl_dingux_joypad_axis_state(unsigned port, uint32_t joyaxis) return 0; return val; +#else + return 0; +#endif } static int16_t sdl_dingux_joypad_axis(unsigned port, uint32_t joyaxis) @@ -465,16 +490,20 @@ static int16_t sdl_dingux_joypad_state( /* Auto-binds are per joypad, not per user. */ const uint64_t joykey = (binds[i].joykey != NO_BTN) ? binds[i].joykey : joypad_info->auto_binds[i].joykey; +#if defined(SDL_DINGUX_HAS_ANALOG) const uint32_t joyaxis = (binds[i].joyaxis != AXIS_NONE) ? binds[i].joyaxis : joypad_info->auto_binds[i].joyaxis; - - if ((uint16_t)joykey != NO_BTN && +#endif + + if ((uint16_t)joykey != NO_BTN && (joypad->pad_state & (1 << (uint16_t)joykey))) ret |= (1 << i); +#if defined(SDL_DINGUX_HAS_ANALOG) else if (joyaxis != AXIS_NONE && - ((float)abs(sdl_dingux_joypad_axis_state(port_idx, joyaxis)) + ((float)abs(sdl_dingux_joypad_axis_state(port_idx, joyaxis)) / 0x8000) > joypad_info->axis_threshold) ret |= (1 << i); +#endif } return ret; @@ -485,6 +514,7 @@ static void sdl_dingux_joypad_poll(void) dingux_joypad_t *joypad = (dingux_joypad_t*)&dingux_joypad; SDL_Event event; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) /* Note: The menu toggle key is an awkward special * case - the press/release events happen almost * instantaneously, and since we only sample once @@ -496,6 +526,7 @@ static void sdl_dingux_joypad_poll(void) BIT64_CLEAR(lifecycle_state, RARCH_MENU_TOGGLE); joypad->menu_toggle = false; } +#endif /* All digital inputs map to keyboard keys * - X: SDLK_SPACE @@ -571,10 +602,12 @@ static void sdl_dingux_joypad_poll(void) case SDLK_LEFT: BIT16_SET(joypad->pad_state, RETRO_DEVICE_ID_JOYPAD_LEFT); break; +#if defined(SDL_DINGUX_HAS_MENU_TOGGLE) case SDLK_HOME: BIT64_SET(lifecycle_state, RARCH_MENU_TOGGLE); joypad->menu_toggle = true; break; +#endif default: break; } @@ -639,6 +672,7 @@ static void sdl_dingux_joypad_poll(void) } } +#if defined(SDL_DINGUX_HAS_ANALOG) /* Analog inputs come from the joypad device, * if connected */ if (joypad->device) @@ -676,6 +710,7 @@ static void sdl_dingux_joypad_poll(void) (axis_value < -0x7FFF) ? -0x7FFF : axis_value; } } +#endif } input_device_driver_t sdl_dingux_joypad = { diff --git a/input/drivers_joypad/wiiu/kpad_driver.c b/input/drivers_joypad/wiiu/kpad_driver.c index 2d7a36a4f4..0466975b5f 100644 --- a/input/drivers_joypad/wiiu/kpad_driver.c +++ b/input/drivers_joypad/wiiu/kpad_driver.c @@ -251,6 +251,12 @@ static void kpad_poll(void) } poll_failures[channel] = 0; + /* Several reads when a device is connected or an attachment added give */ + /* bogus results, try to weed them out */ + if (kpad.wpad_error || kpad.device_type == 255) { + continue; + } + kpad_poll_one_channel(channel, &kpad); } } diff --git a/input/input_defines.h b/input/input_defines.h index 036af0716a..07a0caac0d 100644 --- a/input/input_defines.h +++ b/input/input_defines.h @@ -135,6 +135,52 @@ enum analog_dpad_mode ANALOG_DPAD_LAST }; +enum input_toggle_type +{ + INPUT_TOGGLE_NONE = 0, + INPUT_TOGGLE_DOWN_Y_L_R, + INPUT_TOGGLE_L3_R3, + INPUT_TOGGLE_L1_R1_START_SELECT, + INPUT_TOGGLE_START_SELECT, + INPUT_TOGGLE_L3_R, + INPUT_TOGGLE_L_R, + INPUT_TOGGLE_HOLD_START, + INPUT_TOGGLE_HOLD_SELECT, + INPUT_TOGGLE_DOWN_SELECT, + INPUT_TOGGLE_L2_R2, + INPUT_TOGGLE_LAST +}; + +enum input_turbo_mode +{ + INPUT_TURBO_MODE_CLASSIC = 0, + INPUT_TURBO_MODE_SINGLEBUTTON, + INPUT_TURBO_MODE_SINGLEBUTTON_HOLD, + INPUT_TURBO_MODE_LAST +}; + +enum input_turbo_default_button +{ + INPUT_TURBO_DEFAULT_BUTTON_B = 0, + INPUT_TURBO_DEFAULT_BUTTON_Y, + INPUT_TURBO_DEFAULT_BUTTON_A, + INPUT_TURBO_DEFAULT_BUTTON_X, + INPUT_TURBO_DEFAULT_BUTTON_L, + INPUT_TURBO_DEFAULT_BUTTON_R, + INPUT_TURBO_DEFAULT_BUTTON_L2, + INPUT_TURBO_DEFAULT_BUTTON_R2, + INPUT_TURBO_DEFAULT_BUTTON_L3, + INPUT_TURBO_DEFAULT_BUTTON_R3, + INPUT_TURBO_DEFAULT_BUTTON_LAST +}; + +enum input_action +{ + INPUT_ACTION_NONE = 0, + INPUT_ACTION_AXIS_THRESHOLD, + INPUT_ACTION_MAX_USERS +}; + /* Specialized _MOUSE that targets the full screen regardless of viewport. */ #define RARCH_DEVICE_MOUSE_SCREEN (RETRO_DEVICE_MOUSE | 0x10000) diff --git a/input/input_driver.h b/input/input_driver.h index 10e32b1a30..180dfffa69 100644 --- a/input/input_driver.h +++ b/input/input_driver.h @@ -26,7 +26,7 @@ #ifdef HAVE_CONFIG_H #include "config.h" -#endif +#endif /* HAVE_CONFIG_H */ #include #include @@ -43,83 +43,57 @@ RETRO_BEGIN_DECLS -enum input_toggle_type -{ - INPUT_TOGGLE_NONE = 0, - INPUT_TOGGLE_DOWN_Y_L_R, - INPUT_TOGGLE_L3_R3, - INPUT_TOGGLE_L1_R1_START_SELECT, - INPUT_TOGGLE_START_SELECT, - INPUT_TOGGLE_L3_R, - INPUT_TOGGLE_L_R, - INPUT_TOGGLE_HOLD_START, - INPUT_TOGGLE_HOLD_SELECT, - INPUT_TOGGLE_DOWN_SELECT, - INPUT_TOGGLE_L2_R2, - INPUT_TOGGLE_LAST -}; - -enum input_turbo_mode -{ - INPUT_TURBO_MODE_CLASSIC = 0, - INPUT_TURBO_MODE_SINGLEBUTTON, - INPUT_TURBO_MODE_SINGLEBUTTON_HOLD, - INPUT_TURBO_MODE_LAST -}; - -enum input_turbo_default_button -{ - INPUT_TURBO_DEFAULT_BUTTON_B = 0, - INPUT_TURBO_DEFAULT_BUTTON_Y, - INPUT_TURBO_DEFAULT_BUTTON_A, - INPUT_TURBO_DEFAULT_BUTTON_X, - INPUT_TURBO_DEFAULT_BUTTON_L, - INPUT_TURBO_DEFAULT_BUTTON_R, - INPUT_TURBO_DEFAULT_BUTTON_L2, - INPUT_TURBO_DEFAULT_BUTTON_R2, - INPUT_TURBO_DEFAULT_BUTTON_L3, - INPUT_TURBO_DEFAULT_BUTTON_R3, - INPUT_TURBO_DEFAULT_BUTTON_LAST -}; - -enum input_action -{ - INPUT_ACTION_NONE = 0, - INPUT_ACTION_AXIS_THRESHOLD, - INPUT_ACTION_MAX_USERS -}; - struct retro_keybind { + /** + * Human-readable label for the control. + */ char *joykey_label; + + /** + * Human-readable label for an analog axis. + */ char *joyaxis_label; - /* Joypad axis. Negative and positive axes - * are embedded into this variable. */ + /** + * Joypad axis. Negative and positive axes are both represented by this variable. + */ uint32_t joyaxis; - /* Default joy axis binding value - - * for resetting bind to default */ + /** + * Default joy axis binding value for resetting bind to default. + */ uint32_t def_joyaxis; - /* Used by input_{push,pop}_analog_dpad(). */ + /** + * Used by input_{push,pop}_analog_dpad(). + */ uint32_t orig_joyaxis; enum msg_hash_enums enum_idx; + enum retro_key key; uint16_t id; - uint16_t mbutton; /* mouse button ID */ + /** + * What mouse button ID has been mapped to this control. + */ + uint16_t mbutton; - /* Joypad key. Joypad POV (hats) - * are embedded into this key as well. */ + /** + * Joypad key. Joypad POV (hats) are embedded into this key as well. + **/ uint16_t joykey; - /* Default key binding value - - * for resetting bind to default */ + /** + * Default key binding value (for resetting bind). + */ uint16_t def_joykey; + /** + * Determines whether or not the binding is valid. + */ bool valid; }; @@ -147,10 +121,10 @@ typedef struct } input_device_info_t; /** - * input_driver: * Organizes the functions and data structures of each driver that are accessed * by other parts of the input code. The input_driver structs are the "interface" * between RetroArch and the input driver. + * * Every driver must establish an input_driver struct with pointers to its own * implementations of these functions, and each of those input_driver structs is * declared below. @@ -158,53 +132,50 @@ typedef struct struct input_driver { /** - * init: Initializes input driver. + * Initializes input driver. * - * PARAMETERS - * @joypad_driver: Name of the joypad driver associated with the input driver + * @param joypad_driver Name of the joypad driver associated with the + * input driver */ void *(*init)(const char *joypad_driver); /** - * poll: Called once every frame to poll input. This function pointer can be set - * to NULL if not supported by the input driver, for example if a joypad driver - * is responsible for polling on a particular driver/platform. + * Called once every frame to poll input. This function pointer can be set + * to NULL if not supported by the input driver, for example if a joypad + * driver is responsible for polling on a particular driver/platform. * - * PARAMETERS - * @data: the input state struct + * @param data the input state struct */ void (*poll)(void *data); /** - * input_state: Queries state for a specified control on a specified input port. - * This function pointer can be set to NULL if not supported by the input driver, - * for example if a joypad driver is responsible for quering state for a particular - * driver/platform. + * Queries state for a specified control on a specified input port. This + * function pointer can be set to NULL if not supported by the input driver, + * for example if a joypad driver is responsible for quering state for a + * particular driver/platform. * - * PARAMETERS - * @joypad_data: The input state struct, defined by the input driver - * @sec_joypad_data: The input state struct of any secondary input device - * (e.g. MFi controllers), defined by a secondary input driver. - * May be NULL. Queried state to be returned is the logical - * OR of 'joypad_data' and 'sec_joypad_data' - * @joypad_info: Info struct for the controller to be queried, containing - * physical (hardware) device index and autoconfig input mapping. - * @retro_keybinds: Data structure for control mappings for all libretro - * input device abstractions - * @keyboard_mapping_blocked: - * If true, disregard custom keyboard mapping - * @port: Which RetroArch port is being polled - * @device: Which libretro abstraction is being polled - (RETRO_DEVICE_ID_RETROPAD, RETRO_DEVICE_ID_MOUSE, etc) - * @index: For controls that support more than one axis or can return - * multiple simultaneous inputs, such as an analog joystick - * or touchpad. - * @id: Which control is being polled (eg RETRO_DEVICE_ID_JOYPAD_START) + * @param joypad_data Input state struct, defined by the input driver + * @param sec_joypad_data Input state struct for secondary input devices (eg + * MFi controllers), defined by a secondary driver. + * Queried state to be returned is the logical OR of + * joypad_data and sec_joypad_data. May be NULL. + * @param joypad_info Info struct for the controller to be queried, + * with hardware device ID and autoconfig mapping. + * @param retro_keybinds Structure for control mappings for all libretro + * input device abstractions + * @param keyboard_mapping_blocked + * If true, disregard custom keyboard mapping + * @param port Which RetroArch port is being polled + * @param device Which libretro abstraction is being polled + * (RETRO_DEVICE_ID_RETROPAD, RETRO_DEVICE_ID_MOUSE) + * @param index For controls with more than one axis or multiple + * simultaneous inputs, such as an analog joystick + * or touchpad. + * @param id Which control is being polled + * (eg RETRO_DEVICE_ID_JOYPAD_START) * - * RETURNS - * Digital controls: Returns 1 for a pressed control and 0 otherwise. - * Analog controls: Retruns values in the range of a signed 16-bit integer, - * [-0x8000, 0x7fff] + * @return 1 for pressed digital control, 0 for non-pressed digital control. + * Values in the range of a signed 16-bit integer,[-0x8000, 0x7fff] */ int16_t (*input_state)(void *data, const input_device_driver_t *joypad_data, @@ -215,83 +186,73 @@ struct input_driver unsigned port, unsigned device, unsigned index, unsigned id); /** - * free: Frees the input struct. + * Frees the input struct. * - * PARAMETERS - * @data: The input state struct + * @param data The input state struct. */ void (*free)(void *data); /** - * set_sensor_state: Sets the state related for sensors, such - * as polling rate or enabling/disable the sensor entirely, etc. - * This function pointer may be set to NULL if setting sensor - * values is not supported. + * Sets the state related for sensors, such as polling rate or to deactivate + * the sensor entirely, etc. This function pointer may be set to NULL if + * setting sensor values is not supported. * - * PARAMETERS - * @data: The input state struct - * @port: Input port - * @effect: Sensor action - * @rate: Sensor rate update + * @param data The input state struct + * @param port + * @param effect Sensor action + * @param rate Sensor rate update * - * RETURNS - * Boolean true if the operation is successful. + * @return true if the operation is successful. **/ bool (*set_sensor_state)(void *data, unsigned port, enum retro_sensor_action action, unsigned rate); /** - * get_sensor_input: Retrieves the sensor state associated with - * the provided port and ID. This function pointer may be set to - * NULL if retreiving sensor state is not supported. + * Retrieves the sensor state associated with the provided port and ID. This + * function pointer may be set to NULL if retreiving sensor state is not + * supported. * - * PARAMETERS - * @data: The input state struct - * @port: Input port - * @id: Sensor ID + * @param data The input state struct + * @param port + * @param id Sensor ID * - * RETURNS - * The current state associated with the port and ID as a float. - **/ + * @return The current state associated with the port and ID as a float + **/ float (*get_sensor_input)(void *data, unsigned port, unsigned id); /** - * get_capabilities: The means for an input driver to indicate to RetroArch - * which libretro input abstractions the driver supports - * PARAMETERS - * @data: The input state struct + * The means for an input driver to indicate to RetroArch which libretro + * input abstractions the driver supports. * - * RETURNS - * a unit64_t composed via bitwise operators + * @param data The input state struct. + * + * @return A unit64_t composed via bitwise operators. */ uint64_t (*get_capabilities)(void *data); /** - * ident: The human-readable name of the input driver + * The human-readable name of the input driver. */ const char *ident; /** - * grab_mouse: Grab or ungrab the mouse according to the value of `state`. - * This function pointer can be set to NULL if the driver does not support - * grabbing the mouse. + * Grab or ungrab the mouse according to the value of `state`. This function + * pointer can be set to NULL if the driver does not support grabbing the + * mouse. * - * PARAMETERS - * @data: The input state struct - * @state: True to grab the mouse, false to ungrab + * @param data The input state struct + * @param state True to grab the mouse, false to ungrab */ void (*grab_mouse)(void *data, bool state); /** - * grab_stdin: Check to see if the input driver has claimed stdin, and - * therefore it is not available for other input. This function pointer - * can be set to NULL if the driver does not support claiming stdin. + * Check to see if the input driver has claimed stdin, and therefore it is + * not available for other input. This function pointercan be set to NULL if + * the driver does not support claiming stdin. * - * PARAMETERS - * @data: The input state struct + * @param data The input state struct * - * RETURNS - * True if the input driver has claimed stdin. This function pointer + * @return True if the input driver has claimed stdin. */ bool (*grab_stdin)(void *data); }; @@ -313,6 +274,408 @@ struct rarch_joypad_driver const char *ident; }; +/** + * Get an enumerated list of all input driver names + * + * @return string listing of all input driver names, separated by '|'. + **/ +const char* config_get_input_driver_options(void); + +/** + * Sets the rumble state. Used by RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE. + * + * @param port User number. + * @param effect Rumble effect. + * @param strength Strength of rumble effect. + * + * @return true if the rumble state has been successfully set + **/ +bool input_driver_set_rumble_state(unsigned port, + enum retro_rumble_effect effect, uint16_t strength); + +/** + * Sets the sensor state. Used by RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE. + * + * @param port + * @param effect Sensor action + * @param rate Sensor rate update + * + * @return true if the sensor state has been successfully set + **/ +bool input_sensor_set_state(unsigned port, + enum retro_sensor_action action, unsigned rate); + +/** + * Retrieves the sensor state associated with the provided port and ID. + * + * @param port + * @param id Sensor ID + * + * @return The current state associated with the port and ID as a float + **/ +float input_sensor_get_input(unsigned port, unsigned id); + +/** + * Retrieves the input driver state struct + * + * @return The input state struct + **/ +void *input_driver_get_data(void); + +/** + * Sets the input_driver_nonblock_state flag to true + **/ +void input_driver_set_nonblock_state(void); + +/** + * Sets the input_driver_nonblock_state flag to false + **/ +void input_driver_unset_nonblock_state(void); + +/** + * If the action is INPUT_ACTION_AXIS_THRESHOLD, return the current + * input_driver_axis_threshold. + * + * @return value of input_driver_axis_threshold or NULL for actions other than + * INPUT_ACTION_AXIS_THRESHOLD +**/ +float *input_driver_get_float(enum input_action action); + +/** + * If the action is INPUT_ACTION_MAX_USERS, return the current + * input_driver_max_users. + * + * @return value of input_driver_axis_threshold or NULL for actions other than + * INPUT_ACTION_AXIS_THRESHOLD +**/ +unsigned *input_driver_get_uint(enum input_action action); + +/** + * Get an enumerated list of all joypad driver names + * + * @return String listing of all joypad driver names, separated by '|'. + **/ +const char* config_get_joypad_driver_options(void); + +/** + * Initialize a joypad driver of name ident. If ident points to NULL or a + * zero-length string, equivalent to calling input_joypad_init_first(). + * + * @param ident identifier of driver to initialize. + * + * @return The joypad driver if found, otherwise NULL. + **/ +const input_device_driver_t *input_joypad_init_driver( + const char *ident, void *data); + +/** + * Takes as input analog key identifiers and converts them to corresponding + * bind IDs ident_minus and ident_plus. + * + * @param idx Analog key index (eg RETRO_DEVICE_INDEX_ANALOG_LEFT) + * @param ident Analog key identifier (eg RETRO_DEVICE_ID_ANALOG_X) + * @param ident_minus Bind ID minus, will be set by function. + * @param ident_plus Bind ID plus, will be set by function. + */ +#define input_conv_analog_id_to_bind_id(idx, ident, ident_minus, ident_plus) \ + switch ((idx << 1) | ident) \ + { \ + case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_X: \ + ident_minus = RARCH_ANALOG_LEFT_X_MINUS; \ + ident_plus = RARCH_ANALOG_LEFT_X_PLUS; \ + break; \ + case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_Y: \ + ident_minus = RARCH_ANALOG_LEFT_Y_MINUS; \ + ident_plus = RARCH_ANALOG_LEFT_Y_PLUS; \ + break; \ + case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_X: \ + ident_minus = RARCH_ANALOG_RIGHT_X_MINUS; \ + ident_plus = RARCH_ANALOG_RIGHT_X_PLUS; \ + break; \ + case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_Y: \ + ident_minus = RARCH_ANALOG_RIGHT_Y_MINUS; \ + ident_plus = RARCH_ANALOG_RIGHT_Y_PLUS; \ + break; \ + } + +/** + * Registers a newly connected pad with RetroArch. + * + * @param port Joystick number + * @param driver Handle for joypad driver handling joystick's input + **/ +void input_pad_connect(unsigned port, input_device_driver_t *driver); + + +/*****************************************************************************/ +#ifdef HAVE_HID +#include "include/hid_driver.h" + +/** + * Get an enumerated list of all HID driver names + * + * @return String listing of all HID driver names, separated by '|'. + **/ +const char* config_get_hid_driver_options(void); + +/** + * Finds first suitable HID driver and initializes. + * + * @return HID driver if found, otherwise NULL. + **/ +const hid_driver_t *input_hid_init_first(void); + +/** + * Get a pointer to the HID driver data structure + * + * @return Pointer to hid_data struct + **/ +const void *hid_driver_get_data(void); + +/** + * This should be called after we've invoked free() on the HID driver; the + * memory will have already been freed so we need to reset the pointer. + */ +void hid_driver_reset_data(void); + +#endif /* HAVE_HID */ +/*****************************************************************************/ + + +/** + * line_complete callback (when carriage return is pressed) + * + * @param userdata User data which will be passed to subsequent callbacks. + * @param line the line of input, which can be NULL. + **/ +typedef void (*input_keyboard_line_complete_t)(void *userdata, + const char *line); + +/** + * Callback for keypress events + * + * @param userdata The user data that was passed through from the keyboard press callback. + * @param code keycode + **/ +typedef bool (*input_keyboard_press_t)(void *userdata, unsigned code); + +struct input_keyboard_ctx_wait +{ + void *userdata; + input_keyboard_press_t cb; +}; + +/** + * Called by drivers when keyboard events are fired. Interfaces with the global + * driver struct and libretro callbacks. + * + * @param down Was Keycode pressed down? + * @param code Keycode. + * @param character Character inputted. + * @param mod TODO/FIXME/??? + **/ +void input_keyboard_event(bool down, unsigned code, uint32_t character, + uint16_t mod, unsigned device); + +/** + * Set the name of the device in the specified port + * + * @param port + */ +void input_config_set_device_name(unsigned port, const char *name); + +/** + * Set the formatted "display name" of the device in the specified port + * + * @param port + */ +void input_config_set_device_display_name(unsigned port, const char *name); + +/** + * Set the configuration path for the device in the specified port + * + * @param port + * @param path The path of the device config. + */ +void input_config_set_device_config_path(unsigned port, const char *path); + +/** + * Set the configuration name for the device in the specified port + * + * @param port + * @param name The name of the config to set. + */ +void input_config_set_device_config_name(unsigned port, const char *name); + +/** + * Set the joypad driver for the device in the specified port + * + * @param port + * @param driver The driver to set the given port to. + */ +void input_config_set_device_joypad_driver(unsigned port, const char *driver); + +/** + * Set the vendor ID (vid) for the device in the specified port + * + * @param port + * @param vid The VID to set the given device port to. + */ +void input_config_set_device_vid(unsigned port, uint16_t vid); + +/** + * Set the pad ID (pid) for the device in the specified port + * + * @param port + * @param pid The PID to set the given device port to. + */ +void input_config_set_device_pid(unsigned port, uint16_t pid); + +/** + * Sets the autoconfigured flag for the device in the specified port + * + * @param port + * @param autoconfigured Whether or nor the device is configured automatically. + */ +void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured); + +/** + * Sets the name index number for the device in the specified port + * + * @param port + * @param name_index The name index to set the device to use. + */ +void input_config_set_device_name_index(unsigned port, unsigned name_index); + +/** + * Sets the device type of the specified port + * + * @param port + * @param id The device type (RETRO_DEVICE_JOYPAD, RETRO_DEVICE_MOUSE, etc) + */ +void input_config_set_device(unsigned port, unsigned id); + +/** + * Registers a pad_connection_listener_interface with a function pointer that + * is called when a joypad is connected. Only used by the wiiu_joypad driver. + * + * @param listener a struct that implements pad_connection_listener_interface + */ +void set_connection_listener(pad_connection_listener_t *listener); + +/* Clear input_device_info */ +void input_config_clear_device_name(unsigned port); +void input_config_clear_device_display_name(unsigned port); +void input_config_clear_device_config_path(unsigned port); +void input_config_clear_device_config_name(unsigned port); +void input_config_clear_device_joypad_driver(unsigned port); + +unsigned input_config_get_device_count(void); + +unsigned *input_config_get_device_ptr(unsigned port); + +unsigned input_config_get_device(unsigned port); + +/* Get input_device_info */ +const char *input_config_get_device_name(unsigned port); +const char *input_config_get_device_display_name(unsigned port); +const char *input_config_get_device_config_path(unsigned port); +const char *input_config_get_device_config_name(unsigned port); +const char *input_config_get_device_joypad_driver(unsigned port); + +/** + * Retrieves the vendor id (vid) of a connected controller + * + * @param port + * + * @return the vendor id VID of the device + */ +uint16_t input_config_get_device_vid(unsigned port); + +/** + * Retrieves the pad id (pad) of a connected controller + * + * @param port + * + * @return the port id PID of the device + */ +uint16_t input_config_get_device_pid(unsigned port); + +/** + * Returns the value of the autoconfigured flag for the specified device + * + * @param port + * + * @return the autoconfigured flag + */ +bool input_config_get_device_autoconfigured(unsigned port); + +/** + * Get the name index number for the device in this port + * + * @param port + * + * @return the name index for this device + */ +unsigned input_config_get_device_name_index(unsigned port); + + +/*****************************************************************************/ + +/** + * Retrieve the device name char pointer. + * + * @deprecated input_config_get_device_name_ptr is required by linuxraw_joypad + * and parport_joypad. These drivers should be refactored such that this + * low-level access is not required. + * + * @param port + * + * @return a pointer to the device name on the specified port + */ +char *input_config_get_device_name_ptr(unsigned port); + +/** + * Get the size of the device name. + * + * @deprecated input_config_get_device_name_size is required by linuxraw_joypad + * and parport_joypad. These drivers should be refactored such that this + * low-level access is not required. + * + * @param port + * + * @return the size of the device name on the specified port + */ +size_t input_config_get_device_name_size(unsigned port); + +/*****************************************************************************/ + +/** + * Save the current keybinds on a port to the config file. + * + * @param conf pointer to config file object + * @param user user number (ie port - TODO: change to port nomenclature) + */ +void input_config_save_keybinds_user(void *data, unsigned user); + +const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id); + +/** + * Save a key binding to the config file. + * + * @param conf pointer to config file object + * @param prefix prefix name of keybind + * @param base base name of keybind + * @param bind pointer to key binding object + * @param kb save keyboard binds + */ +void input_config_save_keybind(void *data, const char *prefix, + const char *base, const struct retro_keybind *bind, + bool save_empty); + +void input_config_reset_autoconfig_binds(unsigned port); +void input_config_reset(void); + #if defined(ANDROID) #define DEFAULT_MAX_PADS 8 #define ANDROID_KEYBOARD_PORT DEFAULT_MAX_PADS @@ -325,7 +688,7 @@ struct rarch_joypad_driver #define DEFAULT_MAX_PADS 16 #else #define DEFAULT_MAX_PADS 5 -#endif +#endif /* WIIU_HID */ #elif defined(DJGPP) #define DEFAULT_MAX_PADS 1 #define DOS_KEYBOARD_PORT DEFAULT_MAX_PADS @@ -355,272 +718,7 @@ struct rarch_joypad_driver #define DEFAULT_MAX_PADS 2 #else #define DEFAULT_MAX_PADS 16 -#endif - -/** - * config_get_input_driver_options: - * - * Get an enumerated list of all input driver names, separated by '|'. - * - * Returns: string listing of all input driver names, separated by '|'. - **/ -const char* config_get_input_driver_options(void); - -/** - * input_driver_set_rumble_state: - * @port : User number. - * @effect : Rumble effect. - * @strength : Strength of rumble effect. - * - * Sets the rumble state. - * Used by RETRO_ENVIRONMENT_GET_RUMBLE_INTERFACE. - **/ -bool input_driver_set_rumble_state(unsigned port, - enum retro_rumble_effect effect, uint16_t strength); - -/** - * input_sensor_set_state: - * @port : User number. - * @effect : Sensor action. - * @rate : Sensor rate update. - * - * Sets the sensor state. - * Used by RETRO_ENVIRONMENT_GET_SENSOR_INTERFACE. - **/ -bool input_sensor_set_state(unsigned port, - enum retro_sensor_action action, unsigned rate); - -float input_sensor_get_input(unsigned port, unsigned id); - -void *input_driver_get_data(void); - -void input_driver_set_nonblock_state(void); - -void input_driver_unset_nonblock_state(void); - -float *input_driver_get_float(enum input_action action); - -unsigned *input_driver_get_uint(enum input_action action); - -/** - * config_get_joypad_driver_options: - * - * Get an enumerated list of all joypad driver names, separated by '|'. - * - * Returns: string listing of all joypad driver names, separated by '|'. - **/ -const char* config_get_joypad_driver_options(void); - -/** - * input_joypad_init_driver: - * @ident : identifier of driver to initialize. - * - * Initialize a joypad driver of name @ident. - * - * If ident points to NULL or a zero-length string, - * equivalent to calling input_joypad_init_first(). - * - * Returns: joypad driver if found, otherwise NULL. - **/ -const input_device_driver_t *input_joypad_init_driver( - const char *ident, void *data); - -/** - * input_conv_analog_id_to_bind_id: - * @idx : Analog key index. - * E.g.: - * - RETRO_DEVICE_INDEX_ANALOG_LEFT - * - RETRO_DEVICE_INDEX_ANALOG_RIGHT - * @ident : Analog key identifier. - * E.g.: - * - RETRO_DEVICE_ID_ANALOG_X - * - RETRO_DEVICE_ID_ANALOG_Y - * @ident_minus : Bind ID minus, will be set by function. - * @ident_plus : Bind ID plus, will be set by function. - * - * Takes as input analog key identifiers and converts - * them to corresponding bind IDs @ident_minus and @ident_plus. - **/ -#define input_conv_analog_id_to_bind_id(idx, ident, ident_minus, ident_plus) \ - switch ((idx << 1) | ident) \ - { \ - case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_X: \ - ident_minus = RARCH_ANALOG_LEFT_X_MINUS; \ - ident_plus = RARCH_ANALOG_LEFT_X_PLUS; \ - break; \ - case (RETRO_DEVICE_INDEX_ANALOG_LEFT << 1) | RETRO_DEVICE_ID_ANALOG_Y: \ - ident_minus = RARCH_ANALOG_LEFT_Y_MINUS; \ - ident_plus = RARCH_ANALOG_LEFT_Y_PLUS; \ - break; \ - case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_X: \ - ident_minus = RARCH_ANALOG_RIGHT_X_MINUS; \ - ident_plus = RARCH_ANALOG_RIGHT_X_PLUS; \ - break; \ - case (RETRO_DEVICE_INDEX_ANALOG_RIGHT << 1) | RETRO_DEVICE_ID_ANALOG_Y: \ - ident_minus = RARCH_ANALOG_RIGHT_Y_MINUS; \ - ident_plus = RARCH_ANALOG_RIGHT_Y_PLUS; \ - break; \ - } - -/** - * input_pad_connect: - * @port : Joystick number. - * @driver : handle for joypad driver handling joystick's input - * - * Registers a newly connected pad with RetroArch. - **/ -void input_pad_connect(unsigned port, input_device_driver_t *driver); - -#ifdef HAVE_HID -#include "include/hid_driver.h" - -/** - * config_get_hid_driver_options: - * - * Get an enumerated list of all HID driver names, separated by '|'. - * - * Returns: string listing of all HID driver names, separated by '|'. - **/ -const char* config_get_hid_driver_options(void); - -/** - * input_hid_init_first: - * - * Finds first suitable HID driver and initializes. - * - * Returns: HID driver if found, otherwise NULL. - **/ -const hid_driver_t *input_hid_init_first(void); - -const void *hid_driver_get_data(void); -void hid_driver_reset_data(void); -#endif - -/** Line complete callback. - * Calls back after return is pressed with the completed line. - * Line can be NULL. - **/ -typedef void (*input_keyboard_line_complete_t)(void *userdata, - const char *line); - -typedef bool (*input_keyboard_press_t)(void *userdata, unsigned code); - -struct input_keyboard_ctx_wait -{ - void *userdata; - input_keyboard_press_t cb; -}; - -/** - * input_keyboard_event: - * @down : Keycode was pressed down? - * @code : Keycode. - * @character : Character inputted. - * @mod : TODO/FIXME: ??? - * - * Keyboard event utils. Called by drivers when keyboard events are fired. - * This interfaces with the global driver struct and libretro callbacks. - **/ -void input_keyboard_event(bool down, unsigned code, uint32_t character, - uint16_t mod, unsigned device); - -const char *input_config_bind_map_get_base(unsigned i); - -unsigned input_config_bind_map_get_meta(unsigned i); - -const char *input_config_bind_map_get_desc(unsigned i); - -uint8_t input_config_bind_map_get_retro_key(unsigned i); - -/* auto_bind can be NULL. */ -void input_config_get_bind_string(char *buf, - const struct retro_keybind *bind, - const struct retro_keybind *auto_bind, size_t size); - -/** - * input_config_translate_str_to_rk: - * @str : String to translate to key ID. - * - * Translates string representation to key identifier. - * - * Returns: key identifier. - **/ -enum retro_key input_config_translate_str_to_rk(const char *str); - -/** - * input_config_translate_str_to_bind_id: - * @str : String to translate to bind ID. - * - * Translate string representation to bind ID. - * - * Returns: Bind ID value on success, otherwise - * RARCH_BIND_LIST_END on not found. - **/ -unsigned input_config_translate_str_to_bind_id(const char *str); - -void config_read_keybinds_conf(void *data); - -/* Note: 'data' is an object of type config_file_t - * > We assume it was done like this to avoid including - * config_file.h... */ -void input_config_set_autoconfig_binds(unsigned port, void *data); - -/* Set input_device_info */ -void input_config_set_device_name(unsigned port, const char *name); -void input_config_set_device_display_name(unsigned port, const char *name); -void input_config_set_device_config_path(unsigned port, const char *path); -void input_config_set_device_config_name(unsigned port, const char *name); -void input_config_set_device_joypad_driver(unsigned port, const char *driver); -void input_config_set_device_vid(unsigned port, uint16_t vid); -void input_config_set_device_pid(unsigned port, uint16_t pid); -void input_config_set_device_autoconfigured(unsigned port, bool autoconfigured); -void input_config_set_device_name_index(unsigned port, unsigned name_index); - -/* Clear input_device_info */ -void input_config_clear_device_name(unsigned port); -void input_config_clear_device_display_name(unsigned port); -void input_config_clear_device_config_path(unsigned port); -void input_config_clear_device_config_name(unsigned port); -void input_config_clear_device_joypad_driver(unsigned port); - -unsigned input_config_get_device_count(void); - -unsigned *input_config_get_device_ptr(unsigned port); - -unsigned input_config_get_device(unsigned port); - -void input_config_set_device(unsigned port, unsigned id); - -/* Get input_device_info */ -const char *input_config_get_device_name(unsigned port); -const char *input_config_get_device_display_name(unsigned port); -const char *input_config_get_device_config_path(unsigned port); -const char *input_config_get_device_config_name(unsigned port); -const char *input_config_get_device_joypad_driver(unsigned port); -uint16_t input_config_get_device_vid(unsigned port); -uint16_t input_config_get_device_pid(unsigned port); -bool input_config_get_device_autoconfigured(unsigned port); -unsigned input_config_get_device_name_index(unsigned port); - -/* TODO/FIXME: This is required by linuxraw_joypad.c - * and parport_joypad.c. These input drivers should - * be refactored such that this dubious low-level - * access is not required */ -char *input_config_get_device_name_ptr(unsigned port); -size_t input_config_get_device_name_size(unsigned port); - -const struct retro_keybind *input_config_get_bind_auto(unsigned port, unsigned id); - -void input_config_save_keybinds_user(void *data, unsigned user); - -void input_config_save_keybind(void *data, const char *prefix, - const char *base, const struct retro_keybind *bind, - bool save_empty); - -void input_config_reset_autoconfig_binds(unsigned port); -void input_config_reset(void); - -void set_connection_listener(pad_connection_listener_t *listener); +#endif /* defined(ANDROID) */ extern input_device_driver_t dinput_joypad; extern input_device_driver_t linuxraw_joypad; @@ -675,7 +773,7 @@ extern hid_driver_t iohidmanager_hid; extern hid_driver_t btstack_hid; extern hid_driver_t libusb_hid; extern hid_driver_t wiiusb_hid; -#endif +#endif /* HAVE_HID */ typedef struct menu_input_ctx_line { @@ -704,4 +802,4 @@ void menu_input_dialog_end(void); RETRO_END_DECLS -#endif +#endif /* __INPUT_DRIVER__H */ diff --git a/input/input_remapping.h b/input/input_remapping.h index 2925a66ac5..ab06073037 100644 --- a/input/input_remapping.h +++ b/input/input_remapping.h @@ -26,56 +26,162 @@ RETRO_BEGIN_DECLS /** - * input_remapping_load_file: - * @data : Path to config file. - * * Loads a remap file from disk to memory. + * + * @param data Path to config file. * - * Returns: true (1) if successful, otherwise false (0). + * @return true (1) if successful, otherwise false (0). **/ bool input_remapping_load_file(void *data, const char *path); /** - * input_remapping_save_file: - * @path : Path to remapping file (relative path). - * * Saves remapping values to file. * - * Returns: true (1) if successful, otherwise false (0). + * @param path Relative path to remapping file. + * + * @return true (1) if successful, otherwise false (0). **/ bool input_remapping_save_file(const char *path); -bool input_remapping_remove_file(const char *path, - const char *dir_input_remapping); +bool input_remapping_remove_file(const char *path, + const char *dir_input_remapping); -/* Caches any global configuration settings that - * should not be overwritten by input remap - * changes made while content is running. - * Must be called on each core init. */ +/** + * Caches any global configuration settings that should not be overwritten by + * input remap changes made while content is running. Must be called on each + * core init. + */ void input_remapping_cache_global_config(void); -/* Sets flags to enable the restoration of - * global configuration settings from the - * internal cache. Should be called independently - * from 'input_remapping_cache_global_config()'. + +/** + * Sets flags to enable the restoration of global configuration settings from + * the internal cache. Should be called independently from + * `input_remapping_cache_global_config()`. * Must be called: - * - Whenever content is loaded - * - Whenever a remap file is loaded */ + * - Whenever content is loaded + * - Whenever a remap file is loaded + */ void input_remapping_enable_global_config_restore(void); -/* Restores any cached global configuration settings - * *if* 'input_remapping_enable_global_config_restore()' - * has been called. - * Must be called on core deint. - * If 'clear_cache' is true, function becomes a NOOP - * until the next time input_remapping_cache_global_config() - * and input_remapping_enable_global_config_restore() - * are called. */ + +/** + * Restores any global configuration settings that were cached on the last core + * init if `input_remapping_enable_global_config_restore()` has been called. + * Must be called on core deinitialization. + * + * @param clear_cache If true, function becomes a NOOP until the next time + * `input_remapping_cache_global_config()` and + * `input_remapping_enable_global_config_restore()` are + * called. + */ void input_remapping_restore_global_config(bool clear_cache); +/** + * Must be called whenever `settings->uints.input_remap_ports` is modified. + */ void input_remapping_update_port_map(void); +/** + * Frees global->name.remapfile and sets these runloop_state flags to false: + * remaps_core_active, remaps_content_dir_active, and remaps_game_active. + */ void input_remapping_deinit(void); + +/** + * Used to set the default mapping values within the `settings` struct + * @param clear_cache This value is passed to + * `input_remapping_restore_global_config()`. Please see + * the documentation for that function for details. + */ void input_remapping_set_defaults(bool clear_cache); +/** + * Checks `input_config_bind_map` for the requested `input_bind_map`, and if + * the bind has been registered, returns its base. + * + * @param index + * + * @return the contents of the meta field, or NULL if there is no matching bind + */ +const char *input_config_bind_map_get_base(unsigned bind_index); + +/** + * Checks `input_config_bind_map` for the requested `input_bind_map`, and if + * the bind has been registered, returns the value of its meta binds field. + * + * @param index + * + * @return the contents of the meta field, or 0 if there is no matching bind + */ +unsigned input_config_bind_map_get_meta(unsigned bind_index); + +/** + * Checks `input_config_bind_map` for the requested `input_bind_map`, and if + * the bind has been registered, returns a pointer to its description field. + * + * @param index + * + * @return the contents of the description field, or NULL if there is no + * matching bind + */ +const char *input_config_bind_map_get_desc(unsigned index); + +/** + * Checks `input_config_bind_map` for the requested `input_bind_map`, and if + * the bind has been registered, returns the value of its retro_key field. + * + * @param index + * + * @return the value of the retro_key field, or 0 if there is no matching bind + */ +uint8_t input_config_bind_map_get_retro_key(unsigned index); + +/** + * Converts a retro_keybind to a human-readable string, optionally allowing a + * fallback auto_bind to be used as the source for the string. + * + * @param buf A string which will be overwritten with the returned value + * @param bind A binding to convert to a string + * @param auto_bind A default binding which will be used after `bind`. Can be NULL. + * @param size The maximum length that will be written to `buf` + */ +void input_config_get_bind_string(char *buf, const struct retro_keybind *bind, + const struct retro_keybind *auto_bind, size_t size); + +/** + * Parses the string representation of a retro_key struct + * + * @param str String to parse. + * + * @return Key identifier. + **/ +enum retro_key input_config_translate_str_to_rk(const char *str); + +/** + * Searches for a string among the "base" fields of the list of binds. + * + * @param str String to search for among the binds + * + * @return Bind index value on success or RARCH_BIND_LIST_END if not found. + **/ +unsigned input_config_translate_str_to_bind_id(const char *str); + +/** + * Parse the bind data of an object of config_file_t. + * + * @param data An object of type config_file_t. We assume it is passed as a + * void pointer like this to avoid including config_file.h. + **/ +void config_read_keybinds_conf(void *data); + +/** + * Apply autoconfig binds to the indicated control port. + * + * @param port + * @param data An object of type config_file_t. We assume it is passed as a + * void pointer like this to avoid including config_file.h. + */ +void input_config_set_autoconfig_binds(unsigned port, void *data); + RETRO_END_DECLS #endif diff --git a/intl/msg_hash_de.h b/intl/msg_hash_de.h index 7972b9f828..5ab496b162 100644 --- a/intl/msg_hash_de.h +++ b/intl/msg_hash_de.h @@ -922,18 +922,10 @@ MSG_HASH( MENU_ENUM_SUBLABEL_DRIVER_SETTINGS, "Die von diesem System verwendeten Treiber ändern." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS, - "Videotreiber" - ) MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SETTINGS, "Videoausgabe-Einstellungen ändern." ) -MSG_HASH( - MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS, - "Audiotreiber" - ) MSG_HASH( MENU_ENUM_SUBLABEL_AUDIO_SETTINGS, "Audioausgabe-Einstellungen ändern." @@ -1535,6 +1527,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Das Bild in ganzzahligen Schritten skalieren. Die Basisgröße hängt von der vom System gemeldeten Geometrie und dem Seitenverhältnis ab. Wenn \"Seitenverhältnis erzwingen\" nicht gewählt ist, werden Höhe u. Breite unabhängig skaliert." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Aufgerundete ganzzahlige Skalierung" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Bei ganzzahliger Skalierung den Skalierungsfaktor aufrunden, statt ihn abzurunden." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Bildseitenverhältnis" @@ -7715,7 +7715,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_LOCK_INTEGER, - "Pixelgenaue Bildskalierung" + "Ganzzahlige Skalierung" ) MSG_HASH( MENU_ENUM_LABEL_VALUE_RGUI_ASPECT_RATIO_LOCK_FILL_SCREEN, diff --git a/intl/msg_hash_es.h b/intl/msg_hash_es.h index 191347af56..719732afed 100644 --- a/intl/msg_hash_es.h +++ b/intl/msg_hash_es.h @@ -1587,6 +1587,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Limita el escalado de vídeo a múltiplos enteros. El tamaño base dependerá de la geometría indicada por el sistema y la relación de aspecto. Si la opción «Forzar relación de aspecto» está desactivada, los valores X e Y serán escalados individualmente." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Sobreescalar imagen al usar números enteros" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Hace que el escalado por números enteros redondee siempre a un valor superior en vez de a uno inferior." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Relación de aspecto" @@ -4035,7 +4043,7 @@ MSG_HASH( ) MSG_HASH( MENU_ENUM_LABEL_VALUE_MENU_SCROLL_DELAY, - "Retraso al desplazar el menú" + "Retraso para desplazar el menú" ) MSG_HASH( MENU_ENUM_SUBLABEL_MENU_SCROLL_DELAY, diff --git a/intl/msg_hash_fr.h b/intl/msg_hash_fr.h index 92d7fe1cc0..96a8327838 100644 --- a/intl/msg_hash_fr.h +++ b/intl/msg_hash_fr.h @@ -1579,6 +1579,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Mettre la vidéo à l'échelle sur un nombre entier uniquement. La taille de base dépend de la géométrie et du rapport d'aspect détectés par le système. Si 'Forcer le rapport d'aspect' est désactivé, X/Y seront mis à l'échelle à l'entier indépendamment." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Échelle à l'entier surdimensionnée" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Force la mise à l'échelle sur l'entier à arrondir au prochain entier supérieur plutôt qu'inférieur." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Rapport d'aspect" diff --git a/intl/msg_hash_it.h b/intl/msg_hash_it.h index 9b989081dc..362f3b95f8 100644 --- a/intl/msg_hash_it.h +++ b/intl/msg_hash_it.h @@ -1567,6 +1567,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Scala video solo con passaggi interi. La dimensione di base dipende dalla geometria e dal rapporto di aspetto riportati dal sistema. Se 'Force Aspect Ratio' non è impostato, X/Y sarà scalato in modo indipendente." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Overscale A Scala Intera" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Forza il ridimensionamento degli interi per arrotondare al prossimo numero intero maggiore invece di arrotondare." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Rapporto d'aspetto" diff --git a/intl/msg_hash_ko.h b/intl/msg_hash_ko.h index 795b11a898..afffd7a9da 100644 --- a/intl/msg_hash_ko.h +++ b/intl/msg_hash_ko.h @@ -1607,6 +1607,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "비디오의 크기를 정수 단위로만 조정합니다. 기본 크기는 각 시스템이 보고한 크기와 종횡비에 따라 결정되며 '강제 화면비'를 설정하지 않았을 경우 X/Y 크기를 각각 정수 단위로 조절합니다." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "정수 단위 오버스케일링" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "화면 크기를 조정할 정수 단위 배율을 버림 대신 올림으로 계산합니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "화면비" @@ -2640,6 +2648,10 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_ADC_TYPE, "아날로그로 디지털 입력" ) +MSG_HASH( + MENU_ENUM_SUBLABEL_INPUT_ADC_TYPE, + "지정한 아날로그 스틱을 방향 패드 대신으로 사용합니다. 코어가 아날로그 입력을 지원하는 경우, 방향 패드 매핑은 (강제) 옵션을 선택하지 않은 한 비활성화됩니다. 방향 패드 매핑을 강제하면 코어는 지정한 스틱의 아날로그 입력을 받을 수 없게 됩니다." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_DEVICE_INDEX, "장치 인덱스" @@ -7615,6 +7627,14 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG, "우 아날로그" ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_LEFT_ANALOG_FORCED, + "좌 아날로그 (강제)" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG_FORCED, + "우 아날로그 (강제)" + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_INPUT_KEY, "(키: %s)" diff --git a/intl/msg_hash_lbl.h b/intl/msg_hash_lbl.h index aebd44e3ef..fe048346b5 100644 --- a/intl/msg_hash_lbl.h +++ b/intl/msg_hash_lbl.h @@ -3181,6 +3181,12 @@ MSG_HASH( "video_dingux_refresh_rate" ) #endif +#if defined(RS90) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + "video_dingux_rs90_softfilter_type" + ) +#endif #endif MSG_HASH( MENU_ENUM_LABEL_VIDEO_BLACK_FRAME_INSERTION, @@ -3314,6 +3320,10 @@ MSG_HASH( MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER, "video_scale_integer" ) +MSG_HASH( + MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "video_scale_integer_overscale" + ) MSG_HASH( MENU_ENUM_LABEL_VIDEO_SETTINGS, "video_settings" diff --git a/intl/msg_hash_pt_br.h b/intl/msg_hash_pt_br.h index 6d0c4bdee6..37ad4ad859 100644 --- a/intl/msg_hash_pt_br.h +++ b/intl/msg_hash_pt_br.h @@ -1575,6 +1575,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Apenas redimensione o vídeo com valores inteiros. O tamanho principal depende da geometria informada pelo sistema e da proporção da tela. Caso a opção 'Forçar proporção' não esteja definida, X / Y serão dimensionados independentemente com valores inteiros." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Dimensionar imagem em números inteiros" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Faz com que o dimensionamento inteiro seja sempre arredondado para um valor mais alto em vez de um valor mais baixo." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Proporção de tela" diff --git a/intl/msg_hash_ru.h b/intl/msg_hash_ru.h index 717a3f1347..96bd009357 100644 --- a/intl/msg_hash_ru.h +++ b/intl/msg_hash_ru.h @@ -1599,6 +1599,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Масштабировать изображение с целочисленным интервалом. Базовый размер зависит от геометрии и соотношения сторон системы. Если не включена 'Принудительная установка' для соотношения сторон, значения X/Y будут меняться независимо друг от друга." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Повышать целочисленное масштабирование" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "При целочисленном масштабировании делать округление в сторону ближайшего большего целого числа." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Соотношение сторон" diff --git a/intl/msg_hash_tr.h b/intl/msg_hash_tr.h index d6cbddc89c..16f39db720 100644 --- a/intl/msg_hash_tr.h +++ b/intl/msg_hash_tr.h @@ -1579,6 +1579,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Videoyu yalnızca tamsayı adımlarla ölçeklendirir. Temel boyut, sistem tarafından bildirilen geometriye ve en/boy oranına bağlıdır. 'En/Boy Oranını Zorla' ayarlanmazsa, X/Y birbirlerinden bağımsız, tamsayı katlarıyla ölçeklendirilirler." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Tamsayı Ölçeği Aşırı Ölçek" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Aşağı yuvarlamak yerine bir sonraki daha büyük tam sayıya yuvarlamak için tamsayı ölçeklendirmeyi zorlayın." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "En Boy Oranı" diff --git a/intl/msg_hash_uk.h b/intl/msg_hash_uk.h index 5c7775c891..4ef6008c84 100644 --- a/intl/msg_hash_uk.h +++ b/intl/msg_hash_uk.h @@ -1603,6 +1603,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Масштабуйте відео лише цілими кроками. Базовий розмір залежить від геометрії та співвідношення сторін, про які повідомляє система. Якщо не встановлено \"Примусове співвідношення сторін\", X / Y буде цілочисельним масштабом незалежно." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Масштаб Цілочисельной Шкали" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Примусово масштабувати ціле число для округлення до наступного більшого цілого числа замість округлення вниз." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Співвідношення сторін" diff --git a/intl/msg_hash_us.c b/intl/msg_hash_us.c index 39418993bf..9eda1c4ad6 100644 --- a/intl/msg_hash_us.c +++ b/intl/msg_hash_us.c @@ -1365,9 +1365,14 @@ int msg_hash_get_help_us_enum(enum msg_hash_enums msg, char *s, size_t len) "The base size depends on system-reported \n" "geometry and aspect ratio.\n" " \n" - "If Force Aspect is not set, X/Y will be \n" + "If 'Force Aspect Ratio' is not set, X/Y will be \n" "integer scaled independently."); break; + case MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_OVERSCALE: + snprintf(s, len, + "Force integer scaling to round up \n" + " to the next larger integer instead of rounding down."); + break; case MENU_ENUM_LABEL_AUDIO_VOLUME: snprintf(s, len, "Audio volume, expressed in dB.\n" diff --git a/intl/msg_hash_us.h b/intl/msg_hash_us.h index 43e5b65d3a..6cd7527e9c 100644 --- a/intl/msg_hash_us.h +++ b/intl/msg_hash_us.h @@ -1373,6 +1373,24 @@ MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_IPU_FILTER_NEAREST, "Nearest Neighbor" ) +#if defined(RS90) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + "Image Interpolation" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + "Specify image interpolation method when 'Integer Scale' is disabled. 'Nearest Neighbor' has the least performance impact." + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT, + "Nearest Neighbor" + ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ, + "Semi-Linear" + ) +#endif #endif MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DELAY, @@ -1631,6 +1649,14 @@ MSG_HASH( MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER, "Scale video in integer steps only. The base size depends on system-reported geometry and aspect ratio. If 'Force Aspect Ratio' is not set, X/Y will be integer scaled independently." ) +MSG_HASH( + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + "Integer Scale Overscale" + ) +MSG_HASH( + MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + "Force integer scaling to round up to the next larger integer instead of rounding down." + ) MSG_HASH( MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX, "Aspect Ratio" @@ -10528,11 +10554,11 @@ MSG_HASH( ) MSG_HASH( MSG_PUBLIC_ADDRESS, - "Port Mapping Successful" + "Netplay Port Mapping Successful" ) MSG_HASH( MSG_UPNP_FAILED, - "Port Mapping Failed" + "Netplay UPNP Port Mapping Failed" ) MSG_HASH( MSG_NO_ARGUMENTS_SUPPLIED_AND_NO_MENU_BUILTIN, @@ -12026,6 +12052,10 @@ MSG_HASH( MSG_UNSUPPORTED_VIDEO_MODE, "Unsupported video mode" ) +MSG_HASH( + MSG_CORE_INFO_CACHE_UNSUPPORTED, + "Cannot write to core info directory - core info cache will be disabled" + ) /* Lakka */ diff --git a/libretro-common/file/file_path.c b/libretro-common/file/file_path.c index 3993bbaa34..aca7cfbd18 100644 --- a/libretro-common/file/file_path.c +++ b/libretro-common/file/file_path.c @@ -650,16 +650,31 @@ bool path_is_absolute(const char *path) char *path_resolve_realpath(char *buf, size_t size, bool resolve_symlinks) { #if !defined(RARCH_CONSOLE) && defined(RARCH_INTERNAL) - char tmp[PATH_MAX_LENGTH]; #ifdef _WIN32 - strlcpy(tmp, buf, sizeof(tmp)); - if (!_fullpath(buf, tmp, size)) + char *ret = NULL; + wchar_t abs_path[PATH_MAX_LENGTH]; + wchar_t *rel_path = utf8_to_utf16_string_alloc(buf); + + if (rel_path) { - strlcpy(buf, tmp, size); - return NULL; + if (_wfullpath(abs_path, rel_path, PATH_MAX_LENGTH)) + { + char *tmp = utf16_to_utf8_string_alloc(abs_path); + + if (tmp) + { + strlcpy(buf, tmp, size); + free(tmp); + ret = buf; + } + } + + free(rel_path); } - return buf; + + return ret; #else + char tmp[PATH_MAX_LENGTH]; size_t t; char *p; const char *next; diff --git a/libretro-common/file/nbio/nbio_stdio.c b/libretro-common/file/nbio/nbio_stdio.c index 328e32aedb..e05968b6fa 100644 --- a/libretro-common/file/nbio/nbio_stdio.c +++ b/libretro-common/file/nbio/nbio_stdio.c @@ -22,6 +22,9 @@ #include #include +#if defined(WIIU) +#include +#endif #include #include @@ -130,8 +133,14 @@ static void *nbio_stdio_open(const char * filename, unsigned mode) handle->mode = mode; +#if defined(WIIU) + /* hit the aligned-buffer fast path on Wii U */ + if (len) + buf = memalign(0x40, (size_t)len); +#else if (len) buf = malloc((size_t)len); +#endif if (len && !buf) goto error; diff --git a/libretro-common/include/defines/ps3_defines.h b/libretro-common/include/defines/ps3_defines.h index 8114628327..6724691e43 100644 --- a/libretro-common/include/defines/ps3_defines.h +++ b/libretro-common/include/defines/ps3_defines.h @@ -660,6 +660,9 @@ extern int audioAddData(uint32_t portNum, float *data, #define CELL_SYSMODULE_SYSUTIL_NP SYSMODULE_SYSUTIL_NP #define CELL_SYSMODULE_JPGDEC SYSMODULE_JPGDEC #define CELL_SYSMODULE_PNGDEC SYSMODULE_PNGDEC +#define CELL_SYSMODULE_FONT SYSMODULE_FONT +#define CELL_SYSMODULE_FREETYPE SYSMODULE_FREETYPE +#define CELL_SYSMODULE_FONTFT SYSMODULE_FONTFT #define cellSysmoduleLoadModule sysModuleLoad #define cellSysmoduleUnloadModule sysModuleUnload diff --git a/libretro-common/include/net/net_compat.h b/libretro-common/include/net/net_compat.h index 7f9f452e64..7387596eb8 100644 --- a/libretro-common/include/net/net_compat.h +++ b/libretro-common/include/net/net_compat.h @@ -158,6 +158,11 @@ static INLINE bool isagain(int bytes) #endif } +#ifdef WIIU +#define WIIU_RCVBUF (128 * 2 * 1024) +#define WIIU_SNDBUF (128 * 2 * 1024) +#endif + #ifdef _XBOX #define socklen_t int diff --git a/libretro-common/include/net/net_natt.h b/libretro-common/include/net/net_natt.h index 74ca3164ac..8634dc3e73 100644 --- a/libretro-common/include/net/net_natt.h +++ b/libretro-common/include/net/net_natt.h @@ -62,7 +62,8 @@ struct natt_status /** * Initialize global NAT traversal structures (must be called once to use other * functions) */ -void natt_init(void); +void natt_init(struct natt_status *status, + uint16_t port, enum socket_protocol proto); /** Initialize a NAT traversal status object */ bool natt_new(struct natt_status *status); diff --git a/libretro-common/net/net_compat.c b/libretro-common/net/net_compat.c index aacbb4dd3e..8b9e183e46 100644 --- a/libretro-common/net/net_compat.c +++ b/libretro-common/net/net_compat.c @@ -264,6 +264,25 @@ void freeaddrinfo_retro(struct addrinfo *res) #endif } +#if defined(WIIU) +#include + +static OSThread wiiu_net_cmpt_thread; +static void wiiu_net_cmpt_thread_cleanup(OSThread *thread, void *stack) { + free(stack); +} +static int wiiu_net_cmpt_thread_entry(int argc, const char** argv) { + const int buf_size = WIIU_RCVBUF + WIIU_SNDBUF; + void* buf = memalign(128, buf_size); + if (!buf) return -1; + + somemopt(1, buf, buf_size, 0); + + free(buf); + return 0; +} +#endif + /** * network_init: * @@ -332,6 +351,18 @@ bool network_init(void) return false; #elif defined(WIIU) socket_lib_init(); + + const int stack_size = 4096; + void* stack = malloc(stack_size); + if (stack && OSCreateThread(&wiiu_net_cmpt_thread, + wiiu_net_cmpt_thread_entry, 0, NULL, stack+stack_size, stack_size, + 3, OS_THREAD_ATTRIB_AFFINITY_ANY)) { + + OSSetThreadName(&wiiu_net_cmpt_thread, "Network compat thread"); + OSSetThreadDeallocator(&wiiu_net_cmpt_thread, + wiiu_net_cmpt_thread_cleanup); + OSResumeThread(&wiiu_net_cmpt_thread); + } #elif defined(_3DS) _net_compat_net_memory = (u32*)memalign(SOC_ALIGN, SOC_BUFFERSIZE); if (!_net_compat_net_memory) diff --git a/libretro-common/net/net_natt.c b/libretro-common/net/net_natt.c index c8ce68761f..a345af98dc 100644 --- a/libretro-common/net/net_natt.c +++ b/libretro-common/net/net_natt.c @@ -47,7 +47,13 @@ static struct UPNPUrls urls; static struct IGDdatas data; #endif -void natt_init(void) +/* + natt_open_port_any(ntsd->nat_traversal_state, + ntsd->port, SOCKET_PROTOCOL_TCP); +*/ + +void natt_init(struct natt_status *status, + uint16_t port, enum socket_protocol proto) { #ifndef HAVE_SOCKET_LEGACY #if HAVE_MINIUPNPC @@ -56,8 +62,6 @@ void natt_init(void) char * descXML; int descXMLsize = 0; int upnperror = 0; - memset(&urls, 0, sizeof(struct UPNPUrls)); - memset(&data, 0, sizeof(struct IGDdatas)); devlist = upnpDiscover(2000, NULL, NULL, 0, 0, 2, &upnperror); if (devlist) { @@ -65,22 +69,27 @@ void natt_init(void) while (dev) { if (strstr (dev->st, "InternetGatewayDevice")) - break; + { + memset(&urls, 0, sizeof(struct UPNPUrls)); + memset(&data, 0, sizeof(struct IGDdatas)); + descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0, NULL); + if (descXML) + { + parserootdesc(descXML, descXMLsize, &data); + free (descXML); + descXML = 0; + + GetUPNPUrls (&urls, &data, dev->descURL, 0); + } + if(natt_open_port_any(status, port, proto)) + goto end; + + } dev = dev->pNext; } - if (!dev) - dev = devlist; - - descXML = (char *) miniwget(dev->descURL, &descXMLsize, 0, NULL); - if (descXML) - { - parserootdesc(descXML, descXMLsize, &data); - free (descXML); - descXML = 0; - GetUPNPUrls (&urls, &data, dev->descURL, 0); - } - freeUPNPDevlist(devlist); } +end: + freeUPNPDevlist(devlist); #endif #endif } diff --git a/libretro-common/net/net_socket.c b/libretro-common/net/net_socket.c index f33d284075..04b01ade4c 100644 --- a/libretro-common/net/net_socket.c +++ b/libretro-common/net/net_socket.c @@ -256,6 +256,20 @@ int socket_connect(int fd, void *data, bool timeout_enable) setsockopt(fd, SOL_SOCKET, SO_SNDTIMEO, (char*)&timeout, sizeof timeout); } +#endif +#if defined(WIIU) + int op = 1; + setsockopt(fd, SOL_SOCKET, SO_WINSCALE, &op, sizeof(op)); + if (addr->ai_socktype == SOCK_STREAM) { + setsockopt(fd, SOL_SOCKET, SO_TCPSACK, &op, sizeof(op)); + + setsockopt(fd, SOL_SOCKET, 0x10000, &op, sizeof(op)); + int recvsz = WIIU_RCVBUF; + setsockopt(fd, SOL_SOCKET, SO_RCVBUF, &recvsz, sizeof(recvsz)); + int sendsz = WIIU_SNDBUF; + setsockopt(fd, SOL_SOCKET, SO_SNDBUF, &sendsz, sizeof(sendsz)); + } + #endif return connect(fd, addr->ai_addr, addr->ai_addrlen); diff --git a/libretro-common/rthreads/rthreads.c b/libretro-common/rthreads/rthreads.c index bb5b38b037..3942651532 100644 --- a/libretro-common/rthreads/rthreads.c +++ b/libretro-common/rthreads/rthreads.c @@ -872,7 +872,7 @@ bool scond_wait_timeout(scond_t *cond, slock_t *lock, int64_t timeout_us) int tickms = ps2_clock(); now.tv_sec = tickms/1000; now.tv_nsec = tickms * 1000; -#elif defined(__mips__) || defined(VITA) || defined(_3DS) +#elif !defined(DINGUX_BETA) && (defined(__mips__) || defined(VITA) || defined(_3DS)) struct timeval tm; gettimeofday(&tm, NULL); diff --git a/libretro-common/vfs/vfs_implementation.c b/libretro-common/vfs/vfs_implementation.c index 4ad9dbd200..dd7e466b5e 100644 --- a/libretro-common/vfs/vfs_implementation.c +++ b/libretro-common/vfs/vfs_implementation.c @@ -62,6 +62,9 @@ # include # include # endif +# if defined(WIIU) +# include +# endif #endif #include @@ -447,6 +450,14 @@ libretro_vfs_implementation_file *retro_vfs_file_open_impl( if (stream->fp) setvbuf(stream->fp, stream->buf, _IOFBF, 0x10000); } +#elif defined(WIIU) + if (stream->scheme != VFS_SCHEME_CDROM) + { + const int bufsize = 128*1024; + stream->buf = (char*)memalign(0x40, bufsize); + if (stream->fp) + setvbuf(stream->fp, stream->buf, _IOFBF, bufsize); + } #elif !defined(PSP) if (stream->scheme != VFS_SCHEME_CDROM) { diff --git a/menu/cbs/menu_cbs_scan.c b/menu/cbs/menu_cbs_scan.c index 68eb28bb10..6e155035cb 100644 --- a/menu/cbs/menu_cbs_scan.c +++ b/menu/cbs/menu_cbs_scan.c @@ -24,6 +24,7 @@ #include "../menu_driver.h" #include "../menu_cbs.h" #include "../menu_setting.h" +#include "../../input/input_remapping.h" #include "../../input/input_driver.h" diff --git a/menu/cbs/menu_cbs_sublabel.c b/menu/cbs/menu_cbs_sublabel.c index 6ed665bbbe..44dc396dcd 100644 --- a/menu/cbs/menu_cbs_sublabel.c +++ b/menu/cbs/menu_cbs_sublabel.c @@ -21,6 +21,7 @@ #include "../menu_driver.h" #include "../menu_cbs.h" +#include "../../input/input_remapping.h" #include "../../retroarch.h" #include "../../core_option_manager.h" @@ -451,6 +452,7 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_auto_rotate, MENU_ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_input_overlay_auto_scale, MENU_ENUM_SUBLABEL_INPUT_OVERLAY_AUTO_SCALE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_content_collection_list, MENU_ENUM_SUBLABEL_PLAYLISTS_TAB) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_scale_integer, MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_scale_integer_overscale, MENU_ENUM_SUBLABEL_VIDEO_SCALE_INTEGER_OVERSCALE) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_gpu_screenshot, MENU_ENUM_SUBLABEL_VIDEO_GPU_SCREENSHOT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_rotation, MENU_ENUM_SUBLABEL_VIDEO_ROTATION) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_screen_orientation, MENU_ENUM_SUBLABEL_SCREEN_ORIENTATION) @@ -870,6 +872,9 @@ DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_ipu_filter_type, #if defined(DINGUX_BETA) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_refresh_rate, MENU_ENUM_SUBLABEL_VIDEO_DINGUX_REFRESH_RATE) #endif +#if defined(RS90) +DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_dingux_rs90_softfilter_type, MENU_ENUM_SUBLABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE) +#endif #endif DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_height, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_HEIGHT) DEFAULT_SUBLABEL_MACRO(action_bind_sublabel_video_viewport_custom_width, MENU_ENUM_SUBLABEL_VIDEO_VIEWPORT_CUSTOM_WIDTH) @@ -1966,6 +1971,11 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_dingux_refresh_rate); break; #endif +#if defined(RS90) + case MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_dingux_rs90_softfilter_type); + break; +#endif #endif case MENU_ENUM_LABEL_CORE_INFORMATION: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_core_information); @@ -3278,6 +3288,9 @@ int menu_cbs_init_bind_sublabel(menu_file_list_cbs_t *cbs, case MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_scale_integer); break; + case MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_OVERSCALE: + BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_video_scale_integer_overscale); + break; case MENU_ENUM_LABEL_PLAYLISTS_TAB: BIND_ACTION_SUBLABEL(cbs, action_bind_sublabel_content_collection_list); break; diff --git a/menu/drivers/materialui.c b/menu/drivers/materialui.c index 476de4729b..3f063370b4 100644 --- a/menu/drivers/materialui.c +++ b/menu/drivers/materialui.c @@ -3512,7 +3512,15 @@ static void materialui_render(void *data, { size_t i; float bottom; - float scale_factor; + /* c.f. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + * On some platforms (e.g. 32-bit x86 without SSE), + * gcc can produce inconsistent floating point results + * depending upon optimisation level. This can break + * floating point variable comparisons. A workaround is + * to declare the affected variable as 'volatile', which + * disables optimisations and removes excess precision + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c87) */ + volatile float scale_factor; settings_t *settings = config_get_ptr(); materialui_handle_t *mui = (materialui_handle_t*)data; gfx_display_t *p_disp = disp_get_ptr(); diff --git a/menu/drivers/ozone/ozone.c b/menu/drivers/ozone/ozone.c index e9d10aba8a..1dd415bdb0 100644 --- a/menu/drivers/ozone/ozone.c +++ b/menu/drivers/ozone/ozone.c @@ -1750,7 +1750,15 @@ static void ozone_render(void *data, bool is_idle) { size_t i; - float scale_factor; + /* c.f. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + * On some platforms (e.g. 32-bit x86 without SSE), + * gcc can produce inconsistent floating point results + * depending upon optimisation level. This can break + * floating point variable comparisons. A workaround is + * to declare the affected variable as 'volatile', which + * disables optimisations and removes excess precision + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c87) */ + volatile float scale_factor; unsigned entries_end = (unsigned)menu_entries_get_size(); bool pointer_enabled = false; unsigned language = *msg_hash_get_uint(MSG_HASH_USER_LANGUAGE); diff --git a/menu/drivers/rgui.c b/menu/drivers/rgui.c index ff8631edeb..519f17eed4 100644 --- a/menu/drivers/rgui.c +++ b/menu/drivers/rgui.c @@ -80,6 +80,22 @@ #define RGUI_MIN_FB_WIDTH 256 #define RGUI_MAX_FB_WIDTH 426 +#if defined(DINGUX) +#if defined(RS90) +/* The RS-90 uses a fixed framebuffer size + * of 240x160 */ +#define RGUI_DINGUX_ASPECT_RATIO RGUI_ASPECT_RATIO_3_2 +#define RGUI_DINGUX_FB_WIDTH 240 +#define RGUI_DINGUX_FB_HEIGHT 160 +#else +/* Other Dingux devices (RG350 etc.) use a + * fixed framebuffer size of 320x240 */ +#define RGUI_DINGUX_ASPECT_RATIO RGUI_ASPECT_RATIO_4_3 +#define RGUI_DINGUX_FB_WIDTH 320 +#define RGUI_DINGUX_FB_HEIGHT 240 +#endif +#endif + /* Maximum entry value length in characters * when using fixed with layouts * (i.e. Maximum possible 'spacing' as @@ -1502,20 +1518,21 @@ static bool rgui_set_pixel_format_function(void) return transparency_supported; } - if ( string_is_equal(driver_ident, "ps2")) /* PS2 */ + if ( string_is_equal(driver_ident, "ps2")) /* PS2 */ { argb32_to_pixel_platform_format = argb32_to_abgr1555; transparency_supported = false; } - else if (string_is_equal(driver_ident, "gx")) /* GEKKO */ + else if (string_is_equal(driver_ident, "gx")) /* GEKKO */ argb32_to_pixel_platform_format = argb32_to_rgb5a3; - else if (string_is_equal(driver_ident, "psp1")) /* PSP */ + else if (string_is_equal(driver_ident, "psp1")) /* PSP */ argb32_to_pixel_platform_format = argb32_to_abgr4444; - else if (string_is_equal(driver_ident, "d3d10") || /* D3D10/11/12 */ + else if (string_is_equal(driver_ident, "d3d10") || /* D3D10/11/12 */ string_is_equal(driver_ident, "d3d11") || string_is_equal(driver_ident, "d3d12")) argb32_to_pixel_platform_format = argb32_to_bgra4444; - else if (string_is_equal(driver_ident, "sdl_dingux")) /* DINGUX SDL */ + else if (string_is_equal(driver_ident, "sdl_dingux") || /* DINGUX SDL */ + string_is_equal(driver_ident, "sdl_rs90")) { argb32_to_pixel_platform_format = argb32_to_rgb565; transparency_supported = false; @@ -3006,7 +3023,7 @@ static void load_custom_theme(rgui_t *rgui, rgui_theme_t *theme_colors, const ch const char *wallpaper_key = NULL; bool success = false; #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; #else settings_t *settings = config_get_ptr(); unsigned aspect_ratio = settings->uints.menu_rgui_aspect_ratio; @@ -4719,7 +4736,9 @@ static void rgui_render(void *data, unsigned title_y = rgui->term_layout.start_y - rgui->font_height_stride; unsigned term_end_x = rgui->term_layout.start_x + (rgui->term_layout.width * rgui->font_width_stride); unsigned timedate_x = term_end_x - (5 * rgui->font_width_stride); - unsigned core_name_len = ((timedate_x - rgui->term_layout.start_x) / rgui->font_width_stride) - 3; + unsigned core_name_len = menu_timedate_enable ? + ((timedate_x - rgui->term_layout.start_x) / rgui->font_width_stride) - 3 : + rgui->term_layout.width - 1; bool show_mini_thumbnails = rgui->is_playlist && rgui_inline_thumbnails; bool show_thumbnail = false; bool show_left_thumbnail = false; @@ -5435,15 +5454,14 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, * width value must be zero... */ unsigned max_frame_buf_width = 424; #elif defined(DINGUX) - /* Dingux devices use a fixed framebuffer size - * of 320x240 */ - unsigned max_frame_buf_width = 320; + /* Dingux devices use a fixed framebuffer size */ + unsigned max_frame_buf_width = RGUI_DINGUX_FB_WIDTH; #else struct video_viewport vp; unsigned max_frame_buf_width = RGUI_MAX_FB_WIDTH; #endif #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; unsigned aspect_ratio_lock = RGUI_ASPECT_RATIO_LOCK_NONE; #else settings_t *settings = config_get_ptr(); @@ -5469,9 +5487,8 @@ static bool rgui_set_aspect_ratio(rgui_t *rgui, * values */ rgui->frame_buf.height = p_disp->framebuf_height; #elif defined(DINGUX) - /* Dingux devices use a fixed framebuffer size - * of 320x240 */ - rgui->frame_buf.height = 240; + /* Dingux devices use a fixed framebuffer size */ + rgui->frame_buf.height = RGUI_DINGUX_FB_HEIGHT; #else /* If window height is less than RGUI default * height of 240, allow the frame buffer to @@ -6225,7 +6242,7 @@ static void rgui_toggle_fs_thumbnail(void *userdata) } /* Note that we always load thumbnails immediately - * when toggling via the 'scan' button (scheduling a + * when toggling via a RetroPad button (scheduling a * delayed load here would make for a poor user * experience...) */ rgui_scan_selected_entry_thumbnail(rgui, true); @@ -6587,7 +6604,7 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) bool bg_filler_thickness_enable = settings->bools.menu_rgui_background_filler_thickness_enable; bool border_filler_thickness_enable = settings->bools.menu_rgui_border_filler_thickness_enable; #if defined(DINGUX) - unsigned aspect_ratio = RGUI_ASPECT_RATIO_4_3; + unsigned aspect_ratio = RGUI_DINGUX_ASPECT_RATIO; unsigned aspect_ratio_lock = RGUI_ASPECT_RATIO_LOCK_NONE; #else unsigned aspect_ratio = settings->uints.menu_rgui_aspect_ratio; @@ -6714,7 +6731,7 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) if ((rgui->window_width != video_width) || (rgui->window_height != video_height)) { -#if !defined(GEKKO) +#if !defined(GEKKO) && !defined(DINGUX) /* If window width or height are less than the * RGUI default size of (320-426)x240, must enable * dynamic menu 'downscaling'. @@ -6744,7 +6761,6 @@ static void rgui_frame(void *data, video_frame_info_t *video_info) case RGUI_ASPECT_RATIO_5_3_CENTRE: default_fb_width = 400; break; - default: /* 4:3 */ default_fb_width = 320; @@ -6928,8 +6944,22 @@ static enum menu_action rgui_parse_menu_entry_action( } break; case MENU_ACTION_SCAN: - /* If this is a playlist, 'scan' command is - * used to toggle fullscreen thumbnail view */ + case MENU_ACTION_START: + /* If this is a playlist, both the 'scan' + * command and 'start' action are used to + * toggle the fullscreen thumbnail view + * > 'scan' is more ergonomic, which is a + * benefit for RGUI because its low + * resolution framebuffer means fullscreen + * thumbnails are likely to be viewed far + * more often than with other menu drivers + * > 'start' is the regular toggle button + * for all other menu drivers, and is + * included as a fallback here for users + * with gamepads with limited numbers of + * face buttons (e.g. a NES-style pad + * does not possess a RetroPad Y/'scan' + * button) */ if (rgui->is_playlist) { rgui_toggle_fs_thumbnail(rgui); diff --git a/menu/drivers/xmb.c b/menu/drivers/xmb.c index 8a288b1817..058909173b 100644 --- a/menu/drivers/xmb.c +++ b/menu/drivers/xmb.c @@ -3971,7 +3971,15 @@ static void xmb_render(void *data, /* 'i' must be of 'size_t', since it is passed * by reference to menu_entries_ctl() */ size_t i; - float scale_factor; + /* c.f. https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323 + * On some platforms (e.g. 32-bit x86 without SSE), + * gcc can produce inconsistent floating point results + * depending upon optimisation level. This can break + * floating point variable comparisons. A workaround is + * to declare the affected variable as 'volatile', which + * disables optimisations and removes excess precision + * (https://gcc.gnu.org/bugzilla/show_bug.cgi?id=323#c87) */ + volatile float scale_factor; xmb_handle_t *xmb = (xmb_handle_t*)data; settings_t *settings = config_get_ptr(); size_t end = menu_entries_get_size(); diff --git a/menu/menu_defines.h b/menu/menu_defines.h index 939ead32d1..e9698558c2 100644 --- a/menu/menu_defines.h +++ b/menu/menu_defines.h @@ -416,6 +416,15 @@ enum quit_on_close_content_type QUIT_ON_CLOSE_CONTENT_LAST }; +#if defined(DINGUX) && defined(RS90) +enum dingux_rs90_softfilter_type +{ + DINGUX_RS90_SOFTFILTER_POINT = 0, + DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ, + DINGUX_RS90_SOFTFILTER_LAST +}; +#endif + RETRO_END_DECLS #endif diff --git a/menu/menu_displaylist.c b/menu/menu_displaylist.c index ba2dd8ef88..7aded472b3 100644 --- a/menu/menu_displaylist.c +++ b/menu/menu_displaylist.c @@ -112,6 +112,7 @@ #include "../manual_content_scan.h" #include "../core_backup.h" #include "../misc/cpufreq/cpufreq.h" +#include "../input/input_remapping.h" /* Spacers used for ' - ' labels * in playlists */ @@ -6027,6 +6028,12 @@ unsigned menu_displaylist_build_list( MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_FILTER_TYPE, PARSE_ONLY_UINT, false) == 0) count++; +#if defined(RS90) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + PARSE_ONLY_UINT, false) == 0) + count++; +#endif #endif if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_VIDEO_SHADER_DELAY, @@ -7767,7 +7774,8 @@ unsigned menu_displaylist_build_list( case DISPLAYLIST_VIDEO_SCALING_SETTINGS_LIST: { #if defined(DINGUX) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER, @@ -7785,6 +7793,11 @@ unsigned menu_displaylist_build_list( MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER, PARSE_ONLY_BOOL, false) == 0) count++; + if (settings->bools.video_scale_integer) + if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, + MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + PARSE_ONLY_BOOL, false) == 0) + count++; if (MENU_DISPLAYLIST_PARSE_SETTINGS_ENUM(list, MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO_INDEX, PARSE_ONLY_UINT, false) == 0) diff --git a/menu/menu_setting.c b/menu/menu_setting.c index 4ea8deb769..2cc00060de 100644 --- a/menu/menu_setting.c +++ b/menu/menu_setting.c @@ -5200,6 +5200,32 @@ static void setting_get_string_representation_uint_video_dingux_refresh_rate( } } #endif + +#if defined(RS90) +static void setting_get_string_representation_uint_video_dingux_rs90_softfilter_type( + rarch_setting_t *setting, + char *s, size_t len) +{ + if (!setting) + return; + + switch (*setting->value.target.unsigned_integer) + { + case DINGUX_RS90_SOFTFILTER_POINT: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT), + len); + break; + case DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ: + strlcpy(s, + msg_hash_to_str( + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ), + len); + break; + } +} +#endif #endif static void setting_get_string_representation_uint_input_auto_game_focus( @@ -7615,10 +7641,14 @@ static void general_write_handler(rarch_setting_t *setting) case MENU_ENUM_LABEL_VIDEO_CTX_SCALING: #if defined(DINGUX) case MENU_ENUM_LABEL_VIDEO_DINGUX_IPU_FILTER_TYPE: +#if defined(RS90) + case MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE: +#endif #endif { settings_t *settings = config_get_ptr(); - video_driver_set_filtering(1, settings->bools.video_ctx_scaling, settings->bools.video_ctx_scaling); + video_driver_set_filtering(1, settings->bools.video_smooth, + settings->bools.video_ctx_scaling); } break; case MENU_ENUM_LABEL_VIDEO_ROTATION: @@ -7959,8 +7989,24 @@ static void general_write_handler(rarch_setting_t *setting) * force a cache refresh on the next * core info initialisation */ if (*setting->value.target.boolean) - core_info_cache_force_refresh(!string_is_empty(path_libretro_info) ? - path_libretro_info : dir_libretro); + if (!core_info_cache_force_refresh(!string_is_empty(path_libretro_info) ? + path_libretro_info : dir_libretro)) + { + /* core_info_cache_force_refresh() will fail + * if we cannot write to the the core_info + * directory. This will typically only happen + * on platforms where the core_info directory + * is explicitly (and intentionally) placed on + * read-only storage. In this case, core info + * caching cannot function correctly anyway, + * so we simply force-disable the feature */ + configuration_set_bool(settings, + settings->bools.core_info_cache_enable, false); + runloop_msg_queue_push( + msg_hash_to_str(MSG_CORE_INFO_CACHE_UNSUPPORTED), + 1, 100, true, + NULL, MESSAGE_QUEUE_ICON_DEFAULT, MESSAGE_QUEUE_CATEGORY_INFO); + } } break; default: @@ -10954,7 +11000,8 @@ static bool setting_append_list( } #if defined(DINGUX) && defined(DINGUX_BETA) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_UINT( list, list_info, @@ -11209,7 +11256,8 @@ static bool setting_append_list( SETTINGS_DATA_LIST_CURRENT_ADD_FLAGS(list, list_info, SD_FLAG_LAKKA_ADVANCED); #if defined(DINGUX) - if (string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + if (string_is_equal(settings->arrays.video_driver, "sdl_dingux") || + string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_BOOL( list, list_info, @@ -11366,6 +11414,28 @@ static bool setting_append_list( list_info, CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); + CONFIG_BOOL( + list, list_info, + &settings->bools.video_scale_integer_overscale, + MENU_ENUM_LABEL_VIDEO_SCALE_INTEGER_OVERSCALE, + MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER_OVERSCALE, + DEFAULT_SCALE_INTEGER_OVERSCALE, + MENU_ENUM_LABEL_VALUE_OFF, + MENU_ENUM_LABEL_VALUE_ON, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler, + SD_FLAG_NONE); + (*list)[list_info->index - 1].action_ok = setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_left = setting_bool_action_left_with_refresh; + (*list)[list_info->index - 1].action_right = setting_bool_action_right_with_refresh; + MENU_SETTINGS_LIST_CURRENT_ADD_CMD( + list, + list_info, + CMD_EVENT_VIDEO_APPLY_STATE_CHANGES); + #ifdef GEKKO CONFIG_UINT( list, list_info, @@ -11442,6 +11512,27 @@ static bool setting_append_list( menu_settings_list_current_add_range(list, list_info, 0, DINGUX_IPU_FILTER_LAST - 1, 1, true, true); (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX; } +#if defined(RS90) + else if (string_is_equal(settings->arrays.video_driver, "sdl_rs90")) + { + CONFIG_UINT( + list, list_info, + &settings->uints.video_dingux_rs90_softfilter_type, + MENU_ENUM_LABEL_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_TYPE, + DEFAULT_DINGUX_RS90_SOFTFILTER_TYPE, + &group_info, + &subgroup_info, + parent_group, + general_write_handler, + general_read_handler); + (*list)[list_info->index - 1].action_ok = &setting_action_ok_uint; + (*list)[list_info->index - 1].get_string_representation = + &setting_get_string_representation_uint_video_dingux_rs90_softfilter_type; + menu_settings_list_current_add_range(list, list_info, 0, DINGUX_RS90_SOFTFILTER_LAST - 1, 1, true, true); + (*list)[list_info->index - 1].ui_type = ST_UI_TYPE_UINT_COMBOBOX; + } +#endif else #endif { @@ -14913,10 +15004,11 @@ static bool setting_append_list( general_read_handler); MENU_SETTINGS_LIST_CURRENT_ADD_VALUES(list, list_info, "cfg"); - /* ps2 and sdl_dingux gfx drivers do not support - * menu framebuffer transparency */ + /* ps2 and sdl_dingux/sdl_rs90 gfx drivers do + * not support menu framebuffer transparency */ if (!string_is_equal(settings->arrays.video_driver, "ps2") && - !string_is_equal(settings->arrays.video_driver, "sdl_dingux")) + !string_is_equal(settings->arrays.video_driver, "sdl_dingux") && + !string_is_equal(settings->arrays.video_driver, "sdl_rs90")) { CONFIG_BOOL( list, list_info, @@ -16405,7 +16497,7 @@ static bool setting_append_list( &settings->bools.menu_timedate_enable, MENU_ENUM_LABEL_TIMEDATE_ENABLE, MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE, - true, + DEFAULT_MENU_TIMEDATE_ENABLE, MENU_ENUM_LABEL_VALUE_OFF, MENU_ENUM_LABEL_VALUE_ON, &group_info, diff --git a/msg_hash.h b/msg_hash.h index cc67621fd7..ea724912dd 100644 --- a/msg_hash.h +++ b/msg_hash.h @@ -491,6 +491,7 @@ enum msg_hash_enums MSG_LOCALAP_ERROR_CONFIG_PARSE, #endif MSG_UNSUPPORTED_VIDEO_MODE, + MSG_CORE_INFO_CACHE_UNSUPPORTED, MENU_LABEL(MENU_XMB_ANIMATION_HORIZONTAL_HIGHLIGHT), MENU_LABEL(MENU_XMB_ANIMATION_MOVE_UP_DOWN), @@ -1072,6 +1073,7 @@ enum msg_hash_enums MENU_LABEL(VIDEO_NOTCH_WRITE_OVER), MENU_LABEL(VIDEO_SCALE_INTEGER), + MENU_LABEL(VIDEO_SCALE_INTEGER_OVERSCALE), MENU_LABEL(VIDEO_VIEWPORT_CUSTOM_X), MENU_LABEL(VIDEO_VIEWPORT_CUSTOM_Y), MENU_LABEL(VIDEO_VIEWPORT_CUSTOM_WIDTH), @@ -2472,6 +2474,12 @@ enum msg_hash_enums MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_REFRESH_RATE_60HZ, MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_REFRESH_RATE_50HZ, #endif +#if defined(RS90) + MENU_LABEL(VIDEO_DINGUX_RS90_SOFTFILTER_TYPE), + + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_POINT, + MENU_ENUM_LABEL_VALUE_VIDEO_DINGUX_RS90_SOFTFILTER_BRESENHAM_HORZ, +#endif #endif MENU_LABEL(VIDEO_VFILTER), MENU_LABEL(VIDEO_GPU_RECORD), diff --git a/pkg/ctr/Makefile.cores b/pkg/ctr/Makefile.cores index c3645f0502..be73907225 100644 --- a/pkg/ctr/Makefile.cores +++ b/pkg/ctr/Makefile.cores @@ -34,13 +34,6 @@ else ifeq ($(LIBRETRO), bluemsx) APP_ICON = pkg/ctr/assets/bluemsx.png APP_BANNER = pkg/ctr/assets/bluemsx_banner.png -else ifeq ($(LIBRETRO), chailove) - APP_TITLE = ChaiLove - APP_PRODUCT_CODE = RARCH-CHAILOVE - APP_UNIQUE_ID = 0xBACB2 - APP_ICON = pkg/ctr/assets/default.png - APP_BANNER = pkg/ctr/assets/libretro_banner.png - else ifeq ($(LIBRETRO), cap32) APP_TITLE = Caprice32 APP_AUTHOR = various @@ -49,6 +42,13 @@ else ifeq ($(LIBRETRO), cap32) APP_ICON = pkg/ctr/assets/Caprice32.png APP_BANNER = pkg/ctr/assets/Caprice32_banner.png +else ifeq ($(LIBRETRO), chailove) + APP_TITLE = ChaiLove + APP_PRODUCT_CODE = RARCH-CHAILOVE + APP_UNIQUE_ID = 0xBACB2 + APP_ICON = pkg/ctr/assets/default.png + APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), crocods) APP_TITLE = CROCODS APP_PRODUCT_CODE = RARCH-CROCODS @@ -88,15 +88,6 @@ else ifeq ($(LIBRETRO), fbalpha2012) APP_ICON = pkg/ctr/assets/fbalpha2012.png APP_BANNER = pkg/ctr/assets/fbalpha2012_banner.png -else ifeq ($(LIBRETRO), fbalpha2012_neogeo) - APP_TITLE = Final Burn Alpha 2012 - NeoGeo - APP_AUTHOR = Team FB Alpha - APP_PRODUCT_CODE = RARCH-FBANEOGEO - APP_UNIQUE_ID = 0xBAC10 - APP_ICON = pkg/ctr/assets/fbalpha2012_neogeo.png - APP_BANNER = pkg/ctr/assets/fbalpha2012_neogeo_banner.png - APP_SYSTEM_MODE = 80MB - else ifeq ($(LIBRETRO), fbalpha2012_cps1) APP_TITLE = Final Burn Alpha 2012 - CPS-1 APP_AUTHOR = Team FB Alpha @@ -123,6 +114,15 @@ else ifeq ($(LIBRETRO), fbalpha2012_cps3) APP_BANNER = pkg/ctr/assets/fbalpha2012_cps3_banner.png APP_SYSTEM_MODE = 80MB +else ifeq ($(LIBRETRO), fbalpha2012_neogeo) + APP_TITLE = Final Burn Alpha 2012 - NeoGeo + APP_AUTHOR = Team FB Alpha + APP_PRODUCT_CODE = RARCH-FBANEOGEO + APP_UNIQUE_ID = 0xBAC10 + APP_ICON = pkg/ctr/assets/fbalpha2012_neogeo.png + APP_BANNER = pkg/ctr/assets/fbalpha2012_neogeo_banner.png + APP_SYSTEM_MODE = 80MB + else ifeq ($(LIBRETRO), fbneo) APP_TITLE = FinalBurn Neo APP_AUTHOR = Team FBNeo @@ -160,13 +160,6 @@ else ifeq ($(LIBRETRO), freechaf) APP_ICON = pkg/ctr/assets/default.png APP_BANNER = pkg/ctr/assets/libretro_banner.png -else ifeq ($(LIBRETRO), frodo) - APP_TITLE = Frodo - APP_PRODUCT_CODE = RARCH-FRODO - APP_UNIQUE_ID = 0xBACB9 - APP_ICON = pkg/ctr/assets/default.png - APP_BANNER = pkg/ctr/assets/libretro_banner.png - else ifeq ($(LIBRETRO), freeintv) APP_TITLE = FreeIntv APP_AUTHOR = various @@ -175,6 +168,13 @@ else ifeq ($(LIBRETRO), freeintv) APP_ICON = pkg/ctr/assets/freeintv.png APP_BANNER = pkg/ctr/assets/freeintv_banner.png +else ifeq ($(LIBRETRO), frodo) + APP_TITLE = Frodo + APP_PRODUCT_CODE = RARCH-FRODO + APP_UNIQUE_ID = 0xBACB9 + APP_ICON = pkg/ctr/assets/default.png + APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), fuse) APP_TITLE = Fuse APP_AUTHOR = various @@ -197,6 +197,13 @@ else ifeq ($(LIBRETRO), genesis_plus_gx) APP_ICON = pkg/ctr/assets/genesis_plus_gx.png APP_BANNER = pkg/ctr/assets/genesis_plus_gx_banner.png +else ifeq ($(LIBRETRO), genesis_plus_gx_wide) + APP_TITLE = Genesis Plus GX Libretro Wide + APP_PRODUCT_CODE = RARCH-GENPLUSGXWIDE + APP_UNIQUE_ID = 0xBACE0 + APP_ICON = pkg/ctr/assets/genesis_plus_gx.png + APP_BANNER = pkg/ctr/assets/genesis_plus_gx_banner.png + else ifeq ($(LIBRETRO), gme) APP_TITLE = GME APP_PRODUCT_CODE = RARCH-GME @@ -226,6 +233,13 @@ else ifeq ($(LIBRETRO), handy) APP_ICON = pkg/ctr/assets/handy.png APP_BANNER = pkg/ctr/assets/handy_banner.png +else ifeq ($(LIBRETRO), lowresnx) + APP_TITLE = LowRes NX + APP_PRODUCT_CODE = RARCH-LOWRESNX + APP_UNIQUE_ID = 0xBACD1 + APP_ICON = pkg/ctr/assets/default.png + APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), hatari) APP_TITLE = Hatari APP_PRODUCT_CODE = RARCH-HATARI @@ -301,14 +315,6 @@ else ifeq ($(LIBRETRO), mgba) APP_ICON = pkg/ctr/assets/mgba.png APP_BANNER = pkg/ctr/assets/mgba_banner.png -else ifeq ($(LIBRETRO), nekop2) - APP_TITLE = Neko Project 2 - APP_AUTHOR = various - APP_PRODUCT_CODE = RARCH-NP2 - APP_UNIQUE_ID = 0xBAC1C - APP_ICON = pkg/ctr/assets/nekop2.png - APP_BANNER = pkg/ctr/assets/nekop2_banner.png - else ifeq ($(LIBRETRO), mrboom) APP_TITLE = MrBoom APP_PRODUCT_CODE = RARCH-MRBOOM @@ -323,6 +329,14 @@ else ifeq ($(LIBRETRO), mu) APP_ICON = pkg/ctr/assets/MU.png APP_BANNER = pkg/ctr/assets/MU_banner.png +else ifeq ($(LIBRETRO), nekop2) + APP_TITLE = Neko Project 2 + APP_AUTHOR = various + APP_PRODUCT_CODE = RARCH-NP2 + APP_UNIQUE_ID = 0xBAC1C + APP_ICON = pkg/ctr/assets/nekop2.png + APP_BANNER = pkg/ctr/assets/nekop2_banner.png + else ifeq ($(LIBRETRO), neocd) APP_TITLE = NeoCD APP_PRODUCT_CODE = RARCH-NEOCD @@ -392,7 +406,6 @@ else ifeq ($(LIBRETRO), pocketcdg) APP_ICON = pkg/ctr/assets/default.png APP_BANNER = pkg/ctr/assets/libretro_banner.png - else ifeq ($(LIBRETRO), pokemini) APP_TITLE = PokeMini APP_AUTHOR = justburn @@ -597,6 +610,13 @@ else ifeq ($(LIBRETRO), vice_xcbm2) APP_ICON = pkg/ctr/assets/default.png APP_BANNER = pkg/ctr/assets/libretro_banner.png +else ifeq ($(LIBRETRO), vice_xcbm5x0) + APP_TITLE = VICE xcbm5x0 + APP_PRODUCT_CODE = RARCH-VICE-XCBM5X0 + APP_UNIQUE_ID = 0xBACD2 + APP_ICON = pkg/ctr/assets/default.png + APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), vice_xpet) APP_TITLE = VICE xpet APP_PRODUCT_CODE = RARCH-VICE-XPET @@ -611,6 +631,13 @@ else ifeq ($(LIBRETRO), vice_xplus4) APP_ICON = pkg/ctr/assets/default.png APP_BANNER = pkg/ctr/assets/libretro_banner.png +else ifeq ($(LIBRETRO), vice_xscpu64) + APP_TITLE = VICE xscpu64 + APP_PRODUCT_CODE = RARCH-VICE-XSCPU64 + APP_UNIQUE_ID = 0xBACD3 + APP_ICON = pkg/ctr/assets/default.png + APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), vice_xvic) APP_TITLE = VICE xvic APP_PRODUCT_CODE = RARCH-VICE-XVIC @@ -631,6 +658,7 @@ else ifeq ($(LIBRETRO), x1) APP_UNIQUE_ID = 0xBAC99 APP_ICON = pkg/ctr/assets/default.png APP_BANNER = pkg/ctr/assets/libretro_banner.png + else ifeq ($(LIBRETRO), xrick) APP_TITLE = XRick APP_PRODUCT_CODE = RARCH-XRICK diff --git a/ps2/include/ps2_irx_variables.h b/ps2/include/ps2_irx_variables.h index 5696213422..51455e0ea9 100644 --- a/ps2/include/ps2_irx_variables.h +++ b/ps2/include/ps2_irx_variables.h @@ -51,8 +51,14 @@ extern unsigned int size_ps2fs_irx; extern unsigned char usbd_irx; extern unsigned int size_usbd_irx; -extern unsigned char usbhdfsd_irx; -extern unsigned int size_usbhdfsd_irx; +extern unsigned char bdm_irx; +extern unsigned int size_bdm_irx; + +extern unsigned char bdmfs_vfat_irx; +extern unsigned int size_bdmfs_vfat_irx; + +extern unsigned char usbmass_bd_irx; +extern unsigned int size_usbmass_bd_irx; extern unsigned char cdfs_irx; extern unsigned int size_cdfs_irx; diff --git a/ps2/irx/Makefile b/ps2/irx/Makefile index 26997ee593..916ee60f95 100644 --- a/ps2/irx/Makefile +++ b/ps2/irx/Makefile @@ -4,7 +4,8 @@ IRX_DIR = $(PS2SDK)/iop/irx #IRX modules # IRX modules - modules have to be in IRX_DIR -IRX_FILES += iomanX.irx fileXio.irx sio2man.irx mtapman.irx padman.irx mcman.irx mcserv.irx usbd.irx usbhdfsd.irx +IRX_FILES += iomanX.irx fileXio.irx sio2man.irx mtapman.irx padman.irx mcman.irx mcserv.irx +IRX_FILES += usbd.irx bdm.irx bdmfs_vfat.irx usbmass_bd.irx IRX_FILES += libsd.irx audsrv.irx cdfs.irx IRX_C_FILES = $(IRX_FILES:.irx=_irx.c) diff --git a/retroarch.c b/retroarch.c index fd9d55ec53..0642c8c779 100644 --- a/retroarch.c +++ b/retroarch.c @@ -14296,12 +14296,25 @@ bool command_event(enum event_command cmd, void *data) return false; if (!string_is_empty(dir_libretro)) + { + bool cache_supported = false; + core_info_init_list(path_libretro_info, dir_libretro, ext_name, show_hidden_files, - core_info_cache_enable - ); + core_info_cache_enable, + &cache_supported); + + /* If core info cache is enabled but cache + * functionality is unsupported (i.e. because + * the core info directory is on read-only + * storage), force-disable the setting to + * avoid repeated failures */ + if (core_info_cache_enable && !cache_supported) + configuration_set_bool(settings, + settings->bools.core_info_cache_enable, false); + } } break; case CMD_EVENT_CORE_DEINIT: @@ -18137,7 +18150,11 @@ static bool rarch_environment_cb(unsigned cmd, void *data) DRIVERS_CMD_ALL & ~(DRIVER_VIDEO_MASK | DRIVER_INPUT_MASK | DRIVER_MENU_MASK) : DRIVERS_CMD_ALL; - RARCH_LOG("[Environ]: SET_SYSTEM_AV_INFO.\n"); + RARCH_LOG("[Environ]: SET_SYSTEM_AV_INFO: %ux%u, aspect: %.3f, fps: %.3f, sample rate: %.2f Hz.\n", + (*info)->geometry.base_width, (*info)->geometry.base_height, + (*info)->geometry.aspect_ratio, + (*info)->timing.fps, + (*info)->timing.sample_rate); memcpy(av_info, *info, sizeof(*av_info)); command_event(CMD_EVENT_REINIT, &reinit_flags); @@ -26510,46 +26527,46 @@ void input_keyboard_event(bool down, unsigned code, } } -static bool input_config_bind_map_get_valid(unsigned i) +static bool input_config_bind_map_get_valid(unsigned bind_index) { const struct input_bind_map *keybind = - (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i); + (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index); if (!keybind) return false; return keybind->valid; } -unsigned input_config_bind_map_get_meta(unsigned i) +unsigned input_config_bind_map_get_meta(unsigned bind_index) { const struct input_bind_map *keybind = - (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i); + (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index); if (!keybind) return 0; return keybind->meta; } -const char *input_config_bind_map_get_base(unsigned i) +const char *input_config_bind_map_get_base(unsigned bind_index) { const struct input_bind_map *keybind = - (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i); + (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index); if (!keybind) return NULL; return keybind->base; } -const char *input_config_bind_map_get_desc(unsigned i) +const char *input_config_bind_map_get_desc(unsigned bind_index) { const struct input_bind_map *keybind = - (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i); + (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index); if (!keybind) return NULL; return msg_hash_to_str(keybind->desc); } -uint8_t input_config_bind_map_get_retro_key(unsigned i) +uint8_t input_config_bind_map_get_retro_key(unsigned bind_index) { const struct input_bind_map *keybind = - (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(i); + (const struct input_bind_map*)INPUT_CONFIG_BIND_MAP_GET(bind_index); if (!keybind) return 0; return keybind->retro_key; @@ -31379,6 +31396,19 @@ void video_driver_set_viewport_core(void) (float)geom->base_width / geom->base_height; } +void video_driver_set_viewport_full(void) +{ + unsigned width = 0; + unsigned height = 0; + + video_driver_get_size(&width, &height); + + if (width == 0 || height == 0) + return; + + aspectratio_lut[ASPECT_RATIO_FULL].value = (float)width / (float)height; +} + void video_driver_reset_custom_viewport(void) { struct rarch_state *p_rarch = &rarch_st; @@ -31473,6 +31503,10 @@ void video_driver_set_aspect_ratio(void) settings->bools.video_aspect_ratio_auto); break; + case ASPECT_RATIO_FULL: + video_driver_set_viewport_full(); + break; + default: break; } @@ -31822,6 +31856,7 @@ void video_viewport_get_scaled_integer(struct video_viewport *vp, struct rarch_state *p_rarch = &rarch_st; settings_t *settings = p_rarch->configuration_settings; unsigned video_aspect_ratio_idx = settings->uints.video_aspect_ratio_idx; + bool overscale = settings->bools.video_scale_integer_overscale; if (video_aspect_ratio_idx == ASPECT_RATIO_CUSTOM) { @@ -31864,8 +31899,15 @@ void video_viewport_get_scaled_integer(struct video_viewport *vp, if (keep_aspect) { /* X/Y scale must be same. */ - unsigned max_scale = MIN(width / base_width, - height / base_height); + unsigned max_scale = 1; + + if (overscale) + max_scale = MIN((width / base_width) + !!(width % base_width), + (height / base_height) + !!(height % base_height)); + else + max_scale = MIN(width / base_width, + height / base_height); + padding_x = width - base_width * max_scale; padding_y = height - base_height * max_scale; } @@ -32830,6 +32872,7 @@ const gfx_ctx_driver_t *video_context_driver_init_first(void *data, case GFX_CTX_OPENGL_ES_API: case GFX_CTX_OPENVG_API: case GFX_CTX_METAL_API: + case GFX_CTX_RSX_API: return gl_context_driver_init_first( p_rarch, settings, data, ident, api, major, minor, @@ -38007,6 +38050,34 @@ static enum runloop_state runloop_check_state( } #endif + /* + * If the Aspect Ratio is FULL then update the aspect ratio to the + * current video driver aspect ratio (The full window) + * + * TODO/FIXME + * Should possibly be refactored to have last width & driver width & height + * only be done once when we are using an overlay OR using aspect ratio + * full + */ + if (settings->uints.video_aspect_ratio_idx == ASPECT_RATIO_FULL) + { + static unsigned last_width = 0; + static unsigned last_height = 0; + unsigned video_driver_width = p_rarch->video_driver_width; + unsigned video_driver_height = p_rarch->video_driver_height; + + /* Check whether video aspect has changed */ + if ((video_driver_width != last_width) || + (video_driver_height != last_height)) + { + /* Update set aspect ratio so the full matches the current video width & height */ + command_event(CMD_EVENT_VIDEO_SET_ASPECT_RATIO, NULL); + + last_width = video_driver_width; + last_height = video_driver_height; + } + } + /* Check quit key */ { bool trig_quit_key, quit_press_twice; @@ -39315,6 +39386,12 @@ enum retro_language rarch_get_language_from_iso(const char *iso639) {"vi", RETRO_LANGUAGE_VIETNAMESE}, {"ar", RETRO_LANGUAGE_ARABIC}, {"el", RETRO_LANGUAGE_GREEK}, + {"tr", RETRO_LANGUAGE_TURKISH}, + {"sk", RETRO_LANGUAGE_SLOVAK}, + {"fa", RETRO_LANGUAGE_PERSIAN}, + {"he", RETRO_LANGUAGE_HEBREW}, + {"ast", RETRO_LANGUAGE_ASTURIAN}, + {"fi", RETRO_LANGUAGE_FINNISH}, }; if (string_is_empty(iso639)) diff --git a/retroarch.h b/retroarch.h index f76cb34182..d49dca46cd 100644 --- a/retroarch.h +++ b/retroarch.h @@ -839,7 +839,8 @@ enum gfx_ctx_api GFX_CTX_DIRECT3D12_API, GFX_CTX_OPENVG_API, GFX_CTX_VULKAN_API, - GFX_CTX_METAL_API + GFX_CTX_METAL_API, + GFX_CTX_RSX_API }; enum display_metric_types @@ -1567,6 +1568,8 @@ bool video_driver_supports_read_frame_raw(void); void video_driver_set_viewport_core(void); +void video_driver_set_viewport_full(void); + void video_driver_reset_custom_viewport(void); void video_driver_set_rgba(void); @@ -1871,6 +1874,7 @@ extern video_driver_t video_xvideo; extern video_driver_t video_sdl; extern video_driver_t video_sdl2; extern video_driver_t video_sdl_dingux; +extern video_driver_t video_sdl_rs90; extern video_driver_t video_vg; extern video_driver_t video_omap; extern video_driver_t video_exynos; diff --git a/retroarch_data.h b/retroarch_data.h index e9713cf831..b48ace713d 100644 --- a/retroarch_data.h +++ b/retroarch_data.h @@ -645,8 +645,12 @@ static const video_driver_t *video_drivers[] = { &video_sdl2, #endif #ifdef HAVE_SDL_DINGUX +#if defined(RS90) + &video_sdl_rs90, +#else &video_sdl_dingux, #endif +#endif #ifdef HAVE_XVIDEO &video_xvideo, #endif @@ -995,7 +999,7 @@ static input_device_driver_t *joypad_drivers[] = { }; #ifdef HAVE_HID -static bool null_hid_joypad_query(void *data, unsigned pad) { +static bool null_hid_joypad_query(void *data, unsigned pad) { return pad < MAX_USERS; } static const char *null_hid_joypad_name( void *data, unsigned pad) { return NULL; } @@ -1190,7 +1194,7 @@ static midi_driver_t midi_null = { }; static midi_driver_t *midi_drivers[] = { -#if defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) +#if defined(HAVE_ALSA) && !defined(HAVE_HAKCHI) && !defined(HAVE_SEGAM) && !defined(DINGUX) &midi_alsa, #endif #ifdef HAVE_WINMM @@ -1665,7 +1669,7 @@ typedef struct discord_state discord_state_t; #endif struct runloop -{ +{ retro_usec_t frame_time_last; /* int64_t alignment */ msg_queue_t msg_queue; /* ptr alignment */ @@ -1733,7 +1737,7 @@ struct rarch_state menu_input_t menu_input_state; /* retro_time_t alignment */ #endif - + #if defined(HAVE_CG) || defined(HAVE_GLSL) || defined(HAVE_SLANG) || defined(HAVE_HLSL) rarch_timer_t shader_delay_timer; /* int64_t alignment */ @@ -1911,7 +1915,7 @@ struct rarch_state struct retro_subsystem_rom_info subsystem_data_roms[SUBSYSTEM_MAX_SUBSYSTEMS] [SUBSYSTEM_MAX_SUBSYSTEM_ROMS]; /* ptr alignment */ - + gfx_ctx_driver_t current_video_context; /* ptr alignment */ content_state_t content_st; /* ptr alignment */ midi_event_t midi_drv_input_event; /* ptr alignment */ @@ -1989,7 +1993,7 @@ struct rarch_state size_t runahead_save_state_size; #endif - jmp_buf error_sjlj_context; /* 4-byte alignment, + jmp_buf error_sjlj_context; /* 4-byte alignment, put it right before long */ turbo_buttons_t input_driver_turbo_btns; /* int32_t alignment */ @@ -2017,7 +2021,7 @@ struct rarch_state int reannounce; #endif - input_device_info_t input_device_info[MAX_INPUT_DEVICES]; + input_device_info_t input_device_info[MAX_INPUT_DEVICES]; /* unsigned alignment */ #ifdef HAVE_MENU menu_dialog_t dialog_st; /* unsigned alignment */ @@ -2093,7 +2097,7 @@ struct rarch_state #endif #ifdef HAVE_MENU - menu_input_pointer_hw_state_t menu_input_pointer_hw_state; + menu_input_pointer_hw_state_t menu_input_pointer_hw_state; /* int16_t alignment */ #endif @@ -2373,7 +2377,8 @@ struct aspect_ratio_elem aspectratio_lut[ASPECT_RATIO_END] = { { 0.0f, "Config" }, { 1.0f, "Square pixel" }, { 1.0f, "Core provided" }, - { 0.0f, "Custom" } + { 0.0f, "Custom" }, + { 1.3333f, "Full" } }; static gfx_api_gpu_map gpu_map[] = { diff --git a/tasks/task_autodetect.c b/tasks/task_autodetect.c index 6048fcaf91..69d8f94166 100644 --- a/tasks/task_autodetect.c +++ b/tasks/task_autodetect.c @@ -30,6 +30,7 @@ #include "../list_special.h" #include "../retroarch.h" #include "../input/input_driver.h" +#include "../input/input_remapping.h" #include "tasks_internal.h" #ifdef HAVE_BLISSBOX diff --git a/tasks/task_http.c b/tasks/task_http.c index 28ba001d26..eac88020ed 100644 --- a/tasks/task_http.c +++ b/tasks/task_http.c @@ -133,7 +133,7 @@ static int task_http_iterate_transfer(retro_task_t *task) task_set_progress(task, (signed)(pos * 100 / tot)); else /* but invert the logic if it would cause an overflow */ - task_set_progress(task, MAX((signed)pos / (tot / 100), 100)); + task_set_progress(task, MIN((signed)pos / (tot / 100), 100)); return -1; } diff --git a/tasks/task_netplay_nat_traversal.c b/tasks/task_netplay_nat_traversal.c index b645ef93d0..4068072df5 100644 --- a/tasks/task_netplay_nat_traversal.c +++ b/tasks/task_netplay_nat_traversal.c @@ -51,11 +51,8 @@ static void task_netplay_nat_traversal_handler(retro_task_t *task) struct nat_traversal_state_data *ntsd = (struct nat_traversal_state_data *) task->task_data; - natt_init(); - if (natt_new(ntsd->nat_traversal_state)) - natt_open_port_any(ntsd->nat_traversal_state, - ntsd->port, SOCKET_PROTOCOL_TCP); + natt_init(ntsd->nat_traversal_state, ntsd->port, SOCKET_PROTOCOL_TCP); task_set_progress(task, 100); task_set_finished(task, true); diff --git a/tasks/task_overlay.c b/tasks/task_overlay.c index 8d4410b689..3877a7931d 100644 --- a/tasks/task_overlay.c +++ b/tasks/task_overlay.c @@ -28,6 +28,7 @@ #include "tasks_internal.h" #include "../input/input_overlay.h" +#include "../input/input_remapping.h" #include "../retroarch.h" #include "../verbosity.h" diff --git a/ui/drivers/qt/qt_options.cpp b/ui/drivers/qt/qt_options.cpp index 6fbf3326d9..7b0b5d1d8b 100644 --- a/ui/drivers/qt/qt_options.cpp +++ b/ui/drivers/qt/qt_options.cpp @@ -14,6 +14,7 @@ extern "C" { #include "../../../gfx/video_display_server.h" #include "../../../input/input_driver.h" +#include "../../../input/input_remapping.h" #include "../../../network/netplay/netplay.h" #include "../../../retroarch.h" @@ -1352,6 +1353,7 @@ AspectRatioGroup::AspectRatioGroup(const QString &title, QWidget *parent) : QHBoxLayout *custom = new QHBoxLayout; QVBoxLayout *customRadio = new QVBoxLayout; QHBoxLayout *config = new QHBoxLayout; + QHBoxLayout *full = new QHBoxLayout; QHBoxLayout *aspectL = new QHBoxLayout; FormLayout *leftAspectForm = new FormLayout; FormLayout *rightAspectForm = new FormLayout; @@ -1382,6 +1384,8 @@ AspectRatioGroup::AspectRatioGroup(const QString &title, QWidget *parent) : config->setStretch(1, 1); config->setSizeConstraint(QLayout::SetMinimumSize); + full->addWidget(new UIntRadioButton(MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO_INDEX, ASPECT_RATIO_FULL)); + leftAspect->addRow(new UIntRadioButton(MENU_ENUM_LABEL_VIDEO_ASPECT_RATIO_INDEX, ASPECT_RATIO_CORE)); leftAspect->addRow(preset); @@ -1394,6 +1398,7 @@ AspectRatioGroup::AspectRatioGroup(const QString &title, QWidget *parent) : aspectL->addLayout(rightAspect); addRow(aspectL); + addRow(full); addRow(custom); connect(m_radioButton, SIGNAL(clicked(bool)), this, SLOT(onAspectRadioClicked(bool))); diff --git a/wiiu/fs/sd_fat_devoptab.c b/wiiu/fs/sd_fat_devoptab.c index a179d10134..f9b6608bac 100644 --- a/wiiu/fs/sd_fat_devoptab.c +++ b/wiiu/fs/sd_fat_devoptab.c @@ -279,47 +279,56 @@ static ssize_t sd_fat_write_r (struct _reent *r, void* fd, const char *ptr, size OSLockMutex(file->dev->pMutex); - size_t len_aligned = FS_ALIGN(len); - if(len_aligned > 0x4000) - len_aligned = 0x4000; - - unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); - if(!tmpBuf) { - r->_errno = ENOMEM; - OSUnlockMutex(file->dev->pMutex); - return 0; - } - size_t done = 0; - while(done < len) - { - size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); - memcpy(tmpBuf, ptr + done, write_size); - - int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); -#if 0 - FSFlushFile(file->dev->pClient, file->dev->pCmd, file->fd, -1); -#endif - if(result < 0) - { + /* fast path: buffer is already correctly aligned */ + if (!((uintptr_t)ptr & (FS_ALIGNMENT-1))) { + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, (uint8_t*)ptr, 1, len, file->fd, 0, -1); + if(result < 0) { r->_errno = result; - break; - } - else if(result == 0) - { - if(write_size > 0) - done = 0; - break; - } - else - { - done += result; + } else { + done = result; file->pos += result; } + } else { + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + while(done < len) + { + size_t write_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + memcpy(tmpBuf, ptr + done, write_size); + + int result = FSWriteFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, write_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + break; + } + else if(result == 0) + { + if(write_size > 0) + done = 0; + break; + } + else + { + done += result; + file->pos += result; + } + } + + free(tmpBuf); } - free(tmpBuf); OSUnlockMutex(file->dev->pMutex); return done; } @@ -340,44 +349,56 @@ static ssize_t sd_fat_read_r (struct _reent *r, void* fd, char *ptr, size_t len) OSLockMutex(file->dev->pMutex); - size_t len_aligned = FS_ALIGN(len); - if(len_aligned > 0x4000) - len_aligned = 0x4000; - - unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); - if(!tmpBuf) { - r->_errno = ENOMEM; - OSUnlockMutex(file->dev->pMutex); - return 0; - } - size_t done = 0; - while(done < len) - { - size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); - - int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); - if(result < 0) - { + /* fast path: buffer is already correctly aligned */ + if (!((uintptr_t)ptr & (FS_ALIGNMENT-1))) { + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, (uint8_t*)ptr, 1, len, file->fd, 0, -1); + if(result < 0) { r->_errno = result; - done = 0; - break; - } - else if(result == 0) - { - /*! TODO: error on read_size > 0 */ - break; - } - else - { - memcpy(ptr + done, tmpBuf, read_size); - done += result; + } else { + done = result; file->pos += result; } + } else { + size_t len_aligned = FS_ALIGN(len); + if(len_aligned > 0x4000) + len_aligned = 0x4000; + + unsigned char *tmpBuf = (unsigned char *)memalign(FS_ALIGNMENT, len_aligned); + if(!tmpBuf) { + r->_errno = ENOMEM; + OSUnlockMutex(file->dev->pMutex); + return 0; + } + + while(done < len) + { + size_t read_size = (len_aligned < (len - done)) ? len_aligned : (len - done); + + int result = FSReadFile(file->dev->pClient, file->dev->pCmd, tmpBuf, 0x01, read_size, file->fd, 0, -1); + if(result < 0) + { + r->_errno = result; + done = 0; + break; + } + else if(result == 0) + { + /*! TODO: error on read_size > 0 */ + break; + } + else + { + memcpy(ptr + done, tmpBuf, read_size); + done += result; + file->pos += result; + } + } + + free(tmpBuf); } - free(tmpBuf); OSUnlockMutex(file->dev->pMutex); return done; } diff --git a/wiiu/include/sys/socket.h b/wiiu/include/sys/socket.h index 24eabff7f1..45b2ea9bdc 100644 --- a/wiiu/include/sys/socket.h +++ b/wiiu/include/sys/socket.h @@ -21,6 +21,10 @@ extern "C" { /* #define MSG_DONTWAIT 0x0004 */ #define SO_REUSEADDR 0x0004 +#define SO_WINSCALE 0x0400 +#define SO_TCPSACK 0x0200 +#define SO_SNDBUF 0x1001 +#define SO_RCVBUF 0x1002 #define SO_NBIO 0x1014 #define SO_NONBLOCK 0x1016 @@ -70,6 +74,7 @@ int setsockopt(int sockfd, int level, int optname, const void *optval, socklen_t int shutdown(int sockfd, int how); int socket(int domain, int type, int protocol); int select(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, struct timeval *timeout); +int somemopt (int req_type, char* mem, unsigned int memlen, int flags); int socketlasterr(void); diff --git a/wiiu/include/wiiu/os/thread.h b/wiiu/include/wiiu/os/thread.h index b962b1acc5..a545185c60 100644 --- a/wiiu/include/wiiu/os/thread.h +++ b/wiiu/include/wiiu/os/thread.h @@ -133,7 +133,7 @@ typedef struct #define OS_THREAD_TAG 0x74487244u #pragma pack(push, 1) -typedef struct OSThread +typedef struct __attribute__ ((aligned (8))) OSThread { OSContext context; diff --git a/wiiu/system/imports.h b/wiiu/system/imports.h index e3685aaa1a..bfff0e860c 100644 --- a/wiiu/system/imports.h +++ b/wiiu/system/imports.h @@ -32,6 +32,7 @@ IMPORT(OSIsThreadTerminated); IMPORT(OSSetThreadPriority); IMPORT(OSCreateThread); IMPORT(OSSetThreadCleanupCallback); +IMPORT(OSSetThreadDeallocator); IMPORT(OSResumeThread); IMPORT(OSIsThreadSuspended); IMPORT(OSSuspendThread); @@ -39,6 +40,7 @@ IMPORT(OSGetCurrentThread); IMPORT(OSExitThread); IMPORT(OSJoinThread); IMPORT(OSYieldThread); +IMPORT(OSSetThreadName); IMPORT(OSGetCoreId); IMPORT(OSIsMainCore); IMPORT(OSGetSystemTime); @@ -153,6 +155,12 @@ IMPORT(socketlasterr); IMPORT_END(); +IMPORT_BEGIN(nn_nets2); + +IMPORT(somemopt); + +IMPORT_END(); + /* gx2 */ IMPORT_BEGIN(gx2);