commit
c978b53214
22
CHANGES.md
22
CHANGES.md
|
@ -1,15 +1,22 @@
|
|||
# 1.7.0 (future)
|
||||
# 1.7.1 (future)
|
||||
|
||||
# 1.7.0
|
||||
- CHEEVOS: Add badges for achievements, shows thumbnail images of achievements.
|
||||
- CHEEVOS: Leaderboard support.
|
||||
- CHEEVOS: Only disable savestates on hardcore mode if achievements are not available.
|
||||
- COMMANDLINE: Fix fullscreen toggle switch.
|
||||
- COMMON: Add 'Automatically Load Content To Playlist' feature, enabled by default.
|
||||
- COMMON: Fix slowmotion ratio always being reset back to 1.
|
||||
- COMMON: Optimized NBIO implementations now for Apple, Windows, and Linux. Uses mmap for Linux/Windows/BSD if/when available. File I/O should now be much faster for loading images inside the menu.
|
||||
- COMMON: Native Blissbox support now for latest firmware as of writing (2.0). Implementation through libusb and/or native Windows HID.
|
||||
- COMMON: New lightgun API.
|
||||
- COMMON: New VFS (Virtual File System) API.
|
||||
- COMMON: Fixed some playlist bugs.
|
||||
- COMMON: New snow shader.
|
||||
- COMMON: Fix Quick Menu title, no longer shows 'Select File'.
|
||||
- COMMON: Fix loading cores that require no content one after another.
|
||||
- COMMON: Map Delete key to Y button for non-unified menu keyboard controls.
|
||||
- COMMON: Fix for relative paths being normalised and generating a duplicate history entry.
|
||||
- EMSCRIPTEN: Fix references to browserfs.
|
||||
- FREEBSD: Support libusb HID input driver.
|
||||
- HAIKU: Buildfix.
|
||||
|
@ -21,20 +28,31 @@
|
|||
- LOCALIZATION: Update Italian translation.
|
||||
- LOCALIZATION: Update Japanese translation.
|
||||
- LOCALIZATION: Update Portuguese-Brazilian translation.
|
||||
- LOCALIZATION: Update Polish translation.
|
||||
- LOCALIZATION: Update Russian translation.
|
||||
- MENU: Snowflake menu shader effect.
|
||||
- OSX/PPC: Fix the GL2 renderchain, had to use EXT versions of framebuffer/renderbuffer functions.
|
||||
- PS3: HTTP requests / downloads should now work.
|
||||
- PS3: Core Updater now works.
|
||||
- PS3: Improved font rendering, enable STB Unicode font renderer.
|
||||
- PSP: Make it work with Vita's Adrenaline.
|
||||
- PSP: Fix audio sync.
|
||||
- PSP: Fix content loading, port should be functional again.
|
||||
- PSP: Us 64MB when available.
|
||||
- PSP: Use 64MB when available.
|
||||
- SCANNER: Fix crash from Windows-incompatible format string.
|
||||
- VITA: Improve packaging, installation times.
|
||||
- WIIU: Disabled the controller patcher for now since it was the source of many stability issues.
|
||||
- VULKAN: Various stability fixes for WSI.
|
||||
- WINDOWS: Add MSVC 2017 solution.
|
||||
- WINDOWS: Get rid of the empty console window in MSVC 2010 builds.
|
||||
- WINDOWS: Raw input driver now supports new lightgun code.
|
||||
- WINDOWS: Use configured OSD/text message color on GDI driver.
|
||||
- WINDOWS/XINPUT: Populate XInput VID/PID from DInput so autoconfig doesn't rely solely on joypad names
|
||||
- WINDOWS/XINPUT: Fix crash that occurs in some situations with Steam running and a Steam Controller plugged in.
|
||||
- WINDOWS: Improve version reporting under System Information.
|
||||
- WINDOWS: Support window transparency.
|
||||
- WINDOWS: Correct usage of GetWindowPlacement per MS docs, fixes game window position on Win95/98.
|
||||
- WINDOWS: Added Visual Studio 2017 support.
|
||||
|
||||
# 1.6.9
|
||||
- COMMON: Small memory leak.
|
||||
|
|
|
@ -1428,13 +1428,14 @@ ifeq ($(HAVE_BUILTINZLIB),1)
|
|||
$(DEPS_DIR)/libz/uncompr.o \
|
||||
$(DEPS_DIR)/libz/zutil.o
|
||||
else
|
||||
ifeq ($(HAVE_ZLIB),1)
|
||||
ifeq ($(HAVE_ZLIB), 1)
|
||||
OBJ += $(ZLIB_OBJS)
|
||||
endif
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_7ZIP),1)
|
||||
ifeq ($(HAVE_FLAC),1)
|
||||
ifeq ($(HAVE_7ZIP), 1)
|
||||
ifeq ($(HAVE_ZLIB), 1)
|
||||
ifeq ($(HAVE_FLAC), 1)
|
||||
DEFINES += -DHAVE_CHD -DWANT_SUBCODE -DWANT_RAW_DATA_SECTOR
|
||||
CFLAGS += -I$(LIBRETRO_COMM_DIR)/formats/libchdr
|
||||
OBJ += $(LIBRETRO_COMM_DIR)/formats/libchdr/bitstream.o \
|
||||
|
@ -1445,6 +1446,7 @@ ifeq ($(HAVE_FLAC),1)
|
|||
$(LIBRETRO_COMM_DIR)/streams/chd_stream.o
|
||||
endif
|
||||
endif
|
||||
endif
|
||||
|
||||
# Video4Linux 2
|
||||
|
||||
|
@ -1624,6 +1626,29 @@ OBJ += gfx/video_filters/2xsai.o \
|
|||
gfx/video_filters/phosphor2x.o
|
||||
endif
|
||||
|
||||
ifeq ($(WANT_IOSUHAX), 1)
|
||||
DEFINES += -I$(DEPS_DIR)/libiosuhax
|
||||
CFLAGS += -I$(DEPS_DIR)/libiosuhax
|
||||
OBJ += $(DEPS_DIR)/libiosuhax/iosuhax.o \
|
||||
$(DEPS_DIR)/libiosuhax/iosuhax_devoptab.o \
|
||||
$(DEPS_DIR)/libiosuhax/iosuhax_disc_interface.o
|
||||
endif
|
||||
|
||||
ifeq ($(WANT_LIBFAT), 1)
|
||||
DEFINES += -I$(DEPS_DIR)/libfat/include
|
||||
CFLAGS += -I$(DEPS_DIR)/libfat/include
|
||||
OBJ += $(DEPS_DIR)/libfat/cache.o \
|
||||
$(DEPS_DIR)/libfat/directory.o \
|
||||
$(DEPS_DIR)/libfat/disc.o \
|
||||
$(DEPS_DIR)/libfat/fatdir.o \
|
||||
$(DEPS_DIR)/libfat/fatfile.o \
|
||||
$(DEPS_DIR)/libfat/file_allocation_table.o \
|
||||
$(DEPS_DIR)/libfat/filetime.o \
|
||||
$(DEPS_DIR)/libfat/libfat.o \
|
||||
$(DEPS_DIR)/libfat/lock.o \
|
||||
$(DEPS_DIR)/libfat/partition.o
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_STATIC_AUDIO_FILTERS), 1)
|
||||
OBJ += libretro-common/audio/dsp_filters/echo.o \
|
||||
libretro-common/audio/dsp_filters/eq.o \
|
||||
|
|
|
@ -844,6 +844,7 @@ else ifeq ($(platform), vita)
|
|||
else ifneq (,$(findstring msvc,$(platform)))
|
||||
ifeq ($(platform), windows_msvc2003_x86)
|
||||
CFLAGS += -Wp64
|
||||
LDFLAGS += -SUBSYSTEM:WINDOWS -ENTRY:mainCRTStartup
|
||||
endif
|
||||
|
||||
CFLAGS += -O2 -DNDEBUG -MT -TP
|
||||
|
|
14
Makefile.ps3
14
Makefile.ps3
|
@ -63,7 +63,19 @@ endif
|
|||
|
||||
PPU_SRCS = griffin/griffin.c
|
||||
|
||||
DEFINES += -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DMSB_FIRST -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS
|
||||
DEFINES += -DHAVE_MENU -DHAVE_RGUI -DHAVE_XMB -DHAVE_LIBRETRODB -DHAVE_MATERIALUI -DHAVE_SHADERPIPELINE -DRARCH_INTERNAL -DMSB_FIRST -DHAVE_OVERLAY -DHAVE_CC_RESAMPLER -DHAVE_STB_VORBIS -DHAVE_STB_FONT
|
||||
|
||||
ifeq ($(DEX_BUILD), 1)
|
||||
DEFINES += -DDEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(CEX_BUILD), 1)
|
||||
DEFINES += -DCEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(ODE_BUILD), 1)
|
||||
DEFINES += -DODE_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCMGL), 1)
|
||||
DEFINES += -DHAVE_GCMGL
|
||||
|
|
|
@ -63,6 +63,18 @@ PPU_SRCS = griffin/griffin.c
|
|||
|
||||
DEFINES += -DHAVE_RGUI -DHAVE_MATERIALUI -DHAVE_XMB -DHAVE_MENU -DRARCH_INTERNAL
|
||||
|
||||
ifeq ($(DEX_BUILD), 1)
|
||||
DEFINES += -DDEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(CEX_BUILD), 1)
|
||||
DEFINES += -DCEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(ODE_BUILD), 1)
|
||||
DEFINES += -DODE_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(HAVE_GCMGL), 1)
|
||||
DEFINES += -DHAVE_GCMGL
|
||||
GL_LIBS := -L. -lrgl_ps3
|
||||
|
|
|
@ -27,6 +27,18 @@ STRIP = $(CELL_SDK)/host-win32/ppu/bin/ppu-lv2-strip.exe
|
|||
INCFLAGS = -I. -Idefines -Ilibretro-common/include -Ideps/libz
|
||||
DEFINES = -D__CELLOS_LV2__ -DIS_SALAMANDER -DRARCH_CONSOLE -DHAVE_SYSUTILS -DHAVE_SYSMODULES -DHAVE_RARCH_EXEC
|
||||
|
||||
ifeq ($(DEX_BUILD), 1)
|
||||
DEFINES += -DDEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(CEX_BUILD), 1)
|
||||
DEFINES += -DCEX_BUILD
|
||||
endif
|
||||
|
||||
ifeq ($(ODE_BUILD), 1)
|
||||
DEFINES += -DODE_BUILD
|
||||
endif
|
||||
|
||||
PPU_CFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
||||
PPU_CXXFLAGS := $(PPU_OPTIMIZE_LV) $(INCFLAGS) $(DEFINES)
|
||||
|
||||
|
|
|
@ -73,6 +73,8 @@ else
|
|||
# WANT_IFADDRS = 1
|
||||
HAVE_STATIC_VIDEO_FILTERS = 1
|
||||
HAVE_STATIC_AUDIO_FILTERS = 1
|
||||
WANT_LIBFAT = 1
|
||||
WANT_IOSUHAX = 1
|
||||
|
||||
include Makefile.common
|
||||
BLACKLIST :=
|
||||
|
@ -141,7 +143,7 @@ CFLAGS += -ffast-math -Werror=implicit-function-declaration
|
|||
#CFLAGS += -Wall
|
||||
|
||||
#todo: remove -DWIIU and use the built-in macros instead (HW_WUP or __wiiu__).
|
||||
CFLAGS += -DWIIU -DMSB_FIRST
|
||||
CFLAGS += -DWIIU -DMSB_FIRST -D__WUT__
|
||||
CFLAGS += -DHAVE_MAIN
|
||||
CFLAGS += -DHAVE_UPDATE_ASSETS
|
||||
CFLAGS += -DRARCH_INTERNAL -DRARCH_CONSOLE
|
||||
|
@ -166,7 +168,15 @@ CXXFLAGS := $(CFLAGS) -fno-rtti -fno-exceptions -D_GNU_SOURCE
|
|||
|
||||
LDFLAGS += -Wl,--gc-sections
|
||||
|
||||
LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm -lfat -liosuhax
|
||||
LIBS := $(WHOLE_START) -lretro_wiiu $(WHOLE_END) -lm
|
||||
|
||||
ifneq ($(WANT_LIBFAT), 1)
|
||||
LIBS += -lfat
|
||||
endif
|
||||
|
||||
ifneq ($(WANT_IOSUHAX), 1)
|
||||
LIBS += -liosuhax
|
||||
endif
|
||||
|
||||
|
||||
RPX_OBJ = wiiu/system/stubs_rpl.o
|
||||
|
|
|
@ -63,6 +63,7 @@ RetroArch also emphasizes on being easy to integrate into various launcher front
|
|||
|
||||
RetroArch has been ported to the following platforms:
|
||||
|
||||
- DOS
|
||||
- Windows
|
||||
- Linux
|
||||
- FreeBSD
|
||||
|
|
|
@ -45,6 +45,12 @@ typedef struct xaudio2 xaudio2_t;
|
|||
|
||||
#define MAX_BUFFERS_MASK (MAX_BUFFERS - 1)
|
||||
|
||||
#ifndef COINIT_MULTITHREADED
|
||||
#define COINIT_MULTITHREADED 0x00
|
||||
#endif
|
||||
|
||||
#define XAUDIO2_WRITE_AVAILABLE(handle) ((handle)->bufsize * (MAX_BUFFERS - (handle)->buffers - 1))
|
||||
|
||||
typedef struct
|
||||
{
|
||||
xaudio2_t *xa;
|
||||
|
@ -190,10 +196,6 @@ static void xaudio2_free(xaudio2_t *handle)
|
|||
#endif
|
||||
}
|
||||
|
||||
#ifndef COINIT_MULTITHREADED
|
||||
#define COINIT_MULTITHREADED 0x00
|
||||
#endif
|
||||
|
||||
static xaudio2_t *xaudio2_new(unsigned samplerate, unsigned channels,
|
||||
size_t size, unsigned device)
|
||||
{
|
||||
|
@ -251,15 +253,9 @@ error:
|
|||
return NULL;
|
||||
}
|
||||
|
||||
static size_t xaudio2_write_avail(xaudio2_t *handle)
|
||||
{
|
||||
return handle->bufsize * (MAX_BUFFERS - handle->buffers - 1);
|
||||
}
|
||||
|
||||
static size_t xaudio2_write(xaudio2_t *handle, const void *buf, size_t bytes_)
|
||||
static size_t xaudio2_write(xaudio2_t *handle, const uint8_t *buffer, size_t bytes_)
|
||||
{
|
||||
unsigned bytes = bytes_;
|
||||
const uint8_t *buffer = (const uint8_t*)buf;
|
||||
|
||||
while (bytes)
|
||||
{
|
||||
|
@ -344,7 +340,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size)
|
|||
|
||||
if (xa->nonblock)
|
||||
{
|
||||
size_t avail = xaudio2_write_avail(xa->xa);
|
||||
size_t avail = XAUDIO2_WRITE_AVAILABLE(xa->xa);
|
||||
|
||||
if (avail == 0)
|
||||
return 0;
|
||||
|
@ -352,7 +348,7 @@ static ssize_t xa_write(void *data, const void *buf, size_t size)
|
|||
size = avail;
|
||||
}
|
||||
|
||||
ret = xaudio2_write(xa->xa, buf, size);
|
||||
ret = xaudio2_write(xa->xa, (const uint8_t*)buf, size);
|
||||
if (ret == 0 && size > 0)
|
||||
return -1;
|
||||
return ret;
|
||||
|
@ -408,7 +404,7 @@ static void xa_free(void *data)
|
|||
static size_t xa_write_avail(void *data)
|
||||
{
|
||||
xa_t *xa = (xa_t*)data;
|
||||
return xaudio2_write_avail(xa->xa);
|
||||
return XAUDIO2_WRITE_AVAILABLE(xa->xa);
|
||||
}
|
||||
|
||||
static size_t xa_buffer_size(void *data)
|
||||
|
|
|
@ -55,9 +55,10 @@ void exitspawn_kernel(const char *fileName, SceSize args, void *argp)
|
|||
game_param.unk4 = 0;
|
||||
game_param.unk5 = 0x10000;
|
||||
|
||||
pspSdkSetK1(0);
|
||||
sceKernelSuspendAllUserThreads();
|
||||
sceKernelLoadExecVSHMs2(fileName, &game_param);
|
||||
int k1 = pspSdkSetK1(0);
|
||||
//sceKernelSuspendAllUserThreads();
|
||||
int ret = sceKernelLoadExecVSHMs2(fileName, &game_param);
|
||||
pspSdkSetK1(k1);
|
||||
}
|
||||
|
||||
int module_start(SceSize args, void *argp)
|
||||
|
|
16
command.c
16
command.c
|
@ -1957,6 +1957,10 @@ bool command_event(enum event_command cmd, void *data)
|
|||
cheevos_toggle_hardcore_mode();
|
||||
#endif
|
||||
break;
|
||||
/* this fallthrough is on purpose, it should do
|
||||
a CMD_EVENT_REINIT too */
|
||||
case CMD_EVENT_REINIT_FROM_TOGGLE:
|
||||
retroarch_unset_forced_fullscreen();
|
||||
case CMD_EVENT_REINIT:
|
||||
video_driver_reinit();
|
||||
/* Poll input to avoid possibly stale data to corrupt things. */
|
||||
|
@ -2567,15 +2571,21 @@ TODO: Add a setting for these tweaks */
|
|||
case CMD_EVENT_FULLSCREEN_TOGGLE:
|
||||
{
|
||||
settings_t *settings = config_get_ptr();
|
||||
bool new_fullscreen_state = !settings->bools.video_fullscreen;
|
||||
bool new_fullscreen_state = !settings->bools.video_fullscreen
|
||||
&& !retroarch_is_forced_fullscreen();
|
||||
if (!video_driver_has_windowed())
|
||||
return false;
|
||||
|
||||
/* If we go fullscreen we drop all drivers and
|
||||
* reinitialize to be safe. */
|
||||
/* we toggled manually, write the new value to settings */
|
||||
configuration_set_bool(settings, settings->bools.video_fullscreen,
|
||||
new_fullscreen_state);
|
||||
|
||||
/* we toggled manually, the cli arg is irrelevant now */
|
||||
if (retroarch_is_forced_fullscreen())
|
||||
retroarch_unset_forced_fullscreen();
|
||||
|
||||
/* If we go fullscreen we drop all drivers and
|
||||
* reinitialize to be safe. */
|
||||
command_event(CMD_EVENT_REINIT, NULL);
|
||||
if (settings->bools.video_fullscreen)
|
||||
video_driver_hide_mouse();
|
||||
|
|
|
@ -61,6 +61,8 @@ enum event_command
|
|||
/* Quits RetroArch. */
|
||||
CMD_EVENT_QUIT,
|
||||
/* Reinitialize all drivers. */
|
||||
CMD_EVENT_REINIT_FROM_TOGGLE,
|
||||
/* Reinitialize all drivers. */
|
||||
CMD_EVENT_REINIT,
|
||||
/* Toggles cheevos hardcore mode. */
|
||||
CMD_EVENT_CHEEVOS_HARDCORE_MODE_TOGGLE,
|
||||
|
|
10
config.def.h
10
config.def.h
|
@ -298,11 +298,7 @@ static bool xmb_show_add = true;
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#if defined(HAVE_LIBRETRODB) && !defined(RARCH_CONSOLE) && !defined(EMSCRIPTEN)
|
||||
static bool automatically_add_content_to_playlist = true;
|
||||
#else
|
||||
static bool automatically_add_content_to_playlist = false;
|
||||
#endif
|
||||
|
||||
static float menu_framebuffer_opacity = 0.900;
|
||||
|
||||
|
@ -689,6 +685,12 @@ static char buildbot_server_url[] = "";
|
|||
#endif
|
||||
#elif defined(WIIU)
|
||||
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/nintendo/wiiu/latest/";
|
||||
#elif defined(__CELLOS_LV2__) && defined(DEX_BUILD)
|
||||
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/dex-ps3/";
|
||||
#elif defined(__CELLOS_LV2__) && defined(CEX_BUILD)
|
||||
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/cex-ps3/";
|
||||
#elif defined(__CELLOS_LV2__) && defined(ODE_BUILD)
|
||||
static char buildbot_server_url[] = "http://buildbot.libretro.com/nightly/playstation/ps3/latest/ode-ps3/";
|
||||
#else
|
||||
static char buildbot_server_url[] = "";
|
||||
#endif
|
||||
|
|
|
@ -1578,11 +1578,6 @@ static void config_set_defaults(void)
|
|||
#endif
|
||||
settings->floats.video_scale = scale;
|
||||
|
||||
if (retroarch_is_forced_fullscreen())
|
||||
{
|
||||
configuration_set_bool(settings, settings->bools.video_fullscreen, true);
|
||||
}
|
||||
|
||||
if (g_defaults.settings.video_threaded_enable != video_threaded)
|
||||
video_driver_set_threaded(g_defaults.settings.video_threaded_enable);
|
||||
|
||||
|
@ -2377,9 +2372,6 @@ static bool config_load_file(const char *path, bool set_defaults,
|
|||
*bool_settings[i].ptr = tmp;
|
||||
}
|
||||
|
||||
if (!retroarch_is_forced_fullscreen())
|
||||
CONFIG_GET_BOOL_BASE(conf, settings, bools.video_fullscreen, "video_fullscreen");
|
||||
|
||||
#ifdef HAVE_NETWORKGAMEPAD
|
||||
for (i = 0; i < MAX_USERS; i++)
|
||||
{
|
||||
|
|
|
@ -272,7 +272,7 @@ void CORE_PREFIX(retro_set_environment)(retro_environment_t cb)
|
|||
{
|
||||
static const struct retro_variable vars[] = {
|
||||
#if defined(HAVE_OPENGL) || defined(HAVE_OPENGLES)
|
||||
{ "ffmpeg_temporal_interp", "Temporal Interpolation; enabled|disabled" },
|
||||
{ "ffmpeg_temporal_interp", "Temporal Interpolation; disabled|enabled" },
|
||||
#ifdef HAVE_GL_FFT
|
||||
{ "ffmpeg_fft_resolution", "FFT Resolution; 1280x720|1920x1080|2560x1440|3840x2160|640x360|320x180" },
|
||||
{ "ffmpeg_fft_multisample", "FFT Multisample; 1x|2x|4x" },
|
||||
|
|
|
@ -1,20 +1,20 @@
|
|||
image_core.so: image_core.c
|
||||
gcc \
|
||||
-g \
|
||||
-DHAVE_STB_IMAGE \
|
||||
image_core.c \
|
||||
../../libretro-common/file/file_path.c \
|
||||
../../libretro-common/lists/dir_list.c \
|
||||
../../libretro-common/compat/compat_strl.c \
|
||||
-I../../libretro-common/include/ \
|
||||
-I../../deps/stb/ \
|
||||
../../libretro-common/compat/compat_strcasestr.c \
|
||||
../../libretro-common/lists/string_list.c \
|
||||
../../libretro-common/compat/compat_strl.c \
|
||||
../../libretro-common/file/file_path.c \
|
||||
../../libretro-common/file/retro_dirent.c \
|
||||
../../libretro-common/lists/dir_list.c \
|
||||
../../libretro-common/lists/string_list.c \
|
||||
../../libretro-common/streams/file_stream.c \
|
||||
../../libretro-common/vfs/vfs_implementation.c \
|
||||
-o image_core.so \
|
||||
-DHAVE_STB_IMAGE \
|
||||
-I ../../libretro-common/include/ \
|
||||
-I../../deps/stb \
|
||||
-Wl,--no-undefined \
|
||||
-shared \
|
||||
-fPIC \
|
||||
-lm
|
||||
-Wl,--no-undefined \
|
||||
-lm \
|
||||
-o image_core.so
|
||||
|
|
|
@ -307,11 +307,17 @@ void GPU_FinishDrawing()
|
|||
GPUCMD_AddWrite(GPUREG_EARLYDEPTH_CLEAR, 0x00000001);
|
||||
}
|
||||
|
||||
void GPUCMD_Finalize(void)
|
||||
|
||||
void GPU_Finalize(void)
|
||||
{
|
||||
GPUCMD_AddMaskedWrite(GPUREG_PRIMITIVE_CONFIG, 0x8, 0x00000000);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_FLUSH, 0x00000001);
|
||||
GPUCMD_AddWrite(GPUREG_FRAMEBUFFER_INVALIDATE, 0x00000001);
|
||||
#if 0
|
||||
GPUCMD_Split(NULL, NULL);
|
||||
#else
|
||||
GPUCMD_AddWrite(GPUREG_FINALIZE, 0x12345678);
|
||||
GPUCMD_AddWrite(GPUREG_FINALIZE, 0x12345678); //not the cleanest way of guaranteeing 0x10-byte size but whatever good enough for now
|
||||
//not the cleanest way of guaranteeing 0x10-byte size but whatever good enough for now
|
||||
GPUCMD_AddWrite(GPUREG_FINALIZE,0x12345678);
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -236,5 +236,4 @@ void GPU_DrawElements(GPU_Primitive_t primitive, u32* indexArray, u32 n) DEPRECA
|
|||
*/
|
||||
void GPU_FinishDrawing() DEPRECATED;
|
||||
|
||||
/// Finalizes the GPU command buffer.
|
||||
void GPUCMD_Finalize(void) DEPRECATED;
|
||||
void GPU_Finalize(void) DEPRECATED;
|
||||
|
|
|
@ -0,0 +1,61 @@
|
|||
/*
|
||||
bit_ops.h
|
||||
Functions for dealing with conversion of data between types
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _BIT_OPS_H
|
||||
#define _BIT_OPS_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
Functions to deal with little endian values stored in uint8_t arrays
|
||||
-----------------------------------------------------------------*/
|
||||
static inline uint16_t u8array_to_u16 (const uint8_t* item, int offset)
|
||||
{
|
||||
return ( item[offset] | (item[offset + 1] << 8));
|
||||
}
|
||||
|
||||
static inline uint32_t u8array_to_u32 (const uint8_t* item, int offset)
|
||||
{
|
||||
return ( item[offset] | (item[offset + 1] << 8) | (item[offset + 2] << 16) | (item[offset + 3] << 24));
|
||||
}
|
||||
|
||||
static inline void u16_to_u8array (uint8_t* item, int offset, uint16_t value)
|
||||
{
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
}
|
||||
|
||||
static inline void u32_to_u8array (uint8_t* item, int offset, uint32_t value)
|
||||
{
|
||||
item[offset] = (uint8_t) value;
|
||||
item[offset + 1] = (uint8_t)(value >> 8);
|
||||
item[offset + 2] = (uint8_t)(value >> 16);
|
||||
item[offset + 3] = (uint8_t)(value >> 24);
|
||||
}
|
||||
|
||||
#endif /* _BIT_OPS_H */
|
|
@ -0,0 +1,336 @@
|
|||
/*
|
||||
cache.c
|
||||
The cache is not visible to the user. It should be flushed
|
||||
when any file is closed or changes are made to the filesystem.
|
||||
|
||||
This cache implements a least-used-page replacement policy. This will
|
||||
distribute sectors evenly over the pages, so if less than the maximum
|
||||
pages are used at once, they should all eventually remain in the cache.
|
||||
This also has the benefit of throwing out old sectors, so as not to keep
|
||||
too many stale pages around.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "cache.h"
|
||||
#include "disc.h"
|
||||
|
||||
#include "mem_allocate.h"
|
||||
#include "bit_ops.h"
|
||||
#include "file_allocation_table.h"
|
||||
|
||||
#define CACHE_FREE UINT_MAX
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector)
|
||||
{
|
||||
CACHE* cache;
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
|
||||
if (numberOfPages < 2)
|
||||
numberOfPages = 2;
|
||||
|
||||
if (sectorsPerPage < 8)
|
||||
sectorsPerPage = 8;
|
||||
|
||||
cache = (CACHE*) _FAT_mem_allocate (sizeof(CACHE));
|
||||
if (cache == NULL)
|
||||
return NULL;
|
||||
|
||||
cache->disc = discInterface;
|
||||
cache->endOfPartition = endOfPartition;
|
||||
cache->numberOfPages = numberOfPages;
|
||||
cache->sectorsPerPage = sectorsPerPage;
|
||||
cache->bytesPerSector = bytesPerSector;
|
||||
|
||||
|
||||
cacheEntries = (CACHE_ENTRY*) _FAT_mem_allocate ( sizeof(CACHE_ENTRY) * numberOfPages);
|
||||
if (cacheEntries == NULL)
|
||||
{
|
||||
_FAT_mem_free (cache);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
for (i = 0; i < numberOfPages; i++)
|
||||
{
|
||||
cacheEntries[i].sector = CACHE_FREE;
|
||||
cacheEntries[i].count = 0;
|
||||
cacheEntries[i].last_access = 0;
|
||||
cacheEntries[i].dirty = false;
|
||||
cacheEntries[i].cache = (uint8_t*) _FAT_mem_align ( sectorsPerPage * bytesPerSector );
|
||||
}
|
||||
|
||||
cache->cacheEntries = cacheEntries;
|
||||
|
||||
return cache;
|
||||
}
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
/* Clear out cache before destroying it */
|
||||
_FAT_cache_flush(cache);
|
||||
|
||||
/* Free memory in reverse allocation order */
|
||||
for (i = 0; i < cache->numberOfPages; i++)
|
||||
_FAT_mem_free (cache->cacheEntries[i].cache);
|
||||
_FAT_mem_free (cache->cacheEntries);
|
||||
_FAT_mem_free (cache);
|
||||
}
|
||||
|
||||
|
||||
static u32 accessCounter = 0;
|
||||
|
||||
static u32 accessTime(){
|
||||
accessCounter++;
|
||||
return accessCounter;
|
||||
}
|
||||
|
||||
|
||||
static CACHE_ENTRY* _FAT_cache_getPage(CACHE *cache,sec_t sector)
|
||||
{
|
||||
unsigned int i;
|
||||
CACHE_ENTRY* cacheEntries = cache->cacheEntries;
|
||||
unsigned int numberOfPages = cache->numberOfPages;
|
||||
unsigned int sectorsPerPage = cache->sectorsPerPage;
|
||||
|
||||
bool foundFree = false;
|
||||
unsigned int oldUsed = 0;
|
||||
unsigned int oldAccess = UINT_MAX;
|
||||
|
||||
for(i=0;i<numberOfPages;i++)
|
||||
{
|
||||
if(sector>=cacheEntries[i].sector && sector<(cacheEntries[i].sector + cacheEntries[i].count))
|
||||
{
|
||||
cacheEntries[i].last_access = accessTime();
|
||||
return &(cacheEntries[i]);
|
||||
}
|
||||
|
||||
if(foundFree==false && (cacheEntries[i].sector==CACHE_FREE || cacheEntries[i].last_access<oldAccess))
|
||||
{
|
||||
if(cacheEntries[i].sector==CACHE_FREE) foundFree = true;
|
||||
oldUsed = i;
|
||||
oldAccess = cacheEntries[i].last_access;
|
||||
}
|
||||
}
|
||||
|
||||
if(foundFree==false && cacheEntries[oldUsed].dirty==true)
|
||||
{
|
||||
if(!_FAT_disc_writeSectors(cache->disc,cacheEntries[oldUsed].sector,cacheEntries[oldUsed].count,cacheEntries[oldUsed].cache)) return NULL;
|
||||
cacheEntries[oldUsed].dirty = false;
|
||||
}
|
||||
|
||||
sector = (sector/sectorsPerPage)*sectorsPerPage; /* align base sector to page size */
|
||||
sec_t next_page = sector + sectorsPerPage;
|
||||
if(next_page > cache->endOfPartition) next_page = cache->endOfPartition;
|
||||
|
||||
if(!_FAT_disc_readSectors(cache->disc,sector,next_page-sector,cacheEntries[oldUsed].cache)) return NULL;
|
||||
|
||||
cacheEntries[oldUsed].sector = sector;
|
||||
cacheEntries[oldUsed].count = next_page-sector;
|
||||
cacheEntries[oldUsed].last_access = accessTime();
|
||||
|
||||
return &(cacheEntries[oldUsed]);
|
||||
}
|
||||
|
||||
bool _FAT_cache_readSectors(CACHE *cache,sec_t sector,sec_t numSectors,void *buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_read;
|
||||
CACHE_ENTRY *entry;
|
||||
uint8_t *dest = (uint8_t *)buffer;
|
||||
|
||||
while(numSectors>0)
|
||||
{
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_read = entry->count - sec;
|
||||
if(secs_to_read>numSectors) secs_to_read = numSectors;
|
||||
|
||||
memcpy(dest,entry->cache + (sec*cache->bytesPerSector),(secs_to_read*cache->bytesPerSector));
|
||||
|
||||
dest += (secs_to_read*cache->bytesPerSector);
|
||||
sector += secs_to_read;
|
||||
numSectors -= secs_to_read;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Reads some data from a cache page, determined by the sector number
|
||||
*/
|
||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->bytesPerSector) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(buffer,entry->cache + ((sec*cache->bytesPerSector) + offset),size);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes)
|
||||
{
|
||||
uint8_t buf[4];
|
||||
if (!_FAT_cache_readPartialSector(cache, buf, sector, offset, num_bytes)) return false;
|
||||
|
||||
switch(num_bytes)
|
||||
{
|
||||
case 1: *value = buf[0]; break;
|
||||
case 2: *value = u8array_to_u16(buf,0); break;
|
||||
case 4: *value = u8array_to_u32(buf,0); break;
|
||||
default: return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, making sure it is loaded into memory first.
|
||||
*/
|
||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->bytesPerSector) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size);
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int size)
|
||||
{
|
||||
uint8_t buf[4] = {0, 0, 0, 0};
|
||||
|
||||
switch(size)
|
||||
{
|
||||
case 1: buf[0] = value; break;
|
||||
case 2: u16_to_u8array(buf, 0, value); break;
|
||||
case 4: u32_to_u8array(buf, 0, value); break;
|
||||
default: return false;
|
||||
}
|
||||
|
||||
return _FAT_cache_writePartialSector(cache, buf, sector, offset, size);
|
||||
}
|
||||
|
||||
/*
|
||||
Writes some data to a cache page, zeroing out the page first
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size)
|
||||
{
|
||||
sec_t sec;
|
||||
CACHE_ENTRY *entry;
|
||||
|
||||
if (offset + size > cache->bytesPerSector) return false;
|
||||
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
memset(entry->cache + (sec*cache->bytesPerSector),0,cache->bytesPerSector);
|
||||
memcpy(entry->cache + ((sec*cache->bytesPerSector) + offset),buffer,size);
|
||||
|
||||
entry->dirty = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
{
|
||||
sec_t sec;
|
||||
sec_t secs_to_write;
|
||||
CACHE_ENTRY* entry;
|
||||
const uint8_t *src = (const uint8_t *)buffer;
|
||||
|
||||
while(numSectors>0)
|
||||
{
|
||||
entry = _FAT_cache_getPage(cache,sector);
|
||||
if(entry==NULL) return false;
|
||||
|
||||
sec = sector - entry->sector;
|
||||
secs_to_write = entry->count - sec;
|
||||
if(secs_to_write>numSectors) secs_to_write = numSectors;
|
||||
|
||||
memcpy(entry->cache + (sec*cache->bytesPerSector),src,(secs_to_write*cache->bytesPerSector));
|
||||
|
||||
src += (secs_to_write*cache->bytesPerSector);
|
||||
sector += secs_to_write;
|
||||
numSectors -= secs_to_write;
|
||||
|
||||
entry->dirty = true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
/*
|
||||
Flushes all dirty pages to disc, clearing the dirty flag.
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
for (i = 0; i < cache->numberOfPages; i++)
|
||||
{
|
||||
if (cache->cacheEntries[i].dirty)
|
||||
{
|
||||
if (!_FAT_disc_writeSectors (cache->disc, cache->cacheEntries[i].sector, cache->cacheEntries[i].count, cache->cacheEntries[i].cache))
|
||||
return false;
|
||||
}
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void _FAT_cache_invalidate (CACHE* cache)
|
||||
{
|
||||
unsigned int i;
|
||||
_FAT_cache_flush(cache);
|
||||
for (i = 0; i < cache->numberOfPages; i++)
|
||||
{
|
||||
cache->cacheEntries[i].sector = CACHE_FREE;
|
||||
cache->cacheEntries[i].last_access = 0;
|
||||
cache->cacheEntries[i].count = 0;
|
||||
cache->cacheEntries[i].dirty = false;
|
||||
}
|
||||
}
|
|
@ -0,0 +1,128 @@
|
|||
/*
|
||||
cache.h
|
||||
The cache is not visible to the user. It should be flushed
|
||||
when any file is closed or changes are made to the filesystem.
|
||||
|
||||
This cache implements a least-used-page replacement policy. This will
|
||||
distribute sectors evenly over the pages, so if less than the maximum
|
||||
pages are used at once, they should all eventually remain in the cache.
|
||||
This also has the benefit of throwing out old sectors, so as not to keep
|
||||
too many stale pages around.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _CACHE_H
|
||||
#define _CACHE_H
|
||||
|
||||
#include "common.h"
|
||||
#include "disc.h"
|
||||
|
||||
typedef struct {
|
||||
sec_t sector;
|
||||
unsigned int count;
|
||||
unsigned int last_access;
|
||||
bool dirty;
|
||||
uint8_t* cache;
|
||||
} CACHE_ENTRY;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
sec_t endOfPartition;
|
||||
unsigned int numberOfPages;
|
||||
unsigned int sectorsPerPage;
|
||||
unsigned int bytesPerSector;
|
||||
CACHE_ENTRY* cacheEntries;
|
||||
} CACHE;
|
||||
|
||||
/*
|
||||
Read data from a sector in the cache
|
||||
If the sector is not in the cache, it will be swapped in
|
||||
offset is the position to start reading from
|
||||
size is the amount of data to read
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_readPartialSector (CACHE* cache, void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
|
||||
bool _FAT_cache_readLittleEndianValue (CACHE* cache, uint32_t *value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache
|
||||
If the sector is not in the cache, it will be swapped in.
|
||||
When the sector is swapped out, the data will be written to the disc
|
||||
offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_writePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
|
||||
bool _FAT_cache_writeLittleEndianValue (CACHE* cache, const uint32_t value, sec_t sector, unsigned int offset, int num_bytes);
|
||||
|
||||
/*
|
||||
Write data to a sector in the cache, zeroing the sector first
|
||||
If the sector is not in the cache, it will be swapped in.
|
||||
When the sector is swapped out, the data will be written to the disc
|
||||
offset is the position to start writing to
|
||||
size is the amount of data to write
|
||||
Precondition: offset + size <= BYTES_PER_READ
|
||||
*/
|
||||
bool _FAT_cache_eraseWritePartialSector (CACHE* cache, const void* buffer, sec_t sector, unsigned int offset, size_t size);
|
||||
|
||||
/*
|
||||
Read several sectors from the cache
|
||||
*/
|
||||
bool _FAT_cache_readSectors (CACHE* cache, sec_t sector, sec_t numSectors, void* buffer);
|
||||
|
||||
/*
|
||||
Read a full sector from the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_readSector (CACHE* cache, void* buffer, sec_t sector) {
|
||||
return _FAT_cache_readPartialSector (cache, buffer, sector, 0, cache->bytesPerSector);
|
||||
}
|
||||
|
||||
/*
|
||||
Write a full sector to the cache
|
||||
*/
|
||||
static inline bool _FAT_cache_writeSector (CACHE* cache, const void* buffer, sec_t sector) {
|
||||
return _FAT_cache_writePartialSector (cache, buffer, sector, 0, cache->bytesPerSector);
|
||||
}
|
||||
|
||||
bool _FAT_cache_writeSectors (CACHE* cache, sec_t sector, sec_t numSectors, const void* buffer);
|
||||
|
||||
/*
|
||||
Write any dirty sectors back to disc and clear out the contents of the cache
|
||||
*/
|
||||
bool _FAT_cache_flush (CACHE* cache);
|
||||
|
||||
/*
|
||||
Clear out the contents of the cache without writing any dirty sectors first
|
||||
*/
|
||||
void _FAT_cache_invalidate (CACHE* cache);
|
||||
|
||||
CACHE* _FAT_cache_constructor (unsigned int numberOfPages, unsigned int sectorsPerPage, const DISC_INTERFACE* discInterface, sec_t endOfPartition, unsigned int bytesPerSector);
|
||||
|
||||
void _FAT_cache_destructor (CACHE* cache);
|
||||
|
||||
#endif // _CACHE_H
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
/*
|
||||
common.h
|
||||
Common definitions and included files for the FATlib
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _COMMON_H
|
||||
#define _COMMON_H
|
||||
|
||||
#include <fat.h>
|
||||
#include <stddef.h>
|
||||
#include <stdint.h>
|
||||
|
||||
/* When compiling for NDS, make sure NDS is defined */
|
||||
#ifndef NDS
|
||||
#if defined ARM9 || defined ARM7
|
||||
#define NDS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
/* Platform specific includes */
|
||||
#if defined (__wiiu__)
|
||||
#include <iosuhax_disc_interface.h>
|
||||
typedef uint8_t u8;
|
||||
typedef uint16_t u16;
|
||||
typedef int32_t s32;
|
||||
typedef uint32_t u32;
|
||||
typedef int mutex_t;
|
||||
#elif defined(__gamecube__) || defined (__wii__)
|
||||
#include <gctypes.h>
|
||||
#include <ogc/disc_io.h>
|
||||
#include <gccore.h>
|
||||
#elif defined(NDS)
|
||||
#include <nds/ndstypes.h>
|
||||
#include <nds/system.h>
|
||||
#include <nds/disc_io.h>
|
||||
#elif defined(GBA)
|
||||
#include <gba_types.h>
|
||||
#include <disc_io.h>
|
||||
#endif
|
||||
|
||||
/* Platform specific options */
|
||||
#if defined (__wiiu__)
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 64
|
||||
#if 0
|
||||
#define USE_LWP_LOCK
|
||||
#define USE_RTC_TIME
|
||||
#endif
|
||||
#elif defined (__wii__)
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 64
|
||||
#define USE_LWP_LOCK
|
||||
#define USE_RTC_TIME
|
||||
#elif defined (__gamecube__)
|
||||
#define DEFAULT_CACHE_PAGES 4
|
||||
#define DEFAULT_SECTORS_PAGE 64
|
||||
#define USE_LWP_LOCK
|
||||
#define USE_RTC_TIME
|
||||
#elif defined (NDS)
|
||||
#define DEFAULT_CACHE_PAGES 16
|
||||
#define DEFAULT_SECTORS_PAGE 8
|
||||
#define USE_RTC_TIME
|
||||
#elif defined (GBA)
|
||||
#define DEFAULT_CACHE_PAGES 2
|
||||
#define DEFAULT_SECTORS_PAGE 8
|
||||
#define LIMIT_SECTORS 128
|
||||
#endif
|
||||
|
||||
#endif /* _COMMON_H */
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,181 @@
|
|||
/*
|
||||
directory.h
|
||||
Reading, writing and manipulation of the directory structure on
|
||||
a FAT partition
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _DIRECTORY_H
|
||||
#define _DIRECTORY_H
|
||||
|
||||
#include <sys/stat.h>
|
||||
#include <sys/syslimits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "partition.h"
|
||||
|
||||
#define DIR_ENTRY_DATA_SIZE 0x20
|
||||
#define MAX_LFN_LENGTH 256
|
||||
#define MAX_ALIAS_LENGTH 13
|
||||
#define LFN_ENTRY_LENGTH 13
|
||||
#define ALIAS_ENTRY_LENGTH 11
|
||||
#define MAX_ALIAS_EXT_LENGTH 3
|
||||
#define MAX_ALIAS_PRI_LENGTH 8
|
||||
#define MAX_NUMERIC_TAIL 999999
|
||||
#define FAT16_ROOT_DIR_CLUSTER 0
|
||||
|
||||
#define DIR_SEPARATOR '/'
|
||||
|
||||
/* File attributes */
|
||||
#define ATTRIB_ARCH 0x20 /* Archive */
|
||||
#define ATTRIB_DIR 0x10 /* Directory */
|
||||
#define ATTRIB_LFN 0x0F /* Long file name */
|
||||
#define ATTRIB_VOL 0x08 /* Volume */
|
||||
#define ATTRIB_SYS 0x04 /* System */
|
||||
#define ATTRIB_HID 0x02 /* Hidden */
|
||||
#define ATTRIB_RO 0x01 /* Read only */
|
||||
|
||||
#define CASE_LOWER_EXT 0x10 /* WinNT lowercase extension */
|
||||
#define CASE_LOWER_BASE 0x08 /* WinNT lowercase basename */
|
||||
|
||||
typedef enum {FT_DIRECTORY, FT_FILE} FILE_TYPE;
|
||||
|
||||
typedef struct {
|
||||
uint32_t cluster;
|
||||
sec_t sector;
|
||||
int32_t offset;
|
||||
} DIR_ENTRY_POSITION;
|
||||
|
||||
typedef struct {
|
||||
uint8_t entryData[DIR_ENTRY_DATA_SIZE];
|
||||
DIR_ENTRY_POSITION dataStart; /* Points to the start of the LFN entries of a file, or the alias for no LFN */
|
||||
DIR_ENTRY_POSITION dataEnd; /* Always points to the file/directory's alias entry */
|
||||
char filename[NAME_MAX];
|
||||
} DIR_ENTRY;
|
||||
|
||||
/* Directory entry offsets */
|
||||
enum DIR_ENTRY_offset {
|
||||
DIR_ENTRY_name = 0x00,
|
||||
DIR_ENTRY_extension = 0x08,
|
||||
DIR_ENTRY_attributes = 0x0B,
|
||||
DIR_ENTRY_caseInfo = 0x0C,
|
||||
DIR_ENTRY_cTime_ms = 0x0D,
|
||||
DIR_ENTRY_cTime = 0x0E,
|
||||
DIR_ENTRY_cDate = 0x10,
|
||||
DIR_ENTRY_aDate = 0x12,
|
||||
DIR_ENTRY_clusterHigh = 0x14,
|
||||
DIR_ENTRY_mTime = 0x16,
|
||||
DIR_ENTRY_mDate = 0x18,
|
||||
DIR_ENTRY_cluster = 0x1A,
|
||||
DIR_ENTRY_fileSize = 0x1C
|
||||
};
|
||||
|
||||
/*
|
||||
Returns true if the file specified by entry is a directory
|
||||
*/
|
||||
static inline bool _FAT_directory_isDirectory (DIR_ENTRY* entry) {
|
||||
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_DIR) != 0);
|
||||
}
|
||||
|
||||
static inline bool _FAT_directory_isWritable (DIR_ENTRY* entry) {
|
||||
return ((entry->entryData[DIR_ENTRY_attributes] & ATTRIB_RO) == 0);
|
||||
}
|
||||
|
||||
static inline bool _FAT_directory_isDot (DIR_ENTRY* entry) {
|
||||
return ((entry->filename[0] == '.') && ((entry->filename[1] == '\0') ||
|
||||
((entry->filename[1] == '.') && entry->filename[2] == '\0')));
|
||||
}
|
||||
|
||||
/*
|
||||
Reads the first directory entry from the directory starting at dirCluster
|
||||
Places result in entry
|
||||
entry will be destroyed even if no directory entry is found
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_getFirstEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||
|
||||
/*
|
||||
Reads the next directory entry after the one already pointed to by entry
|
||||
Places result in entry
|
||||
entry will be destroyed even if no directory entry is found
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_getNextEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||
|
||||
/*
|
||||
Gets the directory entry corrsponding to the supplied path
|
||||
entry will be destroyed even if no directory entry is found
|
||||
pathEnd specifies the end of the path string, for cutting strings short if needed
|
||||
specify NULL to use the full length of path
|
||||
pathEnd is only a suggestion, and the path string will be searched up until the next PATH_SEPARATOR
|
||||
after pathEND.
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_entryFromPath (PARTITION* partition, DIR_ENTRY* entry, const char* path, const char* pathEnd);
|
||||
|
||||
/*
|
||||
Changes the current directory to the one specified by path
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_chdir (PARTITION* partition, const char* path);
|
||||
|
||||
/*
|
||||
Removes the directory entry specified by entry
|
||||
Assumes that entry is valid
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_removeEntry (PARTITION* partition, DIR_ENTRY* entry);
|
||||
|
||||
/*
|
||||
Add a directory entry to the directory specified by dirCluster
|
||||
The fileData, dataStart and dataEnd elements of the DIR_ENTRY struct are
|
||||
updated with the new directory entry position and alias.
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_addEntry (PARTITION* partition, DIR_ENTRY* entry, uint32_t dirCluster);
|
||||
|
||||
/*
|
||||
Get the start cluster of a file from it's entry data
|
||||
*/
|
||||
uint32_t _FAT_directory_entryGetCluster (PARTITION* partition, const uint8_t* entryData);
|
||||
|
||||
/*
|
||||
Fill in the file name and entry data of DIR_ENTRY* entry.
|
||||
Assumes that the entry's dataStart and dataEnd are correct
|
||||
Returns true on success, false on failure
|
||||
*/
|
||||
bool _FAT_directory_entryFromPosition (PARTITION* partition, DIR_ENTRY* entry);
|
||||
|
||||
/*
|
||||
Fill in a stat struct based on a file entry
|
||||
*/
|
||||
void _FAT_directory_entryStat (PARTITION* partition, DIR_ENTRY* entry, struct stat *st);
|
||||
|
||||
/*
|
||||
Get volume label
|
||||
*/
|
||||
bool _FAT_directory_getVolumeLabel (PARTITION* partition, char *label);
|
||||
|
||||
#endif /* _DIRECTORY_H */
|
|
@ -0,0 +1,139 @@
|
|||
/*
|
||||
disc.c
|
||||
Interface to the low level disc functions. Used by the higher level
|
||||
file system code.
|
||||
|
||||
Copyright (c) 2008 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "disc.h"
|
||||
|
||||
/*
|
||||
The list of interfaces consists of a series of name/interface pairs.
|
||||
The interface is returned via a simple function. This allows for
|
||||
platforms where the interface has to be "assembled" before it can
|
||||
be used, like DLDI on the NDS. For cases where a simple struct
|
||||
is available, wrapper functions are used.
|
||||
The list is terminated by a NULL/NULL entry.
|
||||
*/
|
||||
|
||||
/* ====================== Wii U ====================== */
|
||||
#if defined (__wiiu__)
|
||||
#include <iosuhax_disc_interface.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_wiiu_sd (void)
|
||||
{
|
||||
return &IOSUHAX_sdio_disc_interface;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_wiiu_usb (void)
|
||||
{
|
||||
return &IOSUHAX_usb_disc_interface;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"sd", get_io_wiiu_sd},
|
||||
{"usb", get_io_wiiu_usb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* ====================== Wii ====================== */
|
||||
#elif defined (__wii__)
|
||||
#include <sdcard/wiisd_io.h>
|
||||
#include <ogc/usbstorage.h>
|
||||
#include <sdcard/gcsd.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_wiisd (void)
|
||||
{
|
||||
return &__io_wiisd;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_usbstorage (void)
|
||||
{
|
||||
return &__io_usbstorage;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsda (void)
|
||||
{
|
||||
return &__io_gcsda;
|
||||
}
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsdb (void)
|
||||
{
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"sd", get_io_wiisd},
|
||||
{"usb", get_io_usbstorage},
|
||||
{"carda", get_io_gcsda},
|
||||
{"cardb", get_io_gcsdb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* ==================== Gamecube ==================== */
|
||||
#elif defined (__gamecube__)
|
||||
#include <sdcard/gcsd.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_gcsda (void)
|
||||
{
|
||||
return &__io_gcsda;
|
||||
}
|
||||
static const DISC_INTERFACE* get_io_gcsdb (void)
|
||||
{
|
||||
return &__io_gcsdb;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"carda", get_io_gcsda},
|
||||
{"cardb", get_io_gcsdb},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* ====================== NDS ====================== */
|
||||
#elif defined (NDS)
|
||||
#include <nds/system.h>
|
||||
#include <nds/arm9/dldi.h>
|
||||
|
||||
static const DISC_INTERFACE* get_io_dsisd (void)
|
||||
{
|
||||
return isDSiMode() ? &__io_dsisd : NULL;
|
||||
}
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"sd", get_io_dsisd},
|
||||
{"fat", dldiGetInternal},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
/* ====================== GBA ====================== */
|
||||
#elif defined (GBA)
|
||||
#include <disc.h>
|
||||
|
||||
const INTERFACE_ID _FAT_disc_interfaces[] = {
|
||||
{"fat", discGetInterface},
|
||||
{NULL, NULL}
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
@ -0,0 +1,119 @@
|
|||
/*
|
||||
disc.h
|
||||
Interface to the low level disc functions. Used by the higher level
|
||||
file system code.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
#ifndef _DISC_H
|
||||
#define _DISC_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
/*
|
||||
A list of all default devices to try at startup,
|
||||
terminated by a {NULL,NULL} entry.
|
||||
*/
|
||||
typedef struct
|
||||
{
|
||||
const char* name;
|
||||
const DISC_INTERFACE* (*getInterface)(void);
|
||||
} INTERFACE_ID;
|
||||
extern const INTERFACE_ID _FAT_disc_interfaces[];
|
||||
|
||||
/*
|
||||
Check if a disc is inserted
|
||||
Return true if a disc is inserted and ready, false otherwise
|
||||
*/
|
||||
static inline bool _FAT_disc_isInserted (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->isInserted();
|
||||
}
|
||||
|
||||
/*
|
||||
Read numSectors sectors from a disc, starting at sector.
|
||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||
else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to fill
|
||||
*/
|
||||
static inline bool _FAT_disc_readSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, void* buffer)
|
||||
{
|
||||
return disc->readSectors (sector, numSectors, buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
Write numSectors sectors to a disc, starting at sector.
|
||||
numSectors is between 1 and LIMIT_SECTORS if LIMIT_SECTORS is defined,
|
||||
else it is at least 1
|
||||
sector is 0 or greater
|
||||
buffer is a pointer to the memory to read from
|
||||
*/
|
||||
static inline bool _FAT_disc_writeSectors (const DISC_INTERFACE* disc, sec_t sector, sec_t numSectors, const void* buffer)
|
||||
{
|
||||
return disc->writeSectors (sector, numSectors, buffer);
|
||||
}
|
||||
|
||||
/*
|
||||
Reset the card back to a ready state
|
||||
*/
|
||||
static inline bool _FAT_disc_clearStatus (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->clearStatus();
|
||||
}
|
||||
|
||||
/*
|
||||
Initialise the disc to a state ready for data reading or writing
|
||||
*/
|
||||
static inline bool _FAT_disc_startup (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->startup();
|
||||
}
|
||||
|
||||
/*
|
||||
Put the disc in a state ready for power down.
|
||||
Complete any pending writes and disable the disc if necessary
|
||||
*/
|
||||
static inline bool _FAT_disc_shutdown (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->shutdown();
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value unique to each type of interface
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_hostType (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->ioType;
|
||||
}
|
||||
|
||||
/*
|
||||
Return a 32 bit value that specifies the capabilities of the disc
|
||||
*/
|
||||
static inline uint32_t _FAT_disc_features (const DISC_INTERFACE* disc)
|
||||
{
|
||||
return disc->features;
|
||||
}
|
||||
|
||||
#endif /* _DISC_H */
|
|
@ -0,0 +1,666 @@
|
|||
/*
|
||||
fatdir.c
|
||||
|
||||
Functions used by the newlib disc stubs to interface with
|
||||
this library
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <string.h>
|
||||
#include <errno.h>
|
||||
#include <ctype.h>
|
||||
#include <unistd.h>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
#include "fatdir.h"
|
||||
|
||||
#include "cache.h"
|
||||
#include "file_allocation_table.h"
|
||||
#include "partition.h"
|
||||
#include "directory.h"
|
||||
#include "bit_ops.h"
|
||||
#include "filetime.h"
|
||||
#include "lock.h"
|
||||
|
||||
|
||||
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
|
||||
/* Get the partition this file is on */
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (path, ':') != NULL)
|
||||
path = strchr (path, ':') + 1;
|
||||
if (strchr (path, ':') != NULL)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Search for the file on the disc */
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Fill in the stat struct */
|
||||
_FAT_directory_entryStat (partition, &dirEntry, st);
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink)
|
||||
{
|
||||
r->_errno = ENOTSUP;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _FAT_unlink_r (struct _reent *r, const char *path)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_ENTRY dirContents;
|
||||
uint32_t cluster;
|
||||
bool nextEntry;
|
||||
bool errorOccured = false;
|
||||
|
||||
/* Get the partition this directory is on */
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure we aren't trying to write to a read-only disc */
|
||||
if (partition->readOnly)
|
||||
{
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (path, ':') != NULL)
|
||||
path = strchr (path, ':') + 1;
|
||||
if (strchr (path, ':') != NULL)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Search for the file on the disc */
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, NULL))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
cluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||
|
||||
/* If this is a directory, make sure it is empty */
|
||||
if (_FAT_directory_isDirectory (&dirEntry))
|
||||
{
|
||||
nextEntry = _FAT_directory_getFirstEntry (partition, &dirContents, cluster);
|
||||
|
||||
while (nextEntry)
|
||||
{
|
||||
if (!_FAT_directory_isDot (&dirContents))
|
||||
{
|
||||
/* The directory had something in it that isn't a reference to itself or it's parent */
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTEMPTY;
|
||||
return -1;
|
||||
}
|
||||
nextEntry = _FAT_directory_getNextEntry (partition, &dirContents);
|
||||
}
|
||||
}
|
||||
|
||||
if (_FAT_fat_isValidCluster(partition, cluster))
|
||||
{
|
||||
/* Remove the cluster chain for this file */
|
||||
if (!_FAT_fat_clearLinks (partition, cluster))
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
}
|
||||
|
||||
/* Remove the directory entry for this file */
|
||||
if (!_FAT_directory_removeEntry (partition, &dirEntry))
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
/* Flush any sectors in the disc cache */
|
||||
if (!_FAT_cache_flush(partition->cache))
|
||||
{
|
||||
r->_errno = EIO;
|
||||
errorOccured = true;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
if (errorOccured)
|
||||
return -1;
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_chdir_r (struct _reent *r, const char *path)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
|
||||
/* Get the partition this directory is on */
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (path, ':') != NULL)
|
||||
path = strchr (path, ':') + 1;
|
||||
if (strchr (path, ':') != NULL)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Try changing directory */
|
||||
if (_FAT_directory_chdir (partition, path))
|
||||
{
|
||||
/* Successful */
|
||||
_FAT_unlock(&partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Failed */
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
|
||||
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName)
|
||||
{
|
||||
DIR_ENTRY oldDirEntry;
|
||||
DIR_ENTRY newDirEntry;
|
||||
const char *pathEnd;
|
||||
uint32_t dirCluster;
|
||||
|
||||
/* Get the partition this directory is on */
|
||||
PARTITION *partition = _FAT_partition_getPartitionFromPath (oldName);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Make sure the same partition is used for the old and new names */
|
||||
if (partition != _FAT_partition_getPartitionFromPath (newName))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EXDEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure we aren't trying to write to a read-only disc */
|
||||
if (partition->readOnly)
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (oldName, ':') != NULL)
|
||||
oldName = strchr (oldName, ':') + 1;
|
||||
if (strchr (oldName, ':') != NULL)
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
if (strchr (newName, ':') != NULL)
|
||||
newName = strchr (newName, ':') + 1;
|
||||
if (strchr (newName, ':') != NULL)
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Search for the file on the disc */
|
||||
if (!_FAT_directory_entryFromPath (partition, &oldDirEntry, oldName, NULL))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOENT;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure there is no existing file / directory with the new name */
|
||||
if (_FAT_directory_entryFromPath (partition, &newDirEntry, newName, NULL))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the new file entry
|
||||
* Get the directory it has to go in */
|
||||
pathEnd = strrchr (newName, DIR_SEPARATOR);
|
||||
if (pathEnd == NULL)
|
||||
{
|
||||
/* No path was specified */
|
||||
dirCluster = partition->cwdCluster;
|
||||
pathEnd = newName;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Path was specified -- get the right dirCluster
|
||||
* Recycling newDirEntry, since it needs to be recreated anyway */
|
||||
if (!_FAT_directory_entryFromPath (partition, &newDirEntry, newName, pathEnd) ||
|
||||
!_FAT_directory_isDirectory(&newDirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
dirCluster = _FAT_directory_entryGetCluster (partition, newDirEntry.entryData);
|
||||
/* Move the pathEnd past the last DIR_SEPARATOR */
|
||||
pathEnd += 1;
|
||||
}
|
||||
|
||||
/* Copy the entry data */
|
||||
memcpy (&newDirEntry, &oldDirEntry, sizeof(DIR_ENTRY));
|
||||
|
||||
/* Set the new name */
|
||||
strncpy (newDirEntry.filename, pathEnd, NAME_MAX - 1);
|
||||
|
||||
/* Write the new entry */
|
||||
if (!_FAT_directory_addEntry (partition, &newDirEntry, dirCluster))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Remove the old entry */
|
||||
if (!_FAT_directory_removeEntry (partition, &oldDirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Flush any sectors in the disc cache */
|
||||
if (!_FAT_cache_flush (partition->cache))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_mkdir_r (struct _reent *r, const char *path, int mode)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
bool fileExists;
|
||||
DIR_ENTRY dirEntry;
|
||||
const char* pathEnd;
|
||||
uint32_t parentCluster, dirCluster;
|
||||
uint8_t newEntryData[DIR_ENTRY_DATA_SIZE];
|
||||
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (path, ':') != NULL)
|
||||
path = strchr (path, ':') + 1;
|
||||
if (strchr (path, ':') != NULL)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Search for the file/directory on the disc */
|
||||
fileExists = _FAT_directory_entryFromPath (partition, &dirEntry, path, NULL);
|
||||
|
||||
/* Make sure it doesn't exist */
|
||||
if (fileExists)
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EEXIST;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (partition->readOnly)
|
||||
{
|
||||
/* We can't write to a read-only partition */
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EROFS;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the directory it has to go in */
|
||||
pathEnd = strrchr (path, DIR_SEPARATOR);
|
||||
if (pathEnd == NULL)
|
||||
{
|
||||
/* No path was specified */
|
||||
parentCluster = partition->cwdCluster;
|
||||
pathEnd = path;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Path was specified -- get the right parentCluster
|
||||
* Recycling dirEntry, since it needs to be recreated anyway */
|
||||
if (!_FAT_directory_entryFromPath (partition, &dirEntry, path, pathEnd) ||
|
||||
!_FAT_directory_isDirectory(&dirEntry))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
return -1;
|
||||
}
|
||||
parentCluster = _FAT_directory_entryGetCluster (partition, dirEntry.entryData);
|
||||
/* Move the pathEnd past the last DIR_SEPARATOR */
|
||||
pathEnd += 1;
|
||||
}
|
||||
/* Create the entry data */
|
||||
strncpy (dirEntry.filename, pathEnd, NAME_MAX - 1);
|
||||
memset (dirEntry.entryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
/* Set the creation time and date */
|
||||
dirEntry.entryData[DIR_ENTRY_cTime_ms] = 0;
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cTime, _FAT_filetime_getTimeFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cDate, _FAT_filetime_getDateFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mTime, _FAT_filetime_getTimeFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_mDate, _FAT_filetime_getDateFromRTC());
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_aDate, _FAT_filetime_getDateFromRTC());
|
||||
|
||||
/* Set the directory attribute */
|
||||
dirEntry.entryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||
|
||||
/* Get a cluster for the new directory */
|
||||
dirCluster = _FAT_fat_linkFreeClusterCleared (partition, CLUSTER_FREE);
|
||||
if (!_FAT_fat_isValidCluster(partition, dirCluster))
|
||||
{
|
||||
/* No space left on disc for the cluster */
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_cluster, dirCluster);
|
||||
u16_to_u8array (dirEntry.entryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||
|
||||
/* Write the new directory's entry to it's parent */
|
||||
if (!_FAT_directory_addEntry (partition, &dirEntry, parentCluster))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = ENOSPC;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Create the dot entry within the directory */
|
||||
memset (newEntryData, 0, DIR_ENTRY_DATA_SIZE);
|
||||
memset (newEntryData, ' ', 11);
|
||||
newEntryData[DIR_ENTRY_name] = '.';
|
||||
newEntryData[DIR_ENTRY_attributes] = ATTRIB_DIR;
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, dirCluster);
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, dirCluster >> 16);
|
||||
|
||||
/* Write it to the directory, erasing that sector in the process */
|
||||
_FAT_cache_eraseWritePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector (partition, dirCluster), 0, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
|
||||
/* Create the double dot entry within the directory */
|
||||
|
||||
/* if ParentDir == Rootdir then ".."" always link to Cluster 0 */
|
||||
if(parentCluster == partition->rootDirCluster)
|
||||
parentCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
|
||||
newEntryData[DIR_ENTRY_name + 1] = '.';
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_cluster, parentCluster);
|
||||
u16_to_u8array (newEntryData, DIR_ENTRY_clusterHigh, parentCluster >> 16);
|
||||
|
||||
/* Write it to the directory */
|
||||
_FAT_cache_writePartialSector ( partition->cache, newEntryData,
|
||||
_FAT_fat_clusterToSector (partition, dirCluster), DIR_ENTRY_DATA_SIZE, DIR_ENTRY_DATA_SIZE);
|
||||
|
||||
/* Flush any sectors in the disc cache */
|
||||
if (!_FAT_cache_flush(partition->cache))
|
||||
{
|
||||
_FAT_unlock(&partition->lock);
|
||||
r->_errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf)
|
||||
{
|
||||
PARTITION* partition = NULL;
|
||||
unsigned int freeClusterCount;
|
||||
|
||||
/* Get the partition of the requested path */
|
||||
partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return -1;
|
||||
}
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
if(memcmp(&buf->f_flag, "SCAN", 4) == 0)
|
||||
{
|
||||
/* Special command was given to sync the numberFreeCluster */
|
||||
_FAT_partition_createFSinfo(partition);
|
||||
}
|
||||
|
||||
if(partition->filesysType == FS_FAT32)
|
||||
freeClusterCount = partition->fat.numberFreeCluster;
|
||||
else
|
||||
freeClusterCount = _FAT_fat_freeClusterCount (partition);
|
||||
|
||||
/* FAT clusters = POSIX blocks */
|
||||
buf->f_bsize = partition->bytesPerCluster; /* File system block size. */
|
||||
buf->f_frsize = partition->bytesPerCluster; /* Fundamental file system block size. */
|
||||
|
||||
buf->f_blocks = partition->fat.lastCluster - CLUSTER_FIRST + 1; /* Total number of blocks on file system in units of f_frsize. */
|
||||
buf->f_bfree = freeClusterCount; /* Total number of free blocks. */
|
||||
buf->f_bavail = freeClusterCount; /* Number of free blocks available to non-privileged process. */
|
||||
|
||||
/* Treat requests for info on inodes as clusters */
|
||||
buf->f_files = partition->fat.lastCluster - CLUSTER_FIRST + 1; /* Total number of file serial numbers. */
|
||||
buf->f_ffree = freeClusterCount; /* Total number of free file serial numbers. */
|
||||
buf->f_favail = freeClusterCount; /* Number of file serial numbers available to non-privileged process. */
|
||||
|
||||
/* File system ID. 32bit ioType value */
|
||||
buf->f_fsid = _FAT_disc_hostType(partition->disc);
|
||||
|
||||
/* Bit mask of f_flag values. */
|
||||
buf->f_flag = ST_NOSUID /* No support for ST_ISUID and ST_ISGID file mode bits */
|
||||
| (partition->readOnly ? ST_RDONLY /* Read only file system */ : 0 ) ;
|
||||
/* Maximum filename length. */
|
||||
buf->f_namemax = NAME_MAX;
|
||||
|
||||
_FAT_unlock(&partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path)
|
||||
{
|
||||
DIR_ENTRY dirEntry;
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
bool fileExists;
|
||||
|
||||
state->partition = _FAT_partition_getPartitionFromPath (path);
|
||||
if (state->partition == NULL)
|
||||
{
|
||||
r->_errno = ENODEV;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Move the path pointer to the start of the actual path */
|
||||
if (strchr (path, ':') != NULL)
|
||||
path = strchr (path, ':') + 1;
|
||||
if (strchr (path, ':') != NULL)
|
||||
{
|
||||
r->_errno = EINVAL;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
|
||||
/* Get the start cluster of the directory */
|
||||
fileExists = _FAT_directory_entryFromPath (state->partition, &dirEntry, path, NULL);
|
||||
|
||||
if (!fileExists)
|
||||
{
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
r->_errno = ENOENT;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Make sure it is a directory */
|
||||
if (! _FAT_directory_isDirectory (&dirEntry))
|
||||
{
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
r->_errno = ENOTDIR;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Save the start cluster for use when resetting the directory data */
|
||||
state->startCluster = _FAT_directory_entryGetCluster (state->partition, dirEntry.entryData);
|
||||
|
||||
/* Get the first entry for use with a call to dirnext */
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||
|
||||
/* We are now using this entry */
|
||||
state->inUse = true;
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return (DIR_ITER*) state;
|
||||
}
|
||||
|
||||
int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
|
||||
/* Make sure we are still using this entry */
|
||||
if (!state->inUse)
|
||||
{
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the first entry for use with a call to dirnext */
|
||||
state->validEntry =
|
||||
_FAT_directory_getFirstEntry (state->partition, &(state->currentEntry), state->startCluster);
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat)
|
||||
{
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
|
||||
_FAT_lock(&state->partition->lock);
|
||||
|
||||
/* Make sure we are still using this entry */
|
||||
if (!state->inUse)
|
||||
{
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
r->_errno = EBADF;
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Make sure there is another file to report on */
|
||||
if (! state->validEntry)
|
||||
{
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* Get the filename */
|
||||
strncpy (filename, state->currentEntry.filename, NAME_MAX);
|
||||
/* Get the stats, if requested */
|
||||
if (filestat != NULL)
|
||||
_FAT_directory_entryStat (state->partition, &(state->currentEntry), filestat);
|
||||
|
||||
/* Look for the next entry for use next time */
|
||||
state->validEntry =
|
||||
_FAT_directory_getNextEntry (state->partition, &(state->currentEntry));
|
||||
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
return 0;
|
||||
}
|
||||
|
||||
int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState)
|
||||
{
|
||||
DIR_STATE_STRUCT* state = (DIR_STATE_STRUCT*) (dirState->dirStruct);
|
||||
|
||||
/* We are no longer using this entry */
|
||||
_FAT_lock(&state->partition->lock);
|
||||
state->inUse = false;
|
||||
_FAT_unlock(&state->partition->lock);
|
||||
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,73 @@
|
|||
/*
|
||||
fatdir.h
|
||||
|
||||
Functions used by the newlib disc stubs to interface with
|
||||
this library
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FATDIR_H
|
||||
#define _FATDIR_H
|
||||
|
||||
#include <sys/reent.h>
|
||||
#include <sys/stat.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/iosupport.h>
|
||||
#include "common.h"
|
||||
#include "directory.h"
|
||||
|
||||
typedef struct {
|
||||
PARTITION* partition;
|
||||
DIR_ENTRY currentEntry;
|
||||
uint32_t startCluster;
|
||||
bool inUse;
|
||||
bool validEntry;
|
||||
} DIR_STATE_STRUCT;
|
||||
|
||||
extern int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||
|
||||
extern int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||
|
||||
extern int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||
|
||||
extern int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||
|
||||
extern int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||
|
||||
extern int _FAT_mkdir_r (struct _reent *r, const char *path, int mode);
|
||||
|
||||
extern int _FAT_statvfs_r (struct _reent *r, const char *path, struct statvfs *buf);
|
||||
|
||||
/*
|
||||
Directory iterator functions
|
||||
*/
|
||||
extern DIR_ITER* _FAT_diropen_r(struct _reent *r, DIR_ITER *dirState, const char *path);
|
||||
extern int _FAT_dirreset_r (struct _reent *r, DIR_ITER *dirState);
|
||||
extern int _FAT_dirnext_r (struct _reent *r, DIR_ITER *dirState, char *filename, struct stat *filestat);
|
||||
extern int _FAT_dirclose_r (struct _reent *r, DIR_ITER *dirState);
|
||||
|
||||
|
||||
#endif // _FATDIR_H
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,105 @@
|
|||
/*
|
||||
fatfile.h
|
||||
|
||||
Functions used by the newlib disc stubs to interface with
|
||||
this library
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _FATFILE_H
|
||||
#define _FATFILE_H
|
||||
|
||||
#include <sys/reent.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "partition.h"
|
||||
#include "directory.h"
|
||||
|
||||
#define FILE_MAX_SIZE ((uint32_t)0xFFFFFFFF) /* 4GiB - 1B */
|
||||
|
||||
typedef struct {
|
||||
u32 cluster;
|
||||
sec_t sector;
|
||||
s32 byte;
|
||||
} FILE_POSITION;
|
||||
|
||||
struct _FILE_STRUCT;
|
||||
|
||||
struct _FILE_STRUCT {
|
||||
uint32_t filesize;
|
||||
uint32_t startCluster;
|
||||
uint32_t currentPosition;
|
||||
FILE_POSITION rwPosition;
|
||||
FILE_POSITION appendPosition;
|
||||
DIR_ENTRY_POSITION dirEntryStart; /* Points to the start of the LFN entries of a file, or the alias for no LFN */
|
||||
DIR_ENTRY_POSITION dirEntryEnd; /* Always points to the file's alias entry */
|
||||
PARTITION* partition;
|
||||
struct _FILE_STRUCT* prevOpenFile; /* The previous entry in a double-linked list of open files */
|
||||
struct _FILE_STRUCT* nextOpenFile; /* The next entry in a double-linked list of open files */
|
||||
bool read;
|
||||
bool write;
|
||||
bool append;
|
||||
bool inUse;
|
||||
bool modified;
|
||||
};
|
||||
|
||||
typedef struct _FILE_STRUCT FILE_STRUCT;
|
||||
|
||||
int _FAT_open_r (struct _reent *r, void *fileStruct, const char *path, int flags, int mode);
|
||||
|
||||
int _FAT_close_r (struct _reent *r, void *fd);
|
||||
|
||||
ssize_t _FAT_write_r (struct _reent *r,void *fd, const char *ptr, size_t len);
|
||||
|
||||
ssize_t _FAT_read_r (struct _reent *r, void *fd, char *ptr, size_t len);
|
||||
|
||||
off_t _FAT_seek_r (struct _reent *r, void *fd, off_t pos, int dir);
|
||||
|
||||
int _FAT_fstat_r (struct _reent *r, void *fd, struct stat *st);
|
||||
|
||||
int _FAT_stat_r (struct _reent *r, const char *path, struct stat *st);
|
||||
|
||||
int _FAT_link_r (struct _reent *r, const char *existing, const char *newLink);
|
||||
|
||||
int _FAT_unlink_r (struct _reent *r, const char *name);
|
||||
|
||||
int _FAT_chdir_r (struct _reent *r, const char *name);
|
||||
|
||||
int _FAT_rename_r (struct _reent *r, const char *oldName, const char *newName);
|
||||
|
||||
int _FAT_ftruncate_r (struct _reent *r, void *fd, off_t len);
|
||||
|
||||
int _FAT_fsync_r (struct _reent *r, void *fd);
|
||||
|
||||
/*
|
||||
Synchronizes the file data to disc.
|
||||
Does no locking of its own -- lock the partition before calling.
|
||||
Returns 0 on success, an error code on failure.
|
||||
*/
|
||||
extern int _FAT_syncToDisc (FILE_STRUCT* file);
|
||||
|
||||
#endif /* _FATFILE_H */
|
|
@ -0,0 +1,395 @@
|
|||
/*
|
||||
file_allocation_table.c
|
||||
Reading, writing and manipulation of the FAT structure on
|
||||
a FAT partition
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include "file_allocation_table.h"
|
||||
#include "partition.h"
|
||||
#include "mem_allocate.h"
|
||||
#include <string.h>
|
||||
|
||||
/*
|
||||
Gets the cluster linked from input cluster
|
||||
*/
|
||||
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
uint32_t nextCluster = CLUSTER_FREE;
|
||||
sec_t sector;
|
||||
int offset;
|
||||
|
||||
if (cluster == CLUSTER_FREE)
|
||||
return CLUSTER_FREE;
|
||||
|
||||
switch (partition->filesysType)
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
|
||||
case FS_FAT12:
|
||||
{
|
||||
u32 nextCluster_h;
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector);
|
||||
offset = ((cluster * 3) / 2) % partition->bytesPerSector;
|
||||
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u8));
|
||||
|
||||
offset++;
|
||||
|
||||
if (offset >= partition->bytesPerSector)
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
nextCluster_h = 0;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster_h, sector, offset, sizeof(u8));
|
||||
nextCluster |= (nextCluster_h << 8);
|
||||
|
||||
if (cluster & 0x01)
|
||||
nextCluster = nextCluster >> 4;
|
||||
else
|
||||
nextCluster &= 0x0FFF;
|
||||
|
||||
if (nextCluster >= 0x0FF7)
|
||||
nextCluster = CLUSTER_EOF;
|
||||
|
||||
break;
|
||||
}
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector);
|
||||
offset = (cluster % (partition->bytesPerSector >> 1)) << 1;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u16));
|
||||
|
||||
if (nextCluster >= 0xFFF7)
|
||||
nextCluster = CLUSTER_EOF;
|
||||
break;
|
||||
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector);
|
||||
offset = (cluster % (partition->bytesPerSector >> 2)) << 2;
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &nextCluster, sector, offset, sizeof(u32));
|
||||
|
||||
if (nextCluster >= 0x0FFFFFF7)
|
||||
nextCluster = CLUSTER_EOF;
|
||||
break;
|
||||
|
||||
default:
|
||||
return CLUSTER_ERROR;
|
||||
break;
|
||||
}
|
||||
|
||||
return nextCluster;
|
||||
}
|
||||
|
||||
/*
|
||||
writes value into the correct offset within a partition's FAT, based
|
||||
on the cluster number.
|
||||
*/
|
||||
static bool _FAT_fat_writeFatEntry (PARTITION* partition, uint32_t cluster, uint32_t value)
|
||||
{
|
||||
sec_t sector;
|
||||
int offset;
|
||||
uint32_t oldValue;
|
||||
|
||||
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
switch (partition->filesysType)
|
||||
{
|
||||
case FS_UNKNOWN:
|
||||
return false;
|
||||
break;
|
||||
|
||||
case FS_FAT12:
|
||||
sector = partition->fat.fatStart + (((cluster * 3) / 2) / partition->bytesPerSector);
|
||||
offset = ((cluster * 3) / 2) % partition->bytesPerSector;
|
||||
|
||||
if (cluster & 0x01)
|
||||
{
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||
|
||||
value = (value << 4) | (oldValue & 0x0F);
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value & 0xFF, sector, offset, sizeof(u8));
|
||||
|
||||
offset++;
|
||||
if (offset >= partition->bytesPerSector)
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, (value >> 8) & 0xFF, sector, offset, sizeof(u8));
|
||||
|
||||
} else {
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||
|
||||
offset++;
|
||||
if (offset >= partition->bytesPerSector)
|
||||
{
|
||||
offset = 0;
|
||||
sector++;
|
||||
}
|
||||
|
||||
_FAT_cache_readLittleEndianValue (partition->cache, &oldValue, sector, offset, sizeof(u8));
|
||||
|
||||
value = ((value >> 8) & 0x0F) | (oldValue & 0xF0);
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u8));
|
||||
}
|
||||
|
||||
break;
|
||||
|
||||
case FS_FAT16:
|
||||
sector = partition->fat.fatStart + ((cluster << 1) / partition->bytesPerSector);
|
||||
offset = (cluster % (partition->bytesPerSector >> 1)) << 1;
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u16));
|
||||
|
||||
break;
|
||||
|
||||
case FS_FAT32:
|
||||
sector = partition->fat.fatStart + ((cluster << 2) / partition->bytesPerSector);
|
||||
offset = (cluster % (partition->bytesPerSector >> 2)) << 2;
|
||||
|
||||
_FAT_cache_writeLittleEndianValue (partition->cache, value, sector, offset, sizeof(u32));
|
||||
|
||||
break;
|
||||
|
||||
default:
|
||||
return false;
|
||||
break;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
gets the first available free cluster, sets it
|
||||
to end of file, links the input cluster to it then returns the
|
||||
cluster number
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
uint32_t firstFree;
|
||||
uint32_t curLink;
|
||||
uint32_t lastCluster;
|
||||
bool loopedAroundFAT = false;
|
||||
|
||||
lastCluster = partition->fat.lastCluster;
|
||||
|
||||
if (cluster > lastCluster)
|
||||
return CLUSTER_ERROR;
|
||||
|
||||
/* Check if the cluster already has a link, and return it if so */
|
||||
curLink = _FAT_fat_nextCluster(partition, cluster);
|
||||
if ((curLink >= CLUSTER_FIRST) && (curLink <= lastCluster))
|
||||
return curLink; /* Return the current link - don't allocate a new one */
|
||||
|
||||
/* Get a free cluster */
|
||||
firstFree = partition->fat.firstFree;
|
||||
/* Start at first valid cluster */
|
||||
if (firstFree < CLUSTER_FIRST)
|
||||
firstFree = CLUSTER_FIRST;
|
||||
|
||||
/* Search until a free cluster is found */
|
||||
while (_FAT_fat_nextCluster(partition, firstFree) != CLUSTER_FREE)
|
||||
{
|
||||
firstFree++;
|
||||
if (firstFree > lastCluster)
|
||||
{
|
||||
if (loopedAroundFAT)
|
||||
{
|
||||
/* If couldn't get a free cluster then return an error */
|
||||
partition->fat.firstFree = firstFree;
|
||||
return CLUSTER_ERROR;
|
||||
}
|
||||
|
||||
/* Try looping back to the beginning of the FAT
|
||||
* This was suggested by loopy */
|
||||
firstFree = CLUSTER_FIRST;
|
||||
loopedAroundFAT = true;
|
||||
}
|
||||
}
|
||||
partition->fat.firstFree = firstFree;
|
||||
if(partition->fat.numberFreeCluster)
|
||||
partition->fat.numberFreeCluster--;
|
||||
partition->fat.numberLastAllocCluster = firstFree;
|
||||
|
||||
/* Update the linked from FAT entry */
|
||||
if ((cluster >= CLUSTER_FIRST) && (cluster <= lastCluster))
|
||||
_FAT_fat_writeFatEntry (partition, cluster, firstFree);
|
||||
/* Create the linked to FAT entry */
|
||||
_FAT_fat_writeFatEntry (partition, firstFree, CLUSTER_EOF);
|
||||
|
||||
return firstFree;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
gets the first available free cluster, sets it
|
||||
to end of file, links the input cluster to it, clears the new
|
||||
cluster to 0 valued bytes, then returns the cluster number
|
||||
If an error occurs, return CLUSTER_ERROR
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
uint32_t i;
|
||||
uint8_t *emptySector;
|
||||
|
||||
/* Link the cluster */
|
||||
uint32_t newCluster = _FAT_fat_linkFreeCluster(partition, cluster);
|
||||
|
||||
if (newCluster == CLUSTER_FREE || newCluster == CLUSTER_ERROR)
|
||||
return CLUSTER_ERROR;
|
||||
|
||||
emptySector = (uint8_t*) _FAT_mem_allocate(partition->bytesPerSector);
|
||||
|
||||
/* Clear all the sectors within the cluster */
|
||||
memset (emptySector, 0, partition->bytesPerSector);
|
||||
for (i = 0; i < partition->sectorsPerCluster; i++)
|
||||
{
|
||||
_FAT_cache_writeSectors (partition->cache,
|
||||
_FAT_fat_clusterToSector (partition, newCluster) + i,
|
||||
1, emptySector);
|
||||
}
|
||||
|
||||
_FAT_mem_free(emptySector);
|
||||
|
||||
return newCluster;
|
||||
}
|
||||
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_clearLinks
|
||||
frees any cluster used by a file
|
||||
-----------------------------------------------------------------*/
|
||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if ((cluster < CLUSTER_FIRST) || (cluster > partition->fat.lastCluster /* This will catch CLUSTER_ERROR */))
|
||||
return false;
|
||||
|
||||
/* If this clears up more space in the FAT before the current free pointer, move it backwards */
|
||||
if (cluster < partition->fat.firstFree)
|
||||
partition->fat.firstFree = cluster;
|
||||
|
||||
while ((cluster != CLUSTER_EOF) && (cluster != CLUSTER_FREE) && (cluster != CLUSTER_ERROR))
|
||||
{
|
||||
/* Store next cluster before erasing the link */
|
||||
nextCluster = _FAT_fat_nextCluster (partition, cluster);
|
||||
|
||||
/* Erase the link */
|
||||
_FAT_fat_writeFatEntry (partition, cluster, CLUSTER_FREE);
|
||||
|
||||
if(partition->fat.numberFreeCluster < (partition->numberOfSectors/partition->sectorsPerCluster))
|
||||
partition->fat.numberFreeCluster++;
|
||||
/* Move onto next cluster */
|
||||
cluster = nextCluster;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_trimChain
|
||||
Drop all clusters past the chainLength.
|
||||
If chainLength is 0, all clusters are dropped.
|
||||
If chainLength is 1, the first cluster is kept and the rest are
|
||||
dropped, and so on.
|
||||
Return the last cluster left in the chain.
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength)
|
||||
{
|
||||
uint32_t nextCluster;
|
||||
|
||||
if (chainLength == 0)
|
||||
{
|
||||
/* Drop the entire chain */
|
||||
_FAT_fat_clearLinks (partition, startCluster);
|
||||
return CLUSTER_FREE;
|
||||
}
|
||||
|
||||
/* Find the last cluster in the chain, and the one after it */
|
||||
chainLength--;
|
||||
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||
while ((chainLength > 0) && (nextCluster != CLUSTER_FREE) && (nextCluster != CLUSTER_EOF))
|
||||
{
|
||||
chainLength--;
|
||||
startCluster = nextCluster;
|
||||
nextCluster = _FAT_fat_nextCluster (partition, startCluster);
|
||||
}
|
||||
|
||||
/* Drop all clusters after the last in the chain */
|
||||
if (nextCluster != CLUSTER_FREE && nextCluster != CLUSTER_EOF)
|
||||
_FAT_fat_clearLinks (partition, nextCluster);
|
||||
|
||||
/* Mark the last cluster in the chain as the end of the file */
|
||||
_FAT_fat_writeFatEntry (partition, startCluster, CLUSTER_EOF);
|
||||
|
||||
return startCluster;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_lastCluster
|
||||
Trace the cluster links until the last one is found
|
||||
-----------------------------------------------------------------*/
|
||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster)
|
||||
{
|
||||
while ((_FAT_fat_nextCluster(partition, cluster) != CLUSTER_FREE) && (_FAT_fat_nextCluster(partition, cluster) != CLUSTER_EOF))
|
||||
cluster = _FAT_fat_nextCluster(partition, cluster);
|
||||
return cluster;
|
||||
}
|
||||
|
||||
/*-----------------------------------------------------------------
|
||||
_FAT_fat_freeClusterCount
|
||||
Return the number of free clusters available
|
||||
-----------------------------------------------------------------*/
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition)
|
||||
{
|
||||
unsigned int count = 0;
|
||||
uint32_t curCluster;
|
||||
|
||||
for (curCluster = CLUSTER_FIRST; curCluster <= partition->fat.lastCluster; curCluster++)
|
||||
{
|
||||
if (_FAT_fat_nextCluster(partition, curCluster) == CLUSTER_FREE)
|
||||
count++;
|
||||
}
|
||||
|
||||
return count;
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
/*
|
||||
file_allocation_table.h
|
||||
Reading, writing and manipulation of the FAT structure on
|
||||
a FAT partition
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _FAT_H
|
||||
#define _FAT_H
|
||||
|
||||
#include "common.h"
|
||||
#include "partition.h"
|
||||
|
||||
#define CLUSTER_EOF_16 0xFFFF
|
||||
#define CLUSTER_EOF 0x0FFFFFFF
|
||||
#define CLUSTER_FREE 0x00000000
|
||||
#define CLUSTER_ROOT 0x00000000
|
||||
#define CLUSTER_FIRST 0x00000002
|
||||
#define CLUSTER_ERROR 0xFFFFFFFF
|
||||
|
||||
#define CLUSTERS_PER_FAT12 4085
|
||||
#define CLUSTERS_PER_FAT16 65525
|
||||
|
||||
|
||||
uint32_t _FAT_fat_nextCluster(PARTITION* partition, uint32_t cluster);
|
||||
|
||||
uint32_t _FAT_fat_linkFreeCluster(PARTITION* partition, uint32_t cluster);
|
||||
uint32_t _FAT_fat_linkFreeClusterCleared (PARTITION* partition, uint32_t cluster);
|
||||
|
||||
bool _FAT_fat_clearLinks (PARTITION* partition, uint32_t cluster);
|
||||
|
||||
uint32_t _FAT_fat_trimChain (PARTITION* partition, uint32_t startCluster, unsigned int chainLength);
|
||||
|
||||
uint32_t _FAT_fat_lastCluster (PARTITION* partition, uint32_t cluster);
|
||||
|
||||
unsigned int _FAT_fat_freeClusterCount (PARTITION* partition);
|
||||
|
||||
static inline sec_t _FAT_fat_clusterToSector (PARTITION* partition, uint32_t cluster) {
|
||||
return (cluster >= CLUSTER_FIRST) ?
|
||||
((cluster - CLUSTER_FIRST) * (sec_t)partition->sectorsPerCluster) + partition->dataStart :
|
||||
partition->rootDirStart;
|
||||
}
|
||||
|
||||
static inline bool _FAT_fat_isValidCluster (PARTITION* partition, uint32_t cluster) {
|
||||
return (cluster >= CLUSTER_FIRST) && (cluster <= partition->fat.lastCluster /* This will catch CLUSTER_ERROR */);
|
||||
}
|
||||
|
||||
#endif /* _FAT_H */
|
|
@ -0,0 +1,111 @@
|
|||
/*
|
||||
filetime.c
|
||||
Conversion of file time and date values to various other types
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#include <time.h>
|
||||
#include "filetime.h"
|
||||
#include "common.h"
|
||||
|
||||
#define MAX_HOUR 23
|
||||
#define MAX_MINUTE 59
|
||||
#define MAX_SECOND 59
|
||||
|
||||
#define MAX_MONTH 11
|
||||
#define MIN_MONTH 0
|
||||
#define MAX_DAY 31
|
||||
#define MIN_DAY 1
|
||||
|
||||
uint16_t _FAT_filetime_getTimeFromRTC (void)
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1)
|
||||
return 0;
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
|
||||
/* Check that the values are all in range.
|
||||
* If they are not, return 0 (no timestamp) */
|
||||
if ((timeParts.tm_hour < 0) || (timeParts.tm_hour > MAX_HOUR))
|
||||
return 0;
|
||||
if ((timeParts.tm_min < 0) || (timeParts.tm_min > MAX_MINUTE))
|
||||
return 0;
|
||||
if ((timeParts.tm_sec < 0) || (timeParts.tm_sec > MAX_SECOND))
|
||||
return 0;
|
||||
|
||||
return (
|
||||
((timeParts.tm_hour & 0x1F) << 11) |
|
||||
((timeParts.tm_min & 0x3F) << 5) |
|
||||
((timeParts.tm_sec >> 1) & 0x1F)
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
uint16_t _FAT_filetime_getDateFromRTC (void)
|
||||
{
|
||||
#ifdef USE_RTC_TIME
|
||||
struct tm timeParts;
|
||||
time_t epochTime;
|
||||
|
||||
if (time(&epochTime) == (time_t)-1)
|
||||
return 0;
|
||||
localtime_r(&epochTime, &timeParts);
|
||||
|
||||
if ((timeParts.tm_mon < MIN_MONTH) || (timeParts.tm_mon > MAX_MONTH)) return 0;
|
||||
if ((timeParts.tm_mday < MIN_DAY) || (timeParts.tm_mday > MAX_DAY)) return 0;
|
||||
|
||||
return (
|
||||
(((timeParts.tm_year - 80) & 0x7F) <<9) | /* Adjust for MS-FAT base year (1980 vs 1900 for tm_year) */
|
||||
(((timeParts.tm_mon + 1) & 0xF) << 5) |
|
||||
(timeParts.tm_mday & 0x1F)
|
||||
);
|
||||
#else
|
||||
return 0;
|
||||
#endif
|
||||
}
|
||||
|
||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d)
|
||||
{
|
||||
struct tm timeParts;
|
||||
|
||||
timeParts.tm_hour = t >> 11;
|
||||
timeParts.tm_min = (t >> 5) & 0x3F;
|
||||
timeParts.tm_sec = (t & 0x1F) << 1;
|
||||
|
||||
timeParts.tm_mday = d & 0x1F;
|
||||
timeParts.tm_mon = ((d >> 5) & 0x0F) - 1;
|
||||
timeParts.tm_year = (d >> 9) + 80;
|
||||
|
||||
timeParts.tm_isdst = 0;
|
||||
|
||||
return mktime(&timeParts);
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
/*
|
||||
filetime.h
|
||||
Conversion of file time and date values to various other types
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _FILETIME_H
|
||||
#define _FILETIME_H
|
||||
|
||||
#include "common.h"
|
||||
#include <sys/types.h>
|
||||
|
||||
uint16_t _FAT_filetime_getTimeFromRTC (void);
|
||||
uint16_t _FAT_filetime_getDateFromRTC (void);
|
||||
|
||||
time_t _FAT_filetime_to_time_t (uint16_t t, uint16_t d);
|
||||
|
||||
|
||||
#endif /* _FILETIME_H */
|
|
@ -0,0 +1,124 @@
|
|||
/*
|
||||
fat.h
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
|
||||
Copyright (c) 2006 - 2012
|
||||
Michael "Chishm" Chisholm
|
||||
Dave "WinterMute" Murphy
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
|
||||
#ifndef _LIBFAT_H
|
||||
#define _LIBFAT_H
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#include <libfatversion.h>
|
||||
|
||||
/* When compiling for NDS, make sure NDS is defined */
|
||||
#ifndef NDS
|
||||
#if defined ARM9 || defined ARM7
|
||||
#define NDS
|
||||
#endif
|
||||
#endif
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#if defined (__wiiu__)
|
||||
# include <iosuhax_disc_interface.h>
|
||||
#elif defined(__gamecube__) || defined (__wii__)
|
||||
# include <ogc/disc_io.h>
|
||||
#else
|
||||
# ifdef NDS
|
||||
# include <nds/disc_io.h>
|
||||
# else
|
||||
# include <disc_io.h>
|
||||
# endif
|
||||
#endif
|
||||
|
||||
/*
|
||||
Initialise any inserted block-devices.
|
||||
Add the fat device driver to the devoptab, making it available for standard file functions.
|
||||
cacheSize: The number of pages to allocate for each inserted block-device
|
||||
setAsDefaultDevice: if true, make this the default device driver for file operations
|
||||
*/
|
||||
extern bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice);
|
||||
|
||||
/*
|
||||
Calls fatInit with setAsDefaultDevice = true and cacheSize optimised for the host system.
|
||||
*/
|
||||
extern bool fatInitDefault (void);
|
||||
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
This will mount the active partition or the first valid partition on the disc,
|
||||
and will use a cache size optimized for the host system.
|
||||
*/
|
||||
extern bool fatMountSimple (const char* name, const DISC_INTERFACE* interface);
|
||||
|
||||
/*
|
||||
Mount the device pointed to by interface, and set up a devoptab entry for it as "name:".
|
||||
You can then access the filesystem using "name:/".
|
||||
If startSector = 0, it will mount the active partition of the first valid partition on
|
||||
the disc. Otherwise it will try to mount the partition starting at startSector.
|
||||
cacheSize specifies the number of pages to allocate for the cache.
|
||||
This will not startup the disc, so you need to call interface->startup(); first.
|
||||
*/
|
||||
extern bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage);
|
||||
|
||||
/*
|
||||
Unmount the partition specified by name.
|
||||
If there are open files, it will attempt to synchronise them to disc.
|
||||
*/
|
||||
extern void fatUnmount (const char* name);
|
||||
|
||||
/*
|
||||
Get Volume Label
|
||||
*/
|
||||
extern void fatGetVolumeLabel (const char* name, char *label);
|
||||
|
||||
/* File attributes */
|
||||
#define ATTR_ARCHIVE 0x20 /* Archive */
|
||||
#define ATTR_DIRECTORY 0x10 /* Directory */
|
||||
#define ATTR_VOLUME 0x08 /* Volume */
|
||||
#define ATTR_SYSTEM 0x04 /* System */
|
||||
#define ATTR_HIDDEN 0x02 /* Hidden */
|
||||
#define ATTR_READONLY 0x01 /* Read only */
|
||||
|
||||
/*
|
||||
Methods to modify DOS File Attributes
|
||||
*/
|
||||
int FAT_getAttr(const char *file);
|
||||
int FAT_setAttr(const char *file, uint8_t attr );
|
||||
|
||||
#define LIBFAT_FEOS_MULTICWD
|
||||
|
||||
#ifdef __cplusplus
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* _LIBFAT_H */
|
|
@ -0,0 +1,10 @@
|
|||
#ifndef __LIBFATVERSION_H__
|
||||
#define __LIBFATVERSION_H__
|
||||
|
||||
#define _LIBFAT_MAJOR_ 1
|
||||
#define _LIBFAT_MINOR_ 1
|
||||
#define _LIBFAT_PATCH_ 0
|
||||
|
||||
#define _LIBFAT_STRING "libFAT Release 1.1.0"
|
||||
|
||||
#endif /* __LIBFATVERSION_H__ */
|
|
@ -0,0 +1,264 @@
|
|||
/*
|
||||
libfat.c
|
||||
Simple functionality for startup, mounting and unmounting of FAT-based devices.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <sys/iosupport.h>
|
||||
#include <unistd.h>
|
||||
#include <string.h>
|
||||
#include <stdio.h>
|
||||
#include <limits.h>
|
||||
|
||||
#include "common.h"
|
||||
#include "partition.h"
|
||||
#include "fatfile.h"
|
||||
#include "fatdir.h"
|
||||
#include "lock.h"
|
||||
#include "mem_allocate.h"
|
||||
#include "disc.h"
|
||||
|
||||
static const devoptab_t dotab_fat = {
|
||||
"fat",
|
||||
sizeof (FILE_STRUCT),
|
||||
_FAT_open_r,
|
||||
_FAT_close_r,
|
||||
_FAT_write_r,
|
||||
_FAT_read_r,
|
||||
_FAT_seek_r,
|
||||
_FAT_fstat_r,
|
||||
_FAT_stat_r,
|
||||
_FAT_link_r,
|
||||
_FAT_unlink_r,
|
||||
_FAT_chdir_r,
|
||||
_FAT_rename_r,
|
||||
_FAT_mkdir_r,
|
||||
sizeof (DIR_STATE_STRUCT),
|
||||
_FAT_diropen_r,
|
||||
_FAT_dirreset_r,
|
||||
_FAT_dirnext_r,
|
||||
_FAT_dirclose_r,
|
||||
_FAT_statvfs_r,
|
||||
_FAT_ftruncate_r,
|
||||
_FAT_fsync_r,
|
||||
NULL, /* Device data */
|
||||
NULL, /* chmod_r */
|
||||
NULL /* fchmod_r */
|
||||
};
|
||||
|
||||
bool fatMount (const char* name, const DISC_INTERFACE* interface, sec_t startSector, uint32_t cacheSize, uint32_t SectorsPerPage)
|
||||
{
|
||||
char devname[10];
|
||||
PARTITION* partition;
|
||||
devoptab_t* devops;
|
||||
char* nameCopy;
|
||||
|
||||
if(!name || strlen(name) > 8 || !interface)
|
||||
return false;
|
||||
|
||||
if(!interface->startup())
|
||||
return false;
|
||||
|
||||
if(!interface->isInserted())
|
||||
return false;
|
||||
|
||||
strcpy(devname, name);
|
||||
strcat(devname, ":");
|
||||
if(FindDevice(devname) >= 0)
|
||||
return true;
|
||||
|
||||
devops = _FAT_mem_allocate (sizeof(devoptab_t) + strlen(name) + 1);
|
||||
if (!devops)
|
||||
return false;
|
||||
/* Use the space allocated at the end of the devoptab struct for storing the name */
|
||||
nameCopy = (char*)(devops+1);
|
||||
|
||||
/* Initialize the file system */
|
||||
partition = _FAT_partition_constructor (interface, cacheSize, SectorsPerPage, startSector);
|
||||
if (!partition)
|
||||
{
|
||||
_FAT_mem_free (devops);
|
||||
return false;
|
||||
}
|
||||
|
||||
/* Add an entry for this device to the devoptab table */
|
||||
memcpy (devops, &dotab_fat, sizeof(dotab_fat));
|
||||
strcpy (nameCopy, name);
|
||||
devops->name = nameCopy;
|
||||
devops->deviceData = partition;
|
||||
|
||||
AddDevice (devops);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatMountSimple (const char* name, const DISC_INTERFACE* interface)
|
||||
{
|
||||
return fatMount (name, interface, 0, DEFAULT_CACHE_PAGES, DEFAULT_SECTORS_PAGE);
|
||||
}
|
||||
|
||||
void fatUnmount (const char* name)
|
||||
{
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
|
||||
if(!name)
|
||||
return;
|
||||
|
||||
devops = (devoptab_t*)GetDeviceOpTab (name);
|
||||
if (!devops)
|
||||
return;
|
||||
|
||||
/* Perform a quick check to make sure we're dealing with a libfat controlled device */
|
||||
if (devops->open_r != dotab_fat.open_r)
|
||||
return;
|
||||
|
||||
if (RemoveDevice (name) == -1)
|
||||
return;
|
||||
|
||||
partition = (PARTITION*)devops->deviceData;
|
||||
_FAT_partition_destructor (partition);
|
||||
_FAT_mem_free (devops);
|
||||
}
|
||||
|
||||
bool fatInit (uint32_t cacheSize, bool setAsDefaultDevice)
|
||||
{
|
||||
int i;
|
||||
int defaultDevice = -1;
|
||||
const DISC_INTERFACE *disc;
|
||||
|
||||
for (i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
{
|
||||
disc = _FAT_disc_interfaces[i].getInterface();
|
||||
if (!disc)
|
||||
continue;
|
||||
|
||||
if (fatMount (_FAT_disc_interfaces[i].name, disc, 0, cacheSize, DEFAULT_SECTORS_PAGE))
|
||||
{
|
||||
/* The first device to successfully mount is set as the default */
|
||||
if (defaultDevice < 0)
|
||||
defaultDevice = i;
|
||||
}
|
||||
}
|
||||
|
||||
/* None of our devices mounted */
|
||||
if (defaultDevice < 0)
|
||||
return false;
|
||||
|
||||
if (setAsDefaultDevice)
|
||||
{
|
||||
char filePath[PATH_MAX];
|
||||
strcpy (filePath, _FAT_disc_interfaces[defaultDevice].name);
|
||||
strcat (filePath, ":/");
|
||||
#ifdef ARGV_MAGIC
|
||||
if ( __system_argv->argvMagic == ARGV_MAGIC && __system_argv->argc >= 1 && strrchr( __system_argv->argv[0], '/' )!=NULL )
|
||||
{
|
||||
/* Check the app's path against each of our mounted devices, to see
|
||||
* if we can support it. If so, change to that path. */
|
||||
for (i = 0;
|
||||
_FAT_disc_interfaces[i].name != NULL && _FAT_disc_interfaces[i].getInterface != NULL;
|
||||
i++)
|
||||
{
|
||||
if ( !strncasecmp( __system_argv->argv[0], _FAT_disc_interfaces[i].name,
|
||||
strlen(_FAT_disc_interfaces[i].name)))
|
||||
{
|
||||
char *lastSlash;
|
||||
strcpy(filePath, __system_argv->argv[0]);
|
||||
lastSlash = strrchr( filePath, '/' );
|
||||
|
||||
if ( NULL != lastSlash)
|
||||
{
|
||||
if ( *(lastSlash - 1) == ':')
|
||||
lastSlash++;
|
||||
*lastSlash = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
chdir (filePath);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool fatInitDefault (void)
|
||||
{
|
||||
return fatInit (DEFAULT_CACHE_PAGES, true);
|
||||
}
|
||||
|
||||
void fatGetVolumeLabel (const char* name, char *label)
|
||||
{
|
||||
devoptab_t *devops;
|
||||
PARTITION* partition;
|
||||
char *buf;
|
||||
int namelen,i;
|
||||
|
||||
if(!name || !label)
|
||||
return;
|
||||
|
||||
namelen = strlen(name);
|
||||
buf=(char*)_FAT_mem_allocate(sizeof(char)*namelen+2);
|
||||
strcpy(buf,name);
|
||||
|
||||
if (name[namelen-1] == '/')
|
||||
{
|
||||
buf[namelen-1]='\0';
|
||||
namelen--;
|
||||
}
|
||||
|
||||
if (name[namelen-1] != ':')
|
||||
{
|
||||
buf[namelen]=':';
|
||||
buf[namelen+1]='\0';
|
||||
}
|
||||
|
||||
devops = (devoptab_t*)GetDeviceOpTab(buf);
|
||||
|
||||
for(i=0;buf[i]!='\0' && buf[i]!=':';i++);
|
||||
if (!devops || strncasecmp(buf,devops->name,i))
|
||||
{
|
||||
_FAT_mem_free(buf);
|
||||
return;
|
||||
}
|
||||
|
||||
_FAT_mem_free(buf);
|
||||
|
||||
/* Perform a quick check to make sure we're dealing with a libfat controlled device */
|
||||
if (devops->open_r != dotab_fat.open_r)
|
||||
return;
|
||||
|
||||
partition = (PARTITION*)devops->deviceData;
|
||||
|
||||
if(!_FAT_directory_getVolumeLabel(partition, label))
|
||||
{
|
||||
strncpy(label,partition->label,11);
|
||||
label[11]='\0';
|
||||
}
|
||||
if(!strncmp(label, "NO NAME", 7))
|
||||
label[0]='\0';
|
||||
}
|
|
@ -0,0 +1,29 @@
|
|||
#include "common.h"
|
||||
|
||||
#ifndef USE_LWP_LOCK
|
||||
|
||||
#ifndef mutex_t
|
||||
typedef int mutex_t;
|
||||
#endif
|
||||
|
||||
void __attribute__ ((weak)) _FAT_lock_init(mutex_t *mutex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void __attribute__ ((weak)) _FAT_lock_deinit(mutex_t *mutex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void __attribute__ ((weak)) _FAT_lock(mutex_t *mutex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
void __attribute__ ((weak)) _FAT_unlock(mutex_t *mutex)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
#endif /* USE_LWP_LOCK */
|
|
@ -0,0 +1,72 @@
|
|||
/*
|
||||
lock.h
|
||||
|
||||
Copyright (c) 2008 Sven Peter <svpe@gmx.net>
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
|
||||
*/
|
||||
|
||||
#ifndef _LOCK_H
|
||||
#define _LOCK_H
|
||||
|
||||
#include "common.h"
|
||||
|
||||
#ifdef USE_LWP_LOCK
|
||||
|
||||
static inline void _FAT_lock_init(mutex_t *mutex)
|
||||
{
|
||||
LWP_MutexInit(mutex, false);
|
||||
}
|
||||
|
||||
static inline void _FAT_lock_deinit(mutex_t *mutex)
|
||||
{
|
||||
LWP_MutexDestroy(*mutex);
|
||||
}
|
||||
|
||||
static inline void _FAT_lock(mutex_t *mutex)
|
||||
{
|
||||
LWP_MutexLock(*mutex);
|
||||
}
|
||||
|
||||
static inline void _FAT_unlock(mutex_t *mutex)
|
||||
{
|
||||
LWP_MutexUnlock(*mutex);
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
/* We still need a blank lock type */
|
||||
#ifndef mutex_t
|
||||
typedef int mutex_t;
|
||||
#endif
|
||||
|
||||
void _FAT_lock_init(mutex_t *mutex);
|
||||
void _FAT_lock_deinit(mutex_t *mutex);
|
||||
void _FAT_lock(mutex_t *mutex);
|
||||
void _FAT_unlock(mutex_t *mutex);
|
||||
|
||||
#endif /* USE_LWP_LOCK */
|
||||
|
||||
|
||||
#endif /* _LOCK_H */
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
/*
|
||||
mem_allocate.h
|
||||
Memory allocation and destruction calls
|
||||
Replace these calls with custom allocators if
|
||||
malloc is unavailable
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _MEM_ALLOCATE_H
|
||||
#define _MEM_ALLOCATE_H
|
||||
|
||||
#include <malloc.h>
|
||||
|
||||
static inline void* _FAT_mem_allocate (size_t size)
|
||||
{
|
||||
return malloc (size);
|
||||
}
|
||||
|
||||
static inline void* _FAT_mem_align (size_t size)
|
||||
{
|
||||
#ifdef __wii__
|
||||
return memalign (32, size);
|
||||
#else
|
||||
return malloc (size);
|
||||
#endif
|
||||
}
|
||||
|
||||
static inline void _FAT_mem_free (void* mem)
|
||||
{
|
||||
free (mem);
|
||||
}
|
||||
|
||||
#endif /* _MEM_ALLOCATE_H */
|
|
@ -0,0 +1,464 @@
|
|||
/*
|
||||
partition.c
|
||||
Functions for mounting and dismounting partitions
|
||||
on various block devices.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "partition.h"
|
||||
#include "bit_ops.h"
|
||||
#include "file_allocation_table.h"
|
||||
#include "directory.h"
|
||||
#include "mem_allocate.h"
|
||||
#include "fatfile.h"
|
||||
|
||||
#include <string.h>
|
||||
#include <ctype.h>
|
||||
#include <sys/iosupport.h>
|
||||
|
||||
/*
|
||||
Data offsets
|
||||
*/
|
||||
|
||||
/* BIOS Parameter Block offsets */
|
||||
enum BPB
|
||||
{
|
||||
BPB_jmpBoot = 0x00,
|
||||
BPB_OEMName = 0x03,
|
||||
/* BIOS Parameter Block */
|
||||
BPB_bytesPerSector = 0x0B,
|
||||
BPB_sectorsPerCluster = 0x0D,
|
||||
BPB_reservedSectors = 0x0E,
|
||||
BPB_numFATs = 0x10,
|
||||
BPB_rootEntries = 0x11,
|
||||
BPB_numSectorsSmall = 0x13,
|
||||
BPB_mediaDesc = 0x15,
|
||||
BPB_sectorsPerFAT = 0x16,
|
||||
BPB_sectorsPerTrk = 0x18,
|
||||
BPB_numHeads = 0x1A,
|
||||
BPB_numHiddenSectors = 0x1C,
|
||||
BPB_numSectors = 0x20,
|
||||
/* Ext BIOS Parameter Block for FAT16 */
|
||||
BPB_FAT16_driveNumber = 0x24,
|
||||
BPB_FAT16_reserved1 = 0x25,
|
||||
BPB_FAT16_extBootSig = 0x26,
|
||||
BPB_FAT16_volumeID = 0x27,
|
||||
BPB_FAT16_volumeLabel = 0x2B,
|
||||
BPB_FAT16_fileSysType = 0x36,
|
||||
/* Bootcode */
|
||||
BPB_FAT16_bootCode = 0x3E,
|
||||
/* FAT32 extended block */
|
||||
BPB_FAT32_sectorsPerFAT32 = 0x24,
|
||||
BPB_FAT32_extFlags = 0x28,
|
||||
BPB_FAT32_fsVer = 0x2A,
|
||||
BPB_FAT32_rootClus = 0x2C,
|
||||
BPB_FAT32_fsInfo = 0x30,
|
||||
BPB_FAT32_bkBootSec = 0x32,
|
||||
/* Ext BIOS Parameter Block for FAT32 */
|
||||
BPB_FAT32_driveNumber = 0x40,
|
||||
BPB_FAT32_reserved1 = 0x41,
|
||||
BPB_FAT32_extBootSig = 0x42,
|
||||
BPB_FAT32_volumeID = 0x43,
|
||||
BPB_FAT32_volumeLabel = 0x47,
|
||||
BPB_FAT32_fileSysType = 0x52,
|
||||
/* Bootcode */
|
||||
BPB_FAT32_bootCode = 0x5A,
|
||||
BPB_bootSig_55 = 0x1FE,
|
||||
BPB_bootSig_AA = 0x1FF
|
||||
};
|
||||
|
||||
/* File system information block offsets */
|
||||
enum FSIB
|
||||
{
|
||||
FSIB_SIG1 = 0x00,
|
||||
FSIB_SIG2 = 0x1e4,
|
||||
FSIB_numberOfFreeCluster = 0x1e8,
|
||||
FSIB_numberLastAllocCluster = 0x1ec,
|
||||
FSIB_bootSig_55 = 0x1FE,
|
||||
FSIB_bootSig_AA = 0x1FF
|
||||
};
|
||||
|
||||
static const char FAT_SIG[3] = {'F', 'A', 'T'};
|
||||
static const char FS_INFO_SIG1[4] = {'R', 'R', 'a', 'A'};
|
||||
static const char FS_INFO_SIG2[4] = {'r', 'r', 'A', 'a'};
|
||||
|
||||
sec_t FindFirstValidPartition_buf(const DISC_INTERFACE* disc, uint8_t *sectorBuffer)
|
||||
{
|
||||
uint8_t part_table[16*4];
|
||||
uint8_t *ptr;
|
||||
int i;
|
||||
|
||||
/* Read first sector of disc */
|
||||
if (!_FAT_disc_readSectors (disc, 0, 1, sectorBuffer))
|
||||
return 0;
|
||||
|
||||
memcpy(part_table,sectorBuffer+0x1BE,16*4);
|
||||
ptr = part_table;
|
||||
|
||||
for(i=0;i<4;i++,ptr+=16)
|
||||
{
|
||||
sec_t part_lba = u8array_to_u32(ptr, 0x8);
|
||||
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
return part_lba;
|
||||
|
||||
if(ptr[4]==0)
|
||||
continue;
|
||||
|
||||
if(ptr[4]==0x0F)
|
||||
{
|
||||
sec_t part_lba2=part_lba;
|
||||
sec_t next_lba2=0;
|
||||
int n;
|
||||
|
||||
for(n=0;n<8;n++) /* max 8 logic partitions */
|
||||
{
|
||||
if(!_FAT_disc_readSectors (disc, part_lba+next_lba2, 1, sectorBuffer))
|
||||
return 0;
|
||||
|
||||
part_lba2 = part_lba + next_lba2 + u8array_to_u32(sectorBuffer, 0x1C6) ;
|
||||
next_lba2 = u8array_to_u32(sectorBuffer, 0x1D6);
|
||||
|
||||
if(!_FAT_disc_readSectors (disc, part_lba2, 1, sectorBuffer))
|
||||
return 0;
|
||||
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
return part_lba2;
|
||||
|
||||
if(next_lba2==0) break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(!_FAT_disc_readSectors (disc, part_lba, 1, sectorBuffer))
|
||||
return 0;
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) ||
|
||||
!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
return part_lba;
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
sec_t FindFirstValidPartition(const DISC_INTERFACE* disc)
|
||||
{
|
||||
uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE);
|
||||
if (!sectorBuffer)
|
||||
return 0;
|
||||
sec_t ret = FindFirstValidPartition_buf(disc, sectorBuffer);
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
PARTITION* _FAT_partition_constructor_buf (const DISC_INTERFACE* disc,
|
||||
uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector,
|
||||
uint8_t *sectorBuffer)
|
||||
{
|
||||
PARTITION* partition;
|
||||
uint32_t clusterCount;
|
||||
|
||||
/* Read first sector of disc */
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer))
|
||||
return NULL;
|
||||
|
||||
/* Make sure it is a valid MBR or boot sector */
|
||||
if ( (sectorBuffer[BPB_bootSig_55] != 0x55) || ((sectorBuffer[BPB_bootSig_AA] != 0xAA)
|
||||
#if defined(__gamecube__) || defined (__wii__) || defined (__wiiu__)
|
||||
&& (sectorBuffer[BPB_bootSig_AA] != 0xAB)
|
||||
#endif
|
||||
))
|
||||
return NULL;
|
||||
|
||||
/* We're told where to start the partition, so just accept it */
|
||||
if (startSector != 0) { }
|
||||
/* Check if there is a FAT string, which indicates this is a boot sector */
|
||||
else if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
startSector = 0;
|
||||
/* Check for FAT32 */
|
||||
else if (!memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
startSector = 0;
|
||||
else
|
||||
{
|
||||
startSector = FindFirstValidPartition_buf(disc, sectorBuffer);
|
||||
if (!_FAT_disc_readSectors (disc, startSector, 1, sectorBuffer))
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* Now verify that this is indeed a FAT partition */
|
||||
if (memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)) &&
|
||||
memcmp(sectorBuffer + BPB_FAT32_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
return NULL;
|
||||
|
||||
partition = (PARTITION*) _FAT_mem_allocate (sizeof(PARTITION));
|
||||
if (partition == NULL)
|
||||
return NULL;
|
||||
|
||||
/* Init the partition lock */
|
||||
_FAT_lock_init(&partition->lock);
|
||||
|
||||
if (!memcmp(sectorBuffer + BPB_FAT16_fileSysType, FAT_SIG, sizeof(FAT_SIG)))
|
||||
strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT16_volumeLabel), 11);
|
||||
else
|
||||
strncpy(partition->label, (char*)(sectorBuffer + BPB_FAT32_volumeLabel), 11);
|
||||
partition->label[11] = '\0';
|
||||
|
||||
/* Set partition's disc interface */
|
||||
partition->disc = disc;
|
||||
|
||||
/* Store required information about the file system */
|
||||
partition->fat.sectorsPerFat = u8array_to_u16(sectorBuffer, BPB_sectorsPerFAT);
|
||||
if (partition->fat.sectorsPerFat == 0)
|
||||
partition->fat.sectorsPerFat = u8array_to_u32( sectorBuffer, BPB_FAT32_sectorsPerFAT32);
|
||||
|
||||
partition->numberOfSectors = u8array_to_u16( sectorBuffer, BPB_numSectorsSmall);
|
||||
if (partition->numberOfSectors == 0)
|
||||
partition->numberOfSectors = u8array_to_u32( sectorBuffer, BPB_numSectors);
|
||||
|
||||
partition->bytesPerSector = u8array_to_u16(sectorBuffer, BPB_bytesPerSector);
|
||||
if(partition->bytesPerSector < MIN_SECTOR_SIZE || partition->bytesPerSector > MAX_SECTOR_SIZE)
|
||||
{
|
||||
/* Unsupported sector size */
|
||||
_FAT_mem_free(partition);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
partition->sectorsPerCluster = sectorBuffer[BPB_sectorsPerCluster];
|
||||
partition->bytesPerCluster = partition->bytesPerSector * partition->sectorsPerCluster;
|
||||
partition->fat.fatStart = startSector + u8array_to_u16(sectorBuffer, BPB_reservedSectors);
|
||||
|
||||
partition->rootDirStart = partition->fat.fatStart + (sectorBuffer[BPB_numFATs] * partition->fat.sectorsPerFat);
|
||||
partition->dataStart = partition->rootDirStart +
|
||||
(( u8array_to_u16(sectorBuffer, BPB_rootEntries) * DIR_ENTRY_DATA_SIZE) / partition->bytesPerSector);
|
||||
|
||||
partition->totalSize = ((uint64_t)partition->numberOfSectors - (partition->dataStart - startSector)) * (uint64_t)partition->bytesPerSector;
|
||||
|
||||
/* FS info sector */
|
||||
partition->fsInfoSector = startSector + (u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) ? u8array_to_u16(sectorBuffer, BPB_FAT32_fsInfo) : 1);
|
||||
|
||||
/* Store info about FAT */
|
||||
clusterCount = (partition->numberOfSectors - (uint32_t)(partition->dataStart - startSector)) / partition->sectorsPerCluster;
|
||||
|
||||
partition->fat.lastCluster = clusterCount + CLUSTER_FIRST - 1;
|
||||
partition->fat.firstFree = CLUSTER_FIRST;
|
||||
partition->fat.numberFreeCluster = 0;
|
||||
partition->fat.numberLastAllocCluster = 0;
|
||||
|
||||
if (clusterCount < CLUSTERS_PER_FAT12)
|
||||
partition->filesysType = FS_FAT12; /* FAT12 volume */
|
||||
else if (clusterCount < CLUSTERS_PER_FAT16)
|
||||
partition->filesysType = FS_FAT16; /* FAT16 volume */
|
||||
else
|
||||
partition->filesysType = FS_FAT32; /* FAT32 volume */
|
||||
|
||||
if (partition->filesysType != FS_FAT32)
|
||||
partition->rootDirCluster = FAT16_ROOT_DIR_CLUSTER;
|
||||
else
|
||||
{
|
||||
/* Set up for the FAT32 way */
|
||||
partition->rootDirCluster = u8array_to_u32(sectorBuffer, BPB_FAT32_rootClus);
|
||||
/* Check if FAT mirroring is enabled */
|
||||
if (!(sectorBuffer[BPB_FAT32_extFlags] & 0x80))
|
||||
{
|
||||
/* Use the active FAT */
|
||||
partition->fat.fatStart = partition->fat.fatStart + ( partition->fat.sectorsPerFat * (sectorBuffer[BPB_FAT32_extFlags] & 0x0F));
|
||||
}
|
||||
}
|
||||
|
||||
/* Create a cache to use */
|
||||
partition->cache = _FAT_cache_constructor (cacheSize, sectorsPerPage, partition->disc, startSector+partition->numberOfSectors, partition->bytesPerSector);
|
||||
|
||||
/* Set current directory to the root */
|
||||
partition->cwdCluster = partition->rootDirCluster;
|
||||
|
||||
/* Check if this disc is writable, and set the
|
||||
* readOnly property appropriately */
|
||||
partition->readOnly = !(_FAT_disc_features(disc) & FEATURE_MEDIUM_CANWRITE);
|
||||
|
||||
/* There are currently no open files on this partition */
|
||||
partition->openFileCount = 0;
|
||||
partition->firstOpenFile = NULL;
|
||||
|
||||
_FAT_partition_readFSinfo(partition);
|
||||
|
||||
return partition;
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t sectorsPerPage, sec_t startSector)
|
||||
{
|
||||
PARTITION *ret = NULL;
|
||||
uint8_t *sectorBuffer = (uint8_t*) _FAT_mem_align(MAX_SECTOR_SIZE);
|
||||
if (!sectorBuffer)
|
||||
return NULL;
|
||||
|
||||
ret = _FAT_partition_constructor_buf(disc, cacheSize,
|
||||
sectorsPerPage, startSector, sectorBuffer);
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
void _FAT_partition_destructor (PARTITION* partition)
|
||||
{
|
||||
FILE_STRUCT* nextFile;
|
||||
|
||||
_FAT_lock(&partition->lock);
|
||||
|
||||
/* Synchronize open files */
|
||||
nextFile = partition->firstOpenFile;
|
||||
while (nextFile)
|
||||
{
|
||||
_FAT_syncToDisc (nextFile);
|
||||
nextFile = nextFile->nextOpenFile;
|
||||
}
|
||||
|
||||
/* Write out the fs info sector */
|
||||
_FAT_partition_writeFSinfo(partition);
|
||||
|
||||
/* Free memory used by the cache, writing it to disc at the same time */
|
||||
_FAT_cache_destructor (partition->cache);
|
||||
|
||||
/* Unlock the partition and destroy the lock */
|
||||
_FAT_unlock(&partition->lock);
|
||||
_FAT_lock_deinit(&partition->lock);
|
||||
|
||||
/* Free memory used by the partition */
|
||||
_FAT_mem_free (partition);
|
||||
}
|
||||
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path)
|
||||
{
|
||||
const devoptab_t *devops = GetDeviceOpTab (path);
|
||||
|
||||
if (!devops)
|
||||
return NULL;
|
||||
|
||||
return (PARTITION*)devops->deviceData;
|
||||
}
|
||||
|
||||
void _FAT_partition_createFSinfo(PARTITION * partition)
|
||||
{
|
||||
int i;
|
||||
uint8_t *sectorBuffer;
|
||||
|
||||
if(partition->readOnly || partition->filesysType != FS_FAT32)
|
||||
return;
|
||||
|
||||
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||
if (!sectorBuffer)
|
||||
return;
|
||||
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||
|
||||
for(i = 0; i < 4; ++i)
|
||||
{
|
||||
sectorBuffer[FSIB_SIG1+i] = FS_INFO_SIG1[i];
|
||||
sectorBuffer[FSIB_SIG2+i] = FS_INFO_SIG2[i];
|
||||
}
|
||||
|
||||
partition->fat.numberFreeCluster = _FAT_fat_freeClusterCount(partition);
|
||||
u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster);
|
||||
u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster);
|
||||
|
||||
sectorBuffer[FSIB_bootSig_55] = 0x55;
|
||||
sectorBuffer[FSIB_bootSig_AA] = 0xAA;
|
||||
|
||||
_FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer);
|
||||
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
}
|
||||
|
||||
void _FAT_partition_readFSinfo(PARTITION * partition)
|
||||
{
|
||||
uint8_t *sectorBuffer = NULL;
|
||||
if(partition->filesysType != FS_FAT32)
|
||||
return;
|
||||
|
||||
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||
if (!sectorBuffer)
|
||||
return;
|
||||
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||
|
||||
/* Read first sector of disc */
|
||||
if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer))
|
||||
{
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
/* sector does not yet exist, create one! */
|
||||
if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) != 0 ||
|
||||
memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4) != 0 ||
|
||||
u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster) == 0)
|
||||
_FAT_partition_createFSinfo(partition);
|
||||
else
|
||||
{
|
||||
partition->fat.numberFreeCluster = u8array_to_u32(sectorBuffer, FSIB_numberOfFreeCluster);
|
||||
partition->fat.numberLastAllocCluster = u8array_to_u32(sectorBuffer, FSIB_numberLastAllocCluster);
|
||||
}
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
}
|
||||
|
||||
void _FAT_partition_writeFSinfo(PARTITION * partition)
|
||||
{
|
||||
uint8_t *sectorBuffer = NULL;
|
||||
if(partition->filesysType != FS_FAT32)
|
||||
return;
|
||||
|
||||
sectorBuffer = (uint8_t*) _FAT_mem_align(partition->bytesPerSector);
|
||||
if (!sectorBuffer)
|
||||
return;
|
||||
memset(sectorBuffer, 0, partition->bytesPerSector);
|
||||
/* Read first sector of disc */
|
||||
if (!_FAT_disc_readSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer))
|
||||
{
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
if(memcmp(sectorBuffer+FSIB_SIG1, FS_INFO_SIG1, 4) || memcmp(sectorBuffer+FSIB_SIG2, FS_INFO_SIG2, 4))
|
||||
{
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
return;
|
||||
}
|
||||
|
||||
u32_to_u8array(sectorBuffer, FSIB_numberOfFreeCluster, partition->fat.numberFreeCluster);
|
||||
u32_to_u8array(sectorBuffer, FSIB_numberLastAllocCluster, partition->fat.numberLastAllocCluster);
|
||||
|
||||
/* Write first sector of disc */
|
||||
_FAT_disc_writeSectors (partition->disc, partition->fsInfoSector, 1, sectorBuffer);
|
||||
_FAT_mem_free(sectorBuffer);
|
||||
}
|
||||
|
||||
uint32_t* _FAT_getCwdClusterPtr(const char* name)
|
||||
{
|
||||
PARTITION *partition = _FAT_partition_getPartitionFromPath(name);
|
||||
|
||||
if (!partition)
|
||||
return NULL;
|
||||
|
||||
return &partition->cwdCluster;
|
||||
}
|
|
@ -0,0 +1,107 @@
|
|||
/*
|
||||
partition.h
|
||||
Functions for mounting and dismounting partitions
|
||||
on various block devices.
|
||||
|
||||
Copyright (c) 2006 Michael "Chishm" Chisholm
|
||||
|
||||
Redistribution and use in source and binary forms, with or without modification,
|
||||
are permitted provided that the following conditions are met:
|
||||
|
||||
1. Redistributions of source code must retain the above copyright notice,
|
||||
this list of conditions and the following disclaimer.
|
||||
2. Redistributions in binary form must reproduce the above copyright notice,
|
||||
this list of conditions and the following disclaimer in the documentation and/or
|
||||
other materials provided with the distribution.
|
||||
3. The name of the author may not be used to endorse or promote products derived
|
||||
from this software without specific prior written permission.
|
||||
|
||||
THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR IMPLIED
|
||||
WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY
|
||||
AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR BE
|
||||
LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
|
||||
DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
|
||||
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
|
||||
THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
|
||||
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
|
||||
EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#ifndef _PARTITION_H
|
||||
#define _PARTITION_H
|
||||
|
||||
#include "common.h"
|
||||
#include "cache.h"
|
||||
#include "lock.h"
|
||||
|
||||
#define MIN_SECTOR_SIZE 512
|
||||
#define MAX_SECTOR_SIZE 4096
|
||||
|
||||
/* Filesystem type */
|
||||
typedef enum {FS_UNKNOWN, FS_FAT12, FS_FAT16, FS_FAT32} FS_TYPE;
|
||||
|
||||
typedef struct {
|
||||
sec_t fatStart;
|
||||
uint32_t sectorsPerFat;
|
||||
uint32_t lastCluster;
|
||||
uint32_t firstFree;
|
||||
uint32_t numberFreeCluster;
|
||||
uint32_t numberLastAllocCluster;
|
||||
} FAT;
|
||||
|
||||
typedef struct {
|
||||
const DISC_INTERFACE* disc;
|
||||
CACHE* cache;
|
||||
/* Info about the partition */
|
||||
FS_TYPE filesysType;
|
||||
uint64_t totalSize;
|
||||
sec_t rootDirStart;
|
||||
uint32_t rootDirCluster;
|
||||
uint32_t numberOfSectors;
|
||||
sec_t dataStart;
|
||||
uint32_t bytesPerSector;
|
||||
uint32_t sectorsPerCluster;
|
||||
uint32_t bytesPerCluster;
|
||||
uint32_t fsInfoSector;
|
||||
FAT fat;
|
||||
/* Values that may change after construction */
|
||||
uint32_t cwdCluster; /* Current working directory cluster */
|
||||
int openFileCount;
|
||||
struct _FILE_STRUCT* firstOpenFile; /* The start of a linked list of files */
|
||||
mutex_t lock; /* A lock for partition operations */
|
||||
bool readOnly; /* If this is set, then do not try writing to the disc */
|
||||
char label[12]; /* Volume label */
|
||||
} PARTITION;
|
||||
|
||||
/*
|
||||
Mount the supplied device and return a pointer to the struct necessary to use it
|
||||
*/
|
||||
PARTITION* _FAT_partition_constructor (const DISC_INTERFACE* disc, uint32_t cacheSize, uint32_t SectorsPerPage, sec_t startSector);
|
||||
|
||||
/*
|
||||
Dismount the device and free all structures used.
|
||||
Will also attempt to synchronise all open files to disc.
|
||||
*/
|
||||
void _FAT_partition_destructor (PARTITION* partition);
|
||||
|
||||
/*
|
||||
Return the partition specified in a path, as taken from the devoptab.
|
||||
*/
|
||||
PARTITION* _FAT_partition_getPartitionFromPath (const char* path);
|
||||
|
||||
/*
|
||||
Create the fs info sector.
|
||||
*/
|
||||
void _FAT_partition_createFSinfo(PARTITION * partition);
|
||||
|
||||
/*
|
||||
Read the fs info sector data.
|
||||
*/
|
||||
void _FAT_partition_readFSinfo(PARTITION * partition);
|
||||
|
||||
/*
|
||||
Write the fs info sector data.
|
||||
*/
|
||||
void _FAT_partition_writeFSinfo(PARTITION * partition);
|
||||
|
||||
#endif /* _PARTITION_H */
|
|
@ -0,0 +1,966 @@
|
|||
/***************************************************************************
|
||||
* 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 <string.h>
|
||||
#include <malloc.h>
|
||||
#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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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, 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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
|
||||
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;
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
/***************************************************************************
|
||||
* 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 <stdint.h>
|
||||
|
||||
#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
|
|
@ -0,0 +1,974 @@
|
|||
/***************************************************************************
|
||||
* 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 <errno.h>
|
||||
#include <sys/statvfs.h>
|
||||
#include <sys/dirent.h>
|
||||
#include <string.h>
|
||||
#include <malloc.h>
|
||||
#include <stdint.h>
|
||||
#include <fcntl.h>
|
||||
#include <stdio.h>
|
||||
#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 *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, int 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, int 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, int 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, int 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, int 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, 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, int 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, int 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);
|
||||
}
|
|
@ -0,0 +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_
|
|
@ -0,0 +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 <string.h>
|
||||
#include <malloc.h>
|
||||
#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
|
||||
};
|
|
@ -0,0 +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 <stdint.h>
|
||||
#include <stdbool.h>
|
||||
|
||||
#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
|
|
@ -0,0 +1,44 @@
|
|||
#ifndef __OS_FUNCTIONS_H_
|
||||
#define __OS_FUNCTIONS_H_
|
||||
|
||||
#ifdef __cplusplus
|
||||
extern "C" {
|
||||
#endif
|
||||
|
||||
#define OS_MUTEX_SIZE 44
|
||||
|
||||
#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 // __OS_FUNCTIONS_H_
|
|
@ -2428,8 +2428,9 @@ STBTT_DEF void stbtt_Rasterize(stbtt__bitmap *result, float flatness_in_pixels,
|
|||
stbtt_vertex *vertices, int num_verts, float scale_x, float scale_y,
|
||||
float shift_x, float shift_y, int x_off, int y_off, int invert, void *userdata)
|
||||
{
|
||||
float scale = scale_x > scale_y ? scale_y : scale_x;
|
||||
int winding_count, *winding_lengths;
|
||||
float scale = scale_x > scale_y ? scale_y : scale_x;
|
||||
int winding_count = 0;
|
||||
int *winding_lengths = NULL;
|
||||
stbtt__point *windings = stbtt_FlattenCurves(vertices, num_verts, flatness_in_pixels / scale, &winding_lengths, &winding_count, userdata);
|
||||
if (windings)
|
||||
{
|
||||
|
|
|
@ -73,6 +73,7 @@ elif [ $PLATFORM = "dex-ps3" ] ; then
|
|||
platform=ps3
|
||||
SALAMANDER=yes
|
||||
EXT=a
|
||||
OPTS=DEX_BUILD=1
|
||||
|
||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||
MAKE_FSELF_NPDRM=${EXE_PATH}/make_fself_npdrm.exe
|
||||
|
@ -84,6 +85,7 @@ elif [ $PLATFORM = "cex-ps3" ]; then
|
|||
platform=ps3
|
||||
SALAMANDER=yes
|
||||
EXT=a
|
||||
OPTS=CEX_BUILD=1
|
||||
|
||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||
SCETOOL_PATH=${PS3TOOLS_PATH}/scetool/scetool.exe
|
||||
|
@ -98,6 +100,7 @@ elif [ $PLATFORM = "ode-ps3" ]; then
|
|||
platform=ps3
|
||||
SALAMANDER=yes
|
||||
EXT=a
|
||||
OPTS=ODE_BUILD=1
|
||||
|
||||
EXE_PATH=${CELL_SDK}/host-win32/bin
|
||||
GENPS3ISO_PATH=${PS3TOOLS_PATH}/ODE/genps3iso_v2.5
|
||||
|
@ -124,7 +127,7 @@ fi
|
|||
|
||||
# Compile Salamander core
|
||||
if [ $SALAMANDER = "yes" ]; then
|
||||
make -C ../ -f Makefile.${platform}.salamander || exit 1
|
||||
make -C ../ -f Makefile.${platform}.salamander $OPTS || exit 1
|
||||
if [ $PLATFORM = "psp1" ] ; then
|
||||
mv -f ../EBOOT.PBP ../pkg/${platform}/EBOOT.PBP
|
||||
fi
|
||||
|
@ -193,16 +196,16 @@ for f in `ls -v *_${platform}.${EXT}`; do
|
|||
|
||||
# Compile core
|
||||
if [ $MAKEFILE_GRIFFIN = "yes" ]; then
|
||||
make -C ../ -f Makefile.griffin platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
||||
make -C ../ -f Makefile.griffin $OPTS platform=${platform} $whole_archive $big_stack -j3 || exit 1
|
||||
elif [ $PLATFORM = "emscripten" ]; then
|
||||
echo "BUILD COMMAND: make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js"
|
||||
make -C ../ -f Makefile.emscripten PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js || exit 1
|
||||
make -C ../ -f Makefile.emscripten $OPTS PTHREAD=$pthread ASYNC=$async LTO=$lto -j7 TARGET=${name}_libretro.js || exit 1
|
||||
elif [ $PLATFORM = "unix" ]; then
|
||||
make -C ../ -f Makefile LINK=g++ $whole_archive $big_stack -j3 || exit 1
|
||||
elif [ $PLATFORM = "ctr" ]; then
|
||||
make -C ../ -f Makefile.${platform} LIBRETRO=$name $whole_archive $big_stack -j3 || exit 1
|
||||
make -C ../ -f Makefile.${platform} $OPTS LIBRETRO=$name $whole_archive $big_stack -j3 || exit 1
|
||||
else
|
||||
make -C ../ -f Makefile.${platform} $whole_archive $big_stack -j3 || exit 1
|
||||
make -C ../ -f Makefile.${platform} $OPTS $whole_archive $big_stack -j3 || exit 1
|
||||
fi
|
||||
|
||||
# Do manual executable step
|
||||
|
@ -354,17 +357,20 @@ fi
|
|||
|
||||
# Packaging
|
||||
if [ $PLATFORM = "dex-ps3" ] ; then
|
||||
rsync -av ../pkg/${platform}/SSNE10000/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||
$MAKE_FSELF_NPDRM -c ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
||||
rm -rf ../retroarch-salamander_${platform}.elf
|
||||
$MAKE_PACKAGE_NPDRM ../pkg/${platform}_dex/package.conf ../pkg/${platform}/SSNE10000
|
||||
mv UP0001-SSNE10000_00-0000000000000001.pkg ../pkg/${platform}/RetroArch.PS3.DEX.PS3.pkg
|
||||
elif [ $PLATFORM = "cex-ps3" ] ; then
|
||||
rsync -av ../pkg/${platform}/SSNE10000/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||
$SCETOOL_PATH $SCETOOL_FLAGS_EBOOT ../retroarch-salamander_${platform}.elf ../pkg/${platform}/SSNE10000/USRDIR/EBOOT.BIN
|
||||
rm -rf ../retroarch-salamander_${platform}.elf
|
||||
(cd ../tools/ps3/ps3py && python2 setup.py build)
|
||||
find ../tools/ps3/ps3py/build -name '*.dll' -exec cp {} ../tools/ps3/ps3py \;
|
||||
../tools/ps3/ps3py/pkg.py --contentid UP0001-SSNE10000_00-0000000000000001 ../pkg/${platform}/SSNE10000/ ../pkg/${platform}/RetroArch.PS3.CEX.PS3.pkg
|
||||
elif [ $PLATFORM = "ode-ps3" ] ; then
|
||||
rsync -av ../pkg/${platform}_iso/PS3_GAME/USRDIR/cores/*.SELF ../pkg/${platform}/${PLATFORM}/
|
||||
$SCETOOL_PATH $SCETOOL_FLAGS_ODE ../retroarch-salamander_${platform}.elf ../pkg/${platform}_iso/PS3_GAME/USRDIR/EBOOT.BIN
|
||||
rm -rf ../retroarch-salamander_${platform}.elf
|
||||
|
||||
|
|
|
@ -49,7 +49,7 @@
|
|||
#endif
|
||||
|
||||
static enum frontend_fork ctr_fork_mode = FRONTEND_FORK_NONE;
|
||||
static const char* elf_path_cst = "sdmc:/retroarch/test.3dsx";
|
||||
static const char* elf_path_cst = "sdmc:/retroarch/test.3dsx";
|
||||
|
||||
static void frontend_ctr_get_environment_settings(int *argc, char *argv[],
|
||||
void *args, void *params_data)
|
||||
|
@ -151,7 +151,7 @@ static void frontend_ctr_exec(const char *path, bool should_load_game)
|
|||
DEBUG_STR(path);
|
||||
|
||||
strlcpy(param.args, elf_path_cst, sizeof(param.args));
|
||||
len = strlen(param.args) + 1;
|
||||
len = strlen(param.args) + 1;
|
||||
param.argc = 1;
|
||||
|
||||
RARCH_LOG("Attempt to load core: [%s].\n", path);
|
||||
|
@ -172,11 +172,13 @@ static void frontend_ctr_exec(const char *path, bool should_load_game)
|
|||
}
|
||||
else
|
||||
{
|
||||
u32 app_ID_low;
|
||||
char app_ID_str[11];
|
||||
FILE* fp = fopen(path, "rb");
|
||||
u32 app_ID_low = 0;
|
||||
FILE* fp = fopen(path, "rb");
|
||||
size_t bytes_read = fread(app_ID_str, 1, sizeof(app_ID_str), fp);
|
||||
|
||||
fclose(fp);
|
||||
|
||||
if(bytes_read <= 0)
|
||||
{
|
||||
RARCH_LOG("error reading APP_ID from: [%s].\n", path);
|
||||
|
|
|
@ -254,6 +254,15 @@ static void frontend_ps3_get_environment_settings(int *argc, char *argv[],
|
|||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_PLAYLIST],
|
||||
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||
"playlists", sizeof(g_defaults.dirs[DEFAULT_DIR_PLAYLIST]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS],
|
||||
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||
"downloads", sizeof(g_defaults.dirs[DEFAULT_DIR_CORE_ASSETS]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_CHEATS],
|
||||
g_defaults.dirs[DEFAULT_DIR_CORE], "cheats",
|
||||
sizeof(g_defaults.dirs[DEFAULT_DIR_CHEATS]));
|
||||
fill_pathname_join(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG],
|
||||
g_defaults.dirs[DEFAULT_DIR_CORE],
|
||||
"autoconfig", sizeof(g_defaults.dirs[DEFAULT_DIR_AUTOCONFIG]));
|
||||
}
|
||||
|
||||
#ifndef IS_SALAMANDER
|
||||
|
|
|
@ -124,8 +124,8 @@ static void dol_copy_argv_path(const char *dolpath, const char *argpath)
|
|||
* heap memory and are restricted to the stack only. */
|
||||
void system_exec_wii(const char *_path, bool should_load_game)
|
||||
{
|
||||
FILE *fp;
|
||||
size_t size, booter_size;
|
||||
FILE *fp = NULL;
|
||||
void *dol = NULL;
|
||||
char path[PATH_MAX_LENGTH] = {0};
|
||||
char game_path[PATH_MAX_LENGTH] = {0};
|
||||
|
|
|
@ -188,8 +188,8 @@ static void frontend_wiiu_exec(const char *path, bool should_load_game)
|
|||
u32 argc;
|
||||
char * argv[3];
|
||||
char args[];
|
||||
}*param = getApplicationEndAddr();
|
||||
int len = 0;
|
||||
}*param = getApplicationEndAddr();
|
||||
int len = 0;
|
||||
param->argc = 0;
|
||||
|
||||
if(!path || !*path)
|
||||
|
@ -395,7 +395,7 @@ static devoptab_t dotab_stdout =
|
|||
};
|
||||
#endif
|
||||
|
||||
void SaveCallback()
|
||||
void SaveCallback(void)
|
||||
{
|
||||
OSSavesDone_ReadyToRelease();
|
||||
}
|
||||
|
@ -517,7 +517,7 @@ unsigned long _times_r(struct _reent *r, struct tms *tmsbuf)
|
|||
return 0;
|
||||
}
|
||||
|
||||
void __eabi()
|
||||
void __eabi(void)
|
||||
{
|
||||
|
||||
}
|
||||
|
@ -556,7 +556,7 @@ void someFunc(void *arg)
|
|||
|
||||
static int mcp_hook_fd = -1;
|
||||
|
||||
int MCPHookOpen()
|
||||
int MCPHookOpen(void)
|
||||
{
|
||||
//take over mcp thread
|
||||
mcp_hook_fd = IOS_Open("/dev/mcp", 0);
|
||||
|
@ -578,7 +578,7 @@ int MCPHookOpen()
|
|||
return 0;
|
||||
}
|
||||
|
||||
void MCPHookClose()
|
||||
void MCPHookClose(void)
|
||||
{
|
||||
if (mcp_hook_fd < 0)
|
||||
return;
|
||||
|
@ -630,12 +630,14 @@ static void fsdev_exit(void)
|
|||
/* HBL elf entry point */
|
||||
int __entry_menu(int argc, char **argv)
|
||||
{
|
||||
int ret;
|
||||
|
||||
InitFunctionPointers();
|
||||
memoryInitialize();
|
||||
__init();
|
||||
fsdev_init();
|
||||
|
||||
int ret = main(argc, argv);
|
||||
ret = main(argc, argv);
|
||||
|
||||
fsdev_exit();
|
||||
__fini();
|
||||
|
@ -654,9 +656,11 @@ void _start(int argc, char **argv)
|
|||
|
||||
fsdev_exit();
|
||||
|
||||
/* TODO: fix elf2rpl so it doesn't error with "Could not find matching symbol
|
||||
for relocation" then uncomment this */
|
||||
// __fini();
|
||||
/* TODO: fix elf2rpl so it doesn't error with "Could not find matching symbol
|
||||
for relocation" then uncomment this */
|
||||
#if 0
|
||||
__fini();
|
||||
#endif
|
||||
memoryRelease();
|
||||
SYSRelaunchTitle(0, 0);
|
||||
exit(0);
|
||||
|
|
|
@ -86,8 +86,8 @@ bool g_restore_desktop = false;
|
|||
static bool doubleclick_on_titlebar = false;
|
||||
bool g_inited = false;
|
||||
static bool g_quit = false;
|
||||
static unsigned g_pos_x = CW_USEDEFAULT;
|
||||
static unsigned g_pos_y = CW_USEDEFAULT;
|
||||
static int g_pos_x = CW_USEDEFAULT;
|
||||
static int g_pos_y = CW_USEDEFAULT;
|
||||
static void *curD3D = NULL;
|
||||
|
||||
ui_window_win32_t main_window;
|
||||
|
@ -513,7 +513,11 @@ static LRESULT CALLBACK WndProcCommon(bool *quit, HWND hwnd, UINT message,
|
|||
case WM_QUIT:
|
||||
{
|
||||
WINDOWPLACEMENT placement;
|
||||
memset(&placement, 0, sizeof(placement));
|
||||
placement.length = sizeof(placement);
|
||||
|
||||
GetWindowPlacement(main_window.hwnd, &placement);
|
||||
|
||||
g_pos_x = placement.rcNormalPosition.left;
|
||||
g_pos_y = placement.rcNormalPosition.top;
|
||||
g_quit = true;
|
||||
|
|
|
@ -109,7 +109,7 @@ void x11_show_mouse(Display *dpy, Window win, bool state)
|
|||
|
||||
void x11_windowed_fullscreen(Display *dpy, Window win)
|
||||
{
|
||||
XEvent xev = {0};
|
||||
XEvent xev = {0};
|
||||
|
||||
XA_NET_WM_STATE = XInternAtom(dpy, "_NET_WM_STATE", False);
|
||||
XA_NET_WM_STATE_FULLSCREEN = XInternAtom(dpy, "_NET_WM_STATE_FULLSCREEN", False);
|
||||
|
@ -132,7 +132,7 @@ void x11_windowed_fullscreen(Display *dpy, Window win)
|
|||
void x11_move_window(Display *dpy, Window win, int x, int y,
|
||||
unsigned width, unsigned height)
|
||||
{
|
||||
XEvent xev = {0};
|
||||
XEvent xev = {0};
|
||||
|
||||
XA_NET_MOVERESIZE_WINDOW = XInternAtom(dpy, "_NET_MOVERESIZE_WINDOW", False);
|
||||
|
||||
|
@ -162,9 +162,9 @@ static void x11_set_window_class(Display *dpy, Window win)
|
|||
|
||||
static void x11_set_window_pid(Display *dpy, Window win)
|
||||
{
|
||||
long scret;
|
||||
char *hostname;
|
||||
pid_t pid = getpid();
|
||||
long scret = 0;
|
||||
char *hostname = NULL;
|
||||
pid_t pid = getpid();
|
||||
|
||||
XChangeProperty(dpy, win, XInternAtom(dpy, "_NET_WM_PID", False),
|
||||
XA_CARDINAL, 32, PropModeReplace, (unsigned char *)&pid, 1);
|
||||
|
@ -238,9 +238,9 @@ static bool get_video_mode(video_frame_info_t *video_info,
|
|||
Display *dpy, unsigned width, unsigned height,
|
||||
XF86VidModeModeInfo *mode, XF86VidModeModeInfo *desktop_mode)
|
||||
{
|
||||
float refresh_mod;
|
||||
int i, num_modes = 0;
|
||||
bool ret = false;
|
||||
float refresh_mod = 0.0f;
|
||||
float minimum_fps_diff = 0.0f;
|
||||
XF86VidModeModeInfo **modes = NULL;
|
||||
|
||||
|
@ -386,15 +386,15 @@ bool x11_get_metrics(void *data,
|
|||
static void x11_handle_key_event(XEvent *event, XIC ic, bool filter)
|
||||
{
|
||||
int i;
|
||||
unsigned key;
|
||||
uint32_t chars[32];
|
||||
unsigned key = 0;
|
||||
uint16_t mod = 0;
|
||||
unsigned state = event->xkey.state;
|
||||
bool down = event->type == KeyPress;
|
||||
int num = 0;
|
||||
KeySym keysym = 0;
|
||||
bool down = event->type == KeyPress;
|
||||
int num = 0;
|
||||
KeySym keysym = 0;
|
||||
|
||||
chars[0] = '\0';
|
||||
chars[0] = '\0';
|
||||
|
||||
if (!filter)
|
||||
{
|
||||
|
|
|
@ -28,6 +28,9 @@ static void* win32_display_server_init(void)
|
|||
{
|
||||
dispserv_win32_t *dispserv = (dispserv_win32_t*)calloc(1, sizeof(*dispserv));
|
||||
|
||||
if (!dispserv)
|
||||
return NULL;
|
||||
|
||||
return dispserv;
|
||||
}
|
||||
|
||||
|
@ -38,17 +41,17 @@ static void win32_display_server_destroy(void)
|
|||
|
||||
static bool win32_set_window_opacity(void *data, unsigned opacity)
|
||||
{
|
||||
HWND hwnd = win32_get_window();
|
||||
HWND hwnd = win32_get_window();
|
||||
dispserv_win32_t *serv = (dispserv_win32_t*)data;
|
||||
|
||||
serv->opacity = opacity;
|
||||
serv->opacity = opacity;
|
||||
|
||||
#if defined(_WIN32_WINNT) && _WIN32_WINNT >= 0x0500
|
||||
/* Set window transparency on Windows 2000 and above */
|
||||
return SetLayeredWindowAttributes(hwnd, 0, (255 * opacity) / 100, LWA_ALPHA);
|
||||
#else
|
||||
return false;
|
||||
if (SetLayeredWindowAttributes(hwnd, 0, (255 * opacity) / 100, LWA_ALPHA))
|
||||
return true;
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
const video_display_server_t dispserv_win32 = {
|
||||
|
|
|
@ -28,6 +28,9 @@ static void* x11_display_server_init(void)
|
|||
{
|
||||
dispserv_x11_t *dispserv = (dispserv_x11_t*)calloc(1, sizeof(*dispserv));
|
||||
|
||||
if (!dispserv)
|
||||
return NULL;
|
||||
|
||||
return dispserv;
|
||||
}
|
||||
|
||||
|
@ -39,13 +42,13 @@ static void x11_display_server_destroy(void)
|
|||
static bool x11_set_window_opacity(void *data, unsigned opacity)
|
||||
{
|
||||
dispserv_x11_t *serv = (dispserv_x11_t*)data;
|
||||
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
||||
Atom cardinal = XInternAtom(g_x11_dpy, "CARDINAL", False);
|
||||
Atom net_wm_opacity = XInternAtom(g_x11_dpy, "_NET_WM_WINDOW_OPACITY", False);
|
||||
Atom cardinal = XInternAtom(g_x11_dpy, "CARDINAL", False);
|
||||
settings_t *settings = config_get_ptr();
|
||||
|
||||
serv->opacity = opacity;
|
||||
serv->opacity = opacity;
|
||||
|
||||
opacity = opacity * ((unsigned)-1 / 100.0);
|
||||
opacity = opacity * ((unsigned)-1 / 100.0);
|
||||
|
||||
if (opacity == (unsigned)-1)
|
||||
XDeleteProperty(g_x11_dpy, g_x11_win, net_wm_opacity);
|
||||
|
|
|
@ -238,7 +238,7 @@ static void ctr_lcd_aptHook(APT_HookType hook, void* param)
|
|||
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 0 |
|
||||
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 4,
|
||||
sizeof(ctr_vertex_t));
|
||||
GPUCMD_Finalize();
|
||||
GPU_Finalize();
|
||||
ctrGuFlushAndRun(true);
|
||||
gspWaitForEvent(GSPGPU_EVENT_P3D, false);
|
||||
ctr->p3d_event_pending = false;
|
||||
|
@ -407,7 +407,7 @@ static void* ctr_init(const video_info_t* video,
|
|||
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 0 |
|
||||
CTRGU_ATTRIBFMT(GPU_SHORT, 4) << 4,
|
||||
sizeof(ctr_vertex_t));
|
||||
GPUCMD_Finalize();
|
||||
GPU_Finalize();
|
||||
ctrGuFlushAndRun(true);
|
||||
|
||||
ctr->p3d_event_pending = true;
|
||||
|
@ -779,7 +779,7 @@ static bool ctr_frame(void* data, const void* frame,
|
|||
#endif
|
||||
|
||||
GPU_FinishDrawing();
|
||||
GPUCMD_Finalize();
|
||||
GPU_Finalize();
|
||||
ctrGuFlushAndRun(true);
|
||||
|
||||
ctrGuDisplayTransfer(true, ctr->drawbuffers.top.left,
|
||||
|
|
|
@ -34,7 +34,7 @@ static const font_renderer_driver_t *font_backends[] = {
|
|||
&coretext_font_renderer,
|
||||
#endif
|
||||
#ifdef HAVE_STB_FONT
|
||||
#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) || defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER) && _MSC_VER > 1400
|
||||
#if defined(VITA) || defined(WIIU) || defined(ANDROID) || defined(_WIN32) && !defined(_XBOX) && !defined(_MSC_VER) || (defined(_WIN32) && !defined(_XBOX) && defined(_MSC_VER) && _MSC_VER > 1400) || defined(__CELLOS_LV2__)
|
||||
&stb_unicode_font_renderer,
|
||||
#else
|
||||
&stb_font_renderer,
|
||||
|
|
|
@ -29,16 +29,16 @@ void* video_display_server_init(void)
|
|||
|
||||
switch (type)
|
||||
{
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
case RARCH_DISPLAY_WIN32:
|
||||
#if defined(_WIN32) && !defined(_XBOX)
|
||||
current_display_server = &dispserv_win32;
|
||||
break;
|
||||
#endif
|
||||
#if defined(HAVE_X11)
|
||||
break;
|
||||
case RARCH_DISPLAY_X11:
|
||||
#if defined(HAVE_X11)
|
||||
current_display_server = &dispserv_x11;
|
||||
break;
|
||||
#endif
|
||||
break;
|
||||
default:
|
||||
current_display_server = &dispserv_null;
|
||||
break;
|
||||
|
|
|
@ -955,7 +955,7 @@ static bool video_driver_init_internal(bool *video_is_threaded)
|
|||
video_driver_set_aspect_ratio_value(
|
||||
aspectratio_lut[settings->uints.video_aspect_ratio_idx].value);
|
||||
|
||||
if (settings->bools.video_fullscreen)
|
||||
if (settings->bools.video_fullscreen|| retroarch_is_forced_fullscreen())
|
||||
{
|
||||
width = settings->uints.video_fullscreen_x;
|
||||
height = settings->uints.video_fullscreen_y;
|
||||
|
@ -999,7 +999,7 @@ static bool video_driver_init_internal(bool *video_is_threaded)
|
|||
|
||||
video.width = width;
|
||||
video.height = height;
|
||||
video.fullscreen = settings->bools.video_fullscreen;
|
||||
video.fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen();
|
||||
video.vsync = settings->bools.video_vsync && !rarch_ctl(RARCH_CTL_IS_NONBLOCK_FORCED, NULL);
|
||||
video.force_aspect = settings->bools.video_force_aspect;
|
||||
video.font_enable = settings->bools.video_font_enable;
|
||||
|
@ -2515,7 +2515,7 @@ void video_driver_build_info(video_frame_info_t *video_info)
|
|||
video_info->post_filter_record = settings->bools.video_post_filter_record;
|
||||
video_info->max_swapchain_images = settings->uints.video_max_swapchain_images;
|
||||
video_info->windowed_fullscreen = settings->bools.video_windowed_fullscreen;
|
||||
video_info->fullscreen = settings->bools.video_fullscreen;
|
||||
video_info->fullscreen = settings->bools.video_fullscreen || retroarch_is_forced_fullscreen();
|
||||
video_info->monitor_index = settings->uints.video_monitor_index;
|
||||
video_info->shared_context = settings->bools.video_shared_context;
|
||||
|
||||
|
|
|
@ -587,7 +587,6 @@ bool video_shader_resolve_parameters(config_file_t *conf,
|
|||
|
||||
free(line);
|
||||
intfstream_close(file);
|
||||
free(file);
|
||||
}
|
||||
|
||||
if (conf && !video_shader_resolve_current_parameters(conf, shader))
|
||||
|
|
|
@ -84,6 +84,7 @@ int32_t pad_connection_pad_init(joypad_connection_t *joyconn,
|
|||
{ "Wii U GC Controller Adapter", 1406, 823, &pad_connection_wiiugca },
|
||||
{ "PS2/PSX Controller Adapter", 2064, 1, &pad_connection_ps2adapter },
|
||||
{ "PSX to PS3 Controller Adapter", 2064, 3, &pad_connection_psxadapter },
|
||||
{ "Mayflash DolphinBar", 1406, 774, &pad_connection_wii },
|
||||
{ 0, 0}
|
||||
};
|
||||
joypad_connection_t *s = NULL;
|
||||
|
|
|
@ -1429,11 +1429,6 @@ static int16_t android_input_state(void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool android_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void android_input_free_input(void *data)
|
||||
{
|
||||
android_input_t *android = (android_input_t*)data;
|
||||
|
@ -1587,7 +1582,6 @@ input_driver_t input_android = {
|
|||
android_input_init,
|
||||
android_input_poll,
|
||||
android_input_state,
|
||||
android_input_meta_key_pressed,
|
||||
android_input_free_input,
|
||||
android_input_set_sensor_state,
|
||||
android_input_get_sensor_input,
|
||||
|
|
|
@ -328,11 +328,6 @@ static int16_t cocoa_input_state(void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool cocoa_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void cocoa_input_free(void *data)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -426,7 +421,6 @@ input_driver_t input_cocoa = {
|
|||
cocoa_input_init,
|
||||
cocoa_input_poll,
|
||||
cocoa_input_state,
|
||||
cocoa_input_meta_key_pressed,
|
||||
cocoa_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -35,8 +35,6 @@ typedef struct ctr_input
|
|||
const input_device_driver_t *joypad;
|
||||
} ctr_input_t;
|
||||
|
||||
uint64_t lifecycle_state;
|
||||
|
||||
static void ctr_input_poll(void *data)
|
||||
{
|
||||
ctr_input_t *ctr = (ctr_input_t*)data;
|
||||
|
@ -92,14 +90,6 @@ static void* ctr_input_init(const char *joypad_driver)
|
|||
return ctr;
|
||||
}
|
||||
|
||||
static bool ctr_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
if (BIT64_GET(lifecycle_state, key))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t ctr_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -152,7 +142,6 @@ input_driver_t input_ctr = {
|
|||
ctr_input_init,
|
||||
ctr_input_poll,
|
||||
ctr_input_state,
|
||||
ctr_input_meta_key_pressed,
|
||||
ctr_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -364,11 +364,6 @@ static int16_t dinput_pressed_analog(struct dinput_input *di,
|
|||
return pressed_plus + pressed_minus;
|
||||
}
|
||||
|
||||
static bool dinput_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int16_t dinput_lightgun_aiming_state( struct dinput_input *di, unsigned idx, unsigned id )
|
||||
{
|
||||
const int edge_detect = 32700;
|
||||
|
@ -925,7 +920,6 @@ input_driver_t input_dinput = {
|
|||
dinput_init,
|
||||
dinput_poll,
|
||||
dinput_input_state,
|
||||
dinput_meta_key_pressed,
|
||||
dinput_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -86,11 +86,6 @@ static void* dos_input_init(const char *joypad_driver)
|
|||
return dos;
|
||||
}
|
||||
|
||||
static bool dos_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t dos_input_get_capabilities(void *data)
|
||||
{
|
||||
uint64_t caps = 0;
|
||||
|
@ -129,7 +124,6 @@ input_driver_t input_dos = {
|
|||
dos_input_init,
|
||||
dos_input_poll,
|
||||
dos_input_state,
|
||||
dos_input_meta_key_pressed,
|
||||
dos_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -31,8 +31,6 @@
|
|||
#define MAX_PADS 4
|
||||
#endif
|
||||
|
||||
uint64_t lifecycle_state;
|
||||
|
||||
typedef struct gx_input
|
||||
{
|
||||
bool blocked;
|
||||
|
@ -97,14 +95,6 @@ static void gx_input_poll(void *data)
|
|||
gx->joypad->poll();
|
||||
}
|
||||
|
||||
static bool gx_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
if (BIT64_GET(lifecycle_state, key))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t gx_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -157,7 +147,6 @@ input_driver_t input_gx = {
|
|||
gx_input_init,
|
||||
gx_input_poll,
|
||||
gx_input_state,
|
||||
gx_input_meta_key_pressed,
|
||||
gx_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -93,11 +93,6 @@ static int16_t linuxraw_analog_pressed(linuxraw_input_t *linuxraw,
|
|||
return pressed_plus + pressed_minus;
|
||||
}
|
||||
|
||||
static bool linuxraw_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int16_t linuxraw_input_state(void *data,
|
||||
rarch_joypad_info_t joypad_info,
|
||||
const struct retro_keybind **binds, unsigned port,
|
||||
|
@ -223,7 +218,6 @@ input_driver_t input_linuxraw = {
|
|||
linuxraw_input_init,
|
||||
linuxraw_input_poll,
|
||||
linuxraw_input_state,
|
||||
linuxraw_input_meta_key_pressed,
|
||||
linuxraw_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -43,14 +43,6 @@ static int16_t nullinput_input_state(void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool nullinput_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
(void)data;
|
||||
(void)key;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static void nullinput_input_free_input(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -100,7 +92,6 @@ input_driver_t input_null = {
|
|||
nullinput_input_init,
|
||||
nullinput_input_poll,
|
||||
nullinput_input_state,
|
||||
nullinput_input_meta_key_pressed,
|
||||
nullinput_input_free_input,
|
||||
nullinput_set_sensor_state,
|
||||
NULL,
|
||||
|
|
|
@ -179,11 +179,6 @@ static void* ps3_input_init(const char *joypad_driver)
|
|||
return ps3;
|
||||
}
|
||||
|
||||
static bool ps3_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t ps3_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -266,7 +261,6 @@ input_driver_t input_ps3 = {
|
|||
ps3_input_init,
|
||||
ps3_input_poll,
|
||||
ps3_input_state,
|
||||
ps3_input_meta_key_pressed,
|
||||
ps3_input_free_input,
|
||||
ps3_input_set_sensor_state,
|
||||
NULL,
|
||||
|
|
|
@ -49,8 +49,6 @@ typedef struct psp_input
|
|||
const input_device_driver_t *joypad;
|
||||
} psp_input_t;
|
||||
|
||||
uint64_t lifecycle_state;
|
||||
|
||||
static void psp_input_poll(void *data)
|
||||
{
|
||||
psp_input_t *psp = (psp_input_t*)data;
|
||||
|
@ -106,11 +104,6 @@ static void* psp_input_initialize(const char *joypad_driver)
|
|||
return psp;
|
||||
}
|
||||
|
||||
static bool psp_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return (BIT64_GET(lifecycle_state, key));
|
||||
}
|
||||
|
||||
static uint64_t psp_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -163,7 +156,6 @@ input_driver_t input_psp = {
|
|||
psp_input_initialize,
|
||||
psp_input_poll,
|
||||
psp_input_state,
|
||||
psp_input_meta_key_pressed,
|
||||
psp_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -803,11 +803,6 @@ static int16_t qnx_input_state(void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool qnx_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void qnx_input_free_input(void *data)
|
||||
{
|
||||
if (data)
|
||||
|
@ -853,7 +848,6 @@ input_driver_t input_qnx = {
|
|||
qnx_input_init,
|
||||
qnx_input_poll,
|
||||
qnx_input_state,
|
||||
qnx_input_meta_key_pressed,
|
||||
qnx_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -81,13 +81,6 @@ static bool rwebinput_key_pressed_internal(void *data, int key)
|
|||
return ret;
|
||||
}
|
||||
|
||||
static bool rwebinput_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
(void)data;
|
||||
(void)key;
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool rwebinput_is_pressed(rwebinput_input_t *rwebinput,
|
||||
const struct retro_keybind *binds, unsigned id)
|
||||
{
|
||||
|
@ -254,7 +247,6 @@ input_driver_t input_rwebinput = {
|
|||
rwebinput_input_init,
|
||||
rwebinput_input_poll,
|
||||
rwebinput_input_state,
|
||||
rwebinput_meta_key_pressed,
|
||||
rwebinput_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -89,11 +89,6 @@ static int16_t sdl_analog_pressed(sdl_input_t *sdl, const struct retro_keybind *
|
|||
return pressed_plus + pressed_minus;
|
||||
}
|
||||
|
||||
static bool sdl_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int16_t sdl_joypad_device_state(sdl_input_t *sdl,
|
||||
rarch_joypad_info_t joypad_info,
|
||||
const struct retro_keybind *binds,
|
||||
|
@ -409,7 +404,6 @@ input_driver_t input_sdl = {
|
|||
sdl_input_init,
|
||||
sdl_input_poll,
|
||||
sdl_input_state,
|
||||
sdl_input_meta_key_pressed,
|
||||
sdl_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -907,11 +907,6 @@ static int16_t udev_input_state(void *data,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool udev_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void udev_input_free(void *data)
|
||||
{
|
||||
unsigned i;
|
||||
|
@ -1160,7 +1155,6 @@ input_driver_t input_udev = {
|
|||
udev_input_init,
|
||||
udev_input_poll,
|
||||
udev_input_state,
|
||||
udev_input_meta_key_pressed,
|
||||
udev_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -320,19 +320,10 @@ static void input_wl_keyboard_mapping_set_block(void *data, bool value)
|
|||
wl->blocked = value;
|
||||
}
|
||||
|
||||
static bool input_wl_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
(void)data;
|
||||
(void)key;
|
||||
/* FIXME: What is this supposed to do? */
|
||||
return false;
|
||||
}
|
||||
|
||||
input_driver_t input_wayland = {
|
||||
NULL,
|
||||
input_wl_poll,
|
||||
input_wl_state,
|
||||
input_wl_meta_key_pressed,
|
||||
input_wl_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -46,9 +46,6 @@ typedef struct wiiu_input
|
|||
const input_device_driver_t *joypad;
|
||||
} wiiu_input_t;
|
||||
|
||||
uint64_t lifecycle_state;
|
||||
|
||||
|
||||
void kb_connection_callback(KBDKeyEvent *key)
|
||||
{
|
||||
keyboardChannel = keyboardChannel + (key->channel + 0x01);
|
||||
|
@ -200,14 +197,6 @@ static void* wiiu_input_init(const char *joypad_driver)
|
|||
return wiiu;
|
||||
}
|
||||
|
||||
static bool wiiu_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
if (BIT64_GET(lifecycle_state, key))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t wiiu_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -263,7 +252,6 @@ input_driver_t input_wiiu = {
|
|||
wiiu_input_init,
|
||||
wiiu_input_poll,
|
||||
wiiu_input_state,
|
||||
wiiu_input_meta_key_pressed,
|
||||
wiiu_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -762,11 +762,6 @@ static int16_t winraw_input_state(void *d,
|
|||
return 0;
|
||||
}
|
||||
|
||||
static bool winraw_meta_key_pressed(void *u1, int u2)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static void winraw_free(void *d)
|
||||
{
|
||||
winraw_input_t *wr = (winraw_input_t*)d;
|
||||
|
@ -841,7 +836,6 @@ input_driver_t input_winraw = {
|
|||
winraw_init,
|
||||
winraw_poll,
|
||||
winraw_input_state,
|
||||
winraw_meta_key_pressed,
|
||||
winraw_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -179,11 +179,6 @@ static int16_t x_pressed_analog(x11_input_t *x11,
|
|||
return pressed_plus + pressed_minus;
|
||||
}
|
||||
|
||||
static bool x_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static int16_t x_lightgun_aiming_state( x11_input_t *x11, unsigned idx, unsigned id )
|
||||
{
|
||||
const int edge_detect = 32700;
|
||||
|
@ -531,7 +526,6 @@ input_driver_t input_x = {
|
|||
x_input_init,
|
||||
x_input_poll,
|
||||
x_input_state,
|
||||
x_input_meta_key_pressed,
|
||||
x_input_free,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -94,11 +94,6 @@ static void *xdk_input_init(const char *joypad_driver)
|
|||
return xdk;
|
||||
}
|
||||
|
||||
static bool xdk_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static uint64_t xdk_input_get_capabilities(void *data)
|
||||
{
|
||||
(void)data;
|
||||
|
@ -178,7 +173,6 @@ input_driver_t input_xinput = {
|
|||
xdk_input_init,
|
||||
xdk_input_poll,
|
||||
xdk_input_state,
|
||||
xdk_input_meta_key_pressed,
|
||||
xdk_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -90,11 +90,6 @@ static void* xenon360_input_init(const char *joypad_driver)
|
|||
return (void*)-1;
|
||||
}
|
||||
|
||||
static bool xenon360_input_meta_key_pressed(void *data, int key)
|
||||
{
|
||||
return (state & (UINT64_C(1) << key));
|
||||
}
|
||||
|
||||
static uint64_t xenon360_input_get_capabilities(void *data)
|
||||
{
|
||||
uint64_t caps = 0;
|
||||
|
@ -125,7 +120,6 @@ input_driver_t input_xenon360 = {
|
|||
xenon360_input_init,
|
||||
xenon360_input_poll,
|
||||
xenon360_input_state,
|
||||
xenon360_input_meta_key_pressed,
|
||||
xenon360_input_free_input,
|
||||
NULL,
|
||||
NULL,
|
||||
|
|
|
@ -475,7 +475,7 @@ static void xinput_joypad_poll(void)
|
|||
{
|
||||
if (g_xinput_states[i].connected)
|
||||
{
|
||||
if (g_XInputGetStateEx(i,
|
||||
if (g_XInputGetStateEx && g_XInputGetStateEx(i,
|
||||
&(g_xinput_states[i].xstate))
|
||||
== ERROR_DEVICE_NOT_CONNECTED)
|
||||
g_xinput_states[i].connected = false;
|
||||
|
@ -507,6 +507,9 @@ static bool xinput_joypad_rumble(unsigned pad,
|
|||
else if (effect == RETRO_RUMBLE_WEAK)
|
||||
g_xinput_rumble_states[xuser].wRightMotorSpeed = strength;
|
||||
|
||||
if (!g_XInputSetState)
|
||||
return false;
|
||||
|
||||
return (g_XInputSetState(xuser, &g_xinput_rumble_states[xuser])
|
||||
== 0);
|
||||
}
|
||||
|
|
|
@ -233,6 +233,7 @@ static const uint8_t buttons[] = {
|
|||
static uint16_t input_config_vid[MAX_USERS];
|
||||
static uint16_t input_config_pid[MAX_USERS];
|
||||
|
||||
uint64_t lifecycle_state;
|
||||
char input_device_names[MAX_INPUT_DEVICES][64];
|
||||
struct retro_keybind input_config_binds[MAX_USERS][RARCH_BIND_LIST_END];
|
||||
struct retro_keybind input_autoconf_binds[MAX_USERS][RARCH_BIND_LIST_END];
|
||||
|
@ -784,6 +785,42 @@ void state_tracker_update_input(uint16_t *input1, uint16_t *input2)
|
|||
}
|
||||
}
|
||||
|
||||
static INLINE bool input_keys_pressed_iterate(unsigned i,
|
||||
retro_bits_t* p_new_state)
|
||||
{
|
||||
if ((i >= RARCH_FIRST_META_KEY) &&
|
||||
BIT64_GET(lifecycle_state, i)
|
||||
)
|
||||
return true;
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (overlay_ptr &&
|
||||
input_overlay_key_pressed(overlay_ptr, i))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_COMMAND
|
||||
if (input_driver_command)
|
||||
{
|
||||
command_handle_t handle;
|
||||
|
||||
handle.handle = input_driver_command;
|
||||
handle.id = i;
|
||||
|
||||
if (command_get(&handle))
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKGAMEPAD
|
||||
if (input_driver_remote &&
|
||||
input_remote_key_pressed(i, 0))
|
||||
return true;
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
#ifdef HAVE_MENU
|
||||
|
||||
/**
|
||||
|
@ -857,9 +894,11 @@ void input_menu_keys_pressed(void *data, retro_bits_t* p_new_state)
|
|||
|
||||
for (i = 0; i < RARCH_BIND_LIST_END; i++)
|
||||
{
|
||||
bool bit_pressed = false;
|
||||
|
||||
if (
|
||||
(((!input_driver_block_libretro_input && ((i < RARCH_FIRST_META_KEY)))
|
||||
|| !input_driver_block_hotkey))
|
||||
(!input_driver_block_libretro_input && ((i < RARCH_FIRST_META_KEY)))
|
||||
|| !input_driver_block_hotkey
|
||||
)
|
||||
{
|
||||
const input_device_driver_t *first = current_input->get_joypad_driver
|
||||
|
@ -869,21 +908,20 @@ void input_menu_keys_pressed(void *data, retro_bits_t* p_new_state)
|
|||
|
||||
for (port = 0; port < port_max; port++)
|
||||
{
|
||||
uint64_t joykey = 0;
|
||||
uint32_t joyaxis = 0;
|
||||
bool pressed = false;
|
||||
uint64_t joykey = 0;
|
||||
uint32_t joyaxis = 0;
|
||||
const struct retro_keybind *mtkey = &input_config_binds[port][i];
|
||||
|
||||
if (!mtkey->valid)
|
||||
continue;
|
||||
|
||||
joypad_info.joy_idx = settings->uints.input_joypad_map[port];
|
||||
joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx];
|
||||
joypad_info.axis_threshold = input_driver_axis_threshold;
|
||||
joypad_info.joy_idx = settings->uints.input_joypad_map[port];
|
||||
joypad_info.auto_binds = input_autoconf_binds[joypad_info.joy_idx];
|
||||
joypad_info.axis_threshold = input_driver_axis_threshold;
|
||||
|
||||
joykey = (input_config_binds[port][i].joykey != NO_BTN)
|
||||
joykey = (input_config_binds[port][i].joykey != NO_BTN)
|
||||
? input_config_binds[port][i].joykey : joypad_info.auto_binds[i].joykey;
|
||||
joyaxis = (input_config_binds[port][i].joyaxis != AXIS_NONE)
|
||||
joyaxis = (input_config_binds[port][i].joyaxis != AXIS_NONE)
|
||||
? input_config_binds[port][i].joyaxis : joypad_info.auto_binds[i].joyaxis;
|
||||
|
||||
if (sec)
|
||||
|
@ -892,72 +930,33 @@ void input_menu_keys_pressed(void *data, retro_bits_t* p_new_state)
|
|||
{
|
||||
int16_t axis = sec->axis(joypad_info.joy_idx, joyaxis);
|
||||
float scaled_axis = (float)abs(axis) / 0x8000;
|
||||
pressed = scaled_axis > joypad_info.axis_threshold;
|
||||
bit_pressed = scaled_axis > joypad_info.axis_threshold;
|
||||
}
|
||||
else
|
||||
pressed = true;
|
||||
bit_pressed = true;
|
||||
}
|
||||
|
||||
if (!pressed && first)
|
||||
if (!bit_pressed && first)
|
||||
{
|
||||
if ((uint16_t)joykey == NO_BTN || !first->button(joypad_info.joy_idx, (uint16_t)joykey))
|
||||
{
|
||||
int16_t axis = first->axis(joypad_info.joy_idx, joyaxis);
|
||||
float scaled_axis = (float)abs(axis) / 0x8000;
|
||||
pressed = scaled_axis > joypad_info.axis_threshold;
|
||||
bit_pressed = scaled_axis > joypad_info.axis_threshold;
|
||||
}
|
||||
else
|
||||
pressed = true;
|
||||
bit_pressed = true;
|
||||
}
|
||||
|
||||
if (pressed)
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
if (bit_pressed)
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (i >= RARCH_FIRST_META_KEY)
|
||||
{
|
||||
if (current_input->meta_key_pressed(current_input_data, i))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (overlay_ptr && input_overlay_key_pressed(overlay_ptr, i))
|
||||
if (bit_pressed || input_keys_pressed_iterate(i, p_new_state))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_COMMAND
|
||||
if (input_driver_command)
|
||||
{
|
||||
command_handle_t handle;
|
||||
|
||||
handle.handle = input_driver_command;
|
||||
handle.id = i;
|
||||
|
||||
if (command_get(&handle))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKGAMEPAD
|
||||
if (input_driver_remote && input_remote_key_pressed(i, 0))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
for (i = 0; i < max_users; i++)
|
||||
|
@ -1077,6 +1076,8 @@ void input_keys_pressed(void *data, retro_bits_t* p_new_state)
|
|||
|
||||
for (i = 0; i < RARCH_BIND_LIST_END; i++)
|
||||
{
|
||||
bool bit_pressed = false;
|
||||
|
||||
if (
|
||||
((!input_driver_block_libretro_input && ((i < RARCH_FIRST_META_KEY)))
|
||||
|| !input_driver_block_hotkey) &&
|
||||
|
@ -1084,56 +1085,15 @@ void input_keys_pressed(void *data, retro_bits_t* p_new_state)
|
|||
joypad_info, &binds,
|
||||
0, RETRO_DEVICE_JOYPAD, 0, i)
|
||||
)
|
||||
bit_pressed = true;
|
||||
|
||||
if (bit_pressed || input_keys_pressed_iterate(i, p_new_state))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
if ((i >= RARCH_FIRST_META_KEY) &&
|
||||
current_input->meta_key_pressed(current_input_data, i)
|
||||
)
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
|
||||
#ifdef HAVE_OVERLAY
|
||||
if (overlay_ptr &&
|
||||
input_overlay_key_pressed(overlay_ptr, i))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_COMMAND
|
||||
if (input_driver_command)
|
||||
{
|
||||
command_handle_t handle;
|
||||
|
||||
handle.handle = input_driver_command;
|
||||
handle.id = i;
|
||||
|
||||
if (command_get(&handle))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef HAVE_NETWORKGAMEPAD
|
||||
if (input_driver_remote &&
|
||||
input_remote_key_pressed(i, 0))
|
||||
{
|
||||
BIT256_SET_PTR(p_new_state, i);
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void *input_driver_get_data(void)
|
||||
{
|
||||
return current_input_data;
|
||||
|
|
|
@ -147,8 +147,6 @@ typedef struct input_driver
|
|||
const struct retro_keybind **retro_keybinds,
|
||||
unsigned port, unsigned device, unsigned index, unsigned id);
|
||||
|
||||
bool (*meta_key_pressed)(void *data, int key);
|
||||
|
||||
/* Frees the input struct. */
|
||||
void (*free)(void *data);
|
||||
|
||||
|
|
|
@ -43,7 +43,7 @@ typedef struct input_overlay_state
|
|||
int16_t analog[4];
|
||||
uint32_t keys[RETROK_LAST / 32 + 1];
|
||||
/* This is a bitmask of (1 << key_bind_id). */
|
||||
uint64_t buttons;
|
||||
retro_bits_t buttons;
|
||||
} input_overlay_state_t;
|
||||
|
||||
struct input_overlay
|
||||
|
@ -302,17 +302,15 @@ static void input_overlay_poll(
|
|||
{
|
||||
case OVERLAY_TYPE_BUTTONS:
|
||||
{
|
||||
uint64_t mask = desc->key_mask;
|
||||
bits_or_bits(out->buttons.data, desc->button_mask.data, ARRAY_SIZE(desc->button_mask.data));
|
||||
|
||||
out->buttons |= mask;
|
||||
|
||||
if (mask & (UINT64_C(1) << RARCH_OVERLAY_NEXT))
|
||||
if (BIT256_GET(desc->button_mask, RARCH_OVERLAY_NEXT))
|
||||
ol->next_index = desc->next_index;
|
||||
}
|
||||
break;
|
||||
case OVERLAY_TYPE_KEYBOARD:
|
||||
if (desc->key_mask < RETROK_LAST)
|
||||
OVERLAY_SET_KEY(out, desc->key_mask);
|
||||
if (desc->retro_key_idx < RETROK_LAST)
|
||||
OVERLAY_SET_KEY(out, desc->retro_key_idx);
|
||||
break;
|
||||
default:
|
||||
{
|
||||
|
@ -338,7 +336,7 @@ static void input_overlay_poll(
|
|||
}
|
||||
}
|
||||
|
||||
if (!out->buttons)
|
||||
if (!bits_any_set(out->buttons.data, ARRAY_SIZE(out->buttons.data)))
|
||||
ol->blocked = false;
|
||||
else if (ol->blocked)
|
||||
memset(out, 0, sizeof(*out));
|
||||
|
@ -556,12 +554,12 @@ bool input_overlay_is_alive(input_overlay_t *ol)
|
|||
return false;
|
||||
}
|
||||
|
||||
bool input_overlay_key_pressed(input_overlay_t *ol, int key)
|
||||
bool input_overlay_key_pressed(input_overlay_t *ol, unsigned key)
|
||||
{
|
||||
input_overlay_state_t *ol_state = ol ? &ol->overlay_state : NULL;
|
||||
if (!ol)
|
||||
return false;
|
||||
return (ol_state->buttons & (UINT64_C(1) << key));
|
||||
return (BIT256_GET(ol_state->buttons, key));
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -616,12 +614,12 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad
|
|||
else
|
||||
ol->blocked = false;
|
||||
|
||||
ol_state->buttons |= polled_data.buttons;
|
||||
bits_or_bits(ol_state->buttons.data, polled_data.buttons.data, ARRAY_SIZE(polled_data.buttons.data));
|
||||
|
||||
for (j = 0; j < ARRAY_SIZE(ol_state->keys); j++)
|
||||
ol_state->keys[j] |= polled_data.keys[j];
|
||||
|
||||
/* Fingers pressed later take prio and matched up
|
||||
/* Fingers pressed later take priority and matched up
|
||||
* with overlay poll priorities. */
|
||||
for (j = 0; j < 4; j++)
|
||||
if (polled_data.analog[j])
|
||||
|
@ -693,13 +691,13 @@ void input_poll_overlay(input_overlay_t *ol, float opacity, unsigned analog_dpad
|
|||
analog_y = (float)ol_state->analog[analog_base + 1] / 0x7fff;
|
||||
|
||||
if (analog_x <= -axis_threshold)
|
||||
BIT32_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_LEFT);
|
||||
BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_LEFT);
|
||||
if (analog_x >= axis_threshold)
|
||||
BIT32_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_RIGHT);
|
||||
if (analog_y <= -axis_threshold)
|
||||
BIT32_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_UP);
|
||||
BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_UP);
|
||||
if (analog_y >= axis_threshold)
|
||||
BIT32_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_DOWN);
|
||||
BIT256_SET(ol_state->buttons, RETRO_DEVICE_ID_JOYPAD_DOWN);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -767,14 +765,100 @@ void input_state_overlay(input_overlay_t *ol, int16_t *ret,
|
|||
* Adds inputs from current_input to the overlay, so it's displayed
|
||||
* returns true if an input that is pressed will change the overlay
|
||||
*/
|
||||
static bool input_overlay_add_inputs_inner(overlay_desc_t *desc,
|
||||
unsigned port, unsigned analog_dpad_mode)
|
||||
{
|
||||
switch(desc->type)
|
||||
{
|
||||
case OVERLAY_TYPE_BUTTONS:
|
||||
{
|
||||
unsigned i;
|
||||
unsigned id;
|
||||
uint32_t bank_mask;
|
||||
bool all_buttons_pressed = false;
|
||||
|
||||
/*Check each bank of the mask*/
|
||||
for (i=0; i<ARRAY_SIZE(desc->button_mask.data); ++i)
|
||||
{
|
||||
/*Get bank*/
|
||||
bank_mask = BITS_GET_ELEM(desc->button_mask,i);
|
||||
id = i*32;
|
||||
|
||||
/*Worth pursuing? Have we got any bits left in here?*/
|
||||
while (bank_mask)
|
||||
{
|
||||
/*If this bit is set then we need to query the pad
|
||||
*The button must be pressed.*/
|
||||
if (bank_mask & 1)
|
||||
{
|
||||
/* Light up the button if pressed */
|
||||
if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id))
|
||||
{
|
||||
all_buttons_pressed = true;
|
||||
desc->updated = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
/*we need ALL of the inputs to be active*/
|
||||
all_buttons_pressed = false;
|
||||
desc->updated = false;
|
||||
|
||||
/*abort*/
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bank_mask >>= 1;
|
||||
++id;
|
||||
}
|
||||
}
|
||||
|
||||
return all_buttons_pressed;
|
||||
}
|
||||
|
||||
case OVERLAY_TYPE_ANALOG_LEFT:
|
||||
case OVERLAY_TYPE_ANALOG_RIGHT:
|
||||
{
|
||||
float analog_x, analog_y;
|
||||
float dx, dy;
|
||||
unsigned int index = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ?
|
||||
RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT;
|
||||
|
||||
analog_x = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_X);
|
||||
analog_y = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_Y);
|
||||
dx = (analog_x/0x8000)*(desc->range_x/2);
|
||||
dy = (analog_y/0x8000)*(desc->range_y/2);
|
||||
|
||||
desc->delta_x = dx;
|
||||
desc->delta_y = dy;
|
||||
/*Maybe use some option here instead of 0, only display
|
||||
changes greater than some magnitude.
|
||||
*/
|
||||
if((dx*dx) > 0 || (dy*dy) > 0)
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
case OVERLAY_TYPE_KEYBOARD:
|
||||
if(input_state(port, RETRO_DEVICE_KEYBOARD, 0, desc->retro_key_idx))
|
||||
{
|
||||
desc->updated = true;
|
||||
return true;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool input_overlay_add_inputs(input_overlay_t *ol,
|
||||
unsigned port, unsigned analog_dpad_mode)
|
||||
{
|
||||
unsigned i;
|
||||
uint64_t mask;
|
||||
int id;
|
||||
bool button_pressed = false;
|
||||
bool current_button_pressed = false;
|
||||
input_overlay_state_t *ol_state = &ol->overlay_state;
|
||||
|
||||
if(!ol_state)
|
||||
|
@ -783,73 +867,7 @@ static bool input_overlay_add_inputs(input_overlay_t *ol,
|
|||
for(i = 0; i < ol->active->size; i++)
|
||||
{
|
||||
overlay_desc_t *desc = &(ol->active->descs[i]);
|
||||
switch(desc->type)
|
||||
{
|
||||
case OVERLAY_TYPE_BUTTONS:
|
||||
mask = desc->key_mask;
|
||||
id = RETRO_DEVICE_ID_JOYPAD_B;
|
||||
/* Need to check all bits in the mask,
|
||||
* multiple ones can be pressed */
|
||||
current_button_pressed = false;
|
||||
while(mask)
|
||||
{
|
||||
/* Get the next button ID */
|
||||
while(mask && (mask & 1) == 0)
|
||||
{
|
||||
id+=1;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
/* Light up the button if pressed */
|
||||
if(input_state(port, RETRO_DEVICE_JOYPAD, 0, id))
|
||||
{
|
||||
current_button_pressed = true;
|
||||
desc->updated = true;
|
||||
|
||||
id+=1;
|
||||
mask = mask >> 1;
|
||||
}
|
||||
else
|
||||
{
|
||||
/* One of the buttons not pressed */
|
||||
current_button_pressed = false;
|
||||
desc->updated = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
button_pressed = button_pressed || current_button_pressed;
|
||||
break;
|
||||
case OVERLAY_TYPE_ANALOG_LEFT:
|
||||
case OVERLAY_TYPE_ANALOG_RIGHT:
|
||||
{
|
||||
float analog_x, analog_y;
|
||||
float dx, dy;
|
||||
unsigned int index = (desc->type == OVERLAY_TYPE_ANALOG_RIGHT) ?
|
||||
RETRO_DEVICE_INDEX_ANALOG_RIGHT : RETRO_DEVICE_INDEX_ANALOG_LEFT;
|
||||
|
||||
analog_x = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_X);
|
||||
analog_y = input_state(port, RETRO_DEVICE_ANALOG, index, RETRO_DEVICE_ID_ANALOG_Y);
|
||||
dx = (analog_x/0x8000)*(desc->range_x/2);
|
||||
dy = (analog_y/0x8000)*(desc->range_y/2);
|
||||
|
||||
desc->delta_x = dx;
|
||||
desc->delta_y = dy;
|
||||
/*Maybe use some option here instead of 0, only display
|
||||
changes greater than some magnitude.
|
||||
*/
|
||||
if((dx*dx) > 0 || (dy*dy) > 0)
|
||||
button_pressed = true;
|
||||
}
|
||||
break;
|
||||
case OVERLAY_TYPE_KEYBOARD:
|
||||
if(input_state(port, RETRO_DEVICE_KEYBOARD, 0, (unsigned)desc->key_mask))
|
||||
{
|
||||
desc->updated = true;
|
||||
button_pressed = true;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
button_pressed |= input_overlay_add_inputs_inner(desc, port, analog_dpad_mode);
|
||||
}
|
||||
|
||||
return button_pressed;
|
||||
|
|
|
@ -172,7 +172,11 @@ struct overlay_desc
|
|||
float x;
|
||||
float y;
|
||||
|
||||
uint64_t key_mask;
|
||||
/* This is a retro_key value for keyboards */
|
||||
unsigned retro_key_idx;
|
||||
|
||||
/* This is a bit mask of all input binds to set with this overlay control */
|
||||
retro_bits_t button_mask;
|
||||
|
||||
char next_index_name[64];
|
||||
|
||||
|
@ -247,7 +251,7 @@ void input_state_overlay(input_overlay_t *ol,
|
|||
int16_t *ret, unsigned port, unsigned device, unsigned idx,
|
||||
unsigned id);
|
||||
|
||||
bool input_overlay_key_pressed(input_overlay_t *ol, int key);
|
||||
bool input_overlay_key_pressed(input_overlay_t *ol, unsigned key);
|
||||
|
||||
bool input_overlay_is_alive(input_overlay_t *ol);
|
||||
|
||||
|
|
|
@ -42,976 +42,7 @@ const char *msg_hash_to_str_pl(enum msg_hash_enums msg)
|
|||
{
|
||||
switch (msg)
|
||||
{
|
||||
case MENU_ENUM_LABEL_VALUE_ADD_CONTENT_LIST:
|
||||
return "Dodaj treść";
|
||||
case MENU_ENUM_LABEL_VALUE_ASK_ARCHIVE:
|
||||
return "Pytaj";
|
||||
case MENU_ENUM_LABEL_VALUE_ASSETS_DIRECTORY:
|
||||
return "Katalog assetów";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_BLOCK_FRAMES:
|
||||
return "Block Frames";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_DEVICE:
|
||||
return "Urządzenie audio";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_DRIVER:
|
||||
return "Kontroler dźwięku";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_DSP_PLUGIN:
|
||||
return "Wtyczki audio DSP";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_ENABLE:
|
||||
return "Włącz dźwięk";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_FILTER_DIR:
|
||||
return "Katalog filtrów audio";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_LATENCY:
|
||||
return "Opóźnienie dźwięku (ms)";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_MAX_TIMING_SKEW:
|
||||
return "Audio Maximum Timing Skew";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_MUTE:
|
||||
return "Wycisz dźwięk";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_OUTPUT_RATE:
|
||||
return "Częstotliwość próbkowania dźwięku (Hz)";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_RATE_CONTROL_DELTA:
|
||||
return "Audio Rate Control Delta";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_RESAMPLER_DRIVER:
|
||||
return "Kontroler resamplera dźwięku";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_SETTINGS:
|
||||
return "Ustawienia dźwięku";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_SYNC:
|
||||
return "Włącz synchronizację dźwięku";
|
||||
case MENU_ENUM_LABEL_VALUE_AUDIO_VOLUME:
|
||||
return "Poziom głośności (dB)";
|
||||
case MENU_ENUM_LABEL_VALUE_AUTOSAVE_INTERVAL:
|
||||
return "Częstotliwość automatycznego zapisu SaveRAM";
|
||||
case MENU_ENUM_LABEL_VALUE_AUTO_OVERRIDES_ENABLE:
|
||||
return "Load Override Files Automatically"; /* this one's rather complicated */
|
||||
case MENU_ENUM_LABEL_VALUE_AUTO_REMAPS_ENABLE:
|
||||
return "Automatycznie wczytuj pliki remapowania";
|
||||
case MENU_ENUM_LABEL_VALUE_BLOCK_SRAM_OVERWRITE:
|
||||
return "Nie nadpisuj SaveRAM przy wczytywaniu stanu";
|
||||
case MENU_ENUM_LABEL_VALUE_BUILDBOT_ASSETS_URL:
|
||||
return "URL assetów buildbota";
|
||||
case MENU_ENUM_LABEL_VALUE_CACHE_DIRECTORY: /* UPDATE/FIXME */
|
||||
return "Katalog do wypakowywania archiwów";
|
||||
case MENU_ENUM_LABEL_VALUE_CAMERA_ALLOW:
|
||||
return "Zezwalaj na dostęp do kamerki";
|
||||
case MENU_ENUM_LABEL_VALUE_CAMERA_DRIVER:
|
||||
return "Kontroler kamerki";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT:
|
||||
return "Cheat";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT_APPLY_CHANGES:
|
||||
return "Zastosuj zmiany cheatów";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT_DATABASE_PATH:
|
||||
return "Katalog z plikami cheatów";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT_FILE_LOAD:
|
||||
return "Wczytaj plik z cheatami";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT_FILE_SAVE_AS:
|
||||
return "Zapisz plik z cheatami jako";
|
||||
case MENU_ENUM_LABEL_VALUE_CHEAT_NUM_PASSES:
|
||||
return "Liczba przebiegów cheatów";
|
||||
case MENU_ENUM_LABEL_VALUE_CLOSE_CONTENT:
|
||||
return "Zamknij";
|
||||
case MENU_ENUM_LABEL_VALUE_CONFIGURATIONS:
|
||||
return "Wczytaj konfigurację";
|
||||
case MENU_ENUM_LABEL_VALUE_CONFIGURATION_SETTINGS:
|
||||
return "Ustawienia konfiguracji";
|
||||
case MENU_ENUM_LABEL_VALUE_CONFIG_SAVE_ON_EXIT:
|
||||
return "Zapisz konfigurację przy wyjściu";
|
||||
case MENU_ENUM_LABEL_VALUE_CONTENT_COLLECTION_LIST:
|
||||
return "Kolekcji";
|
||||
case MENU_ENUM_LABEL_VALUE_CONTENT_DATABASE_DIRECTORY:
|
||||
return "Katalog bazy danych treści";
|
||||
case MENU_ENUM_LABEL_VALUE_CONTENT_HISTORY_SIZE:
|
||||
return "Rozmiar historii treści";
|
||||
case MENU_ENUM_LABEL_VALUE_CONTENT_SETTINGS:
|
||||
return "Szybkie menu";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_ASSETS_DIRECTORY:
|
||||
return "Katalog pobranych";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_CHEAT_OPTIONS:
|
||||
return "Opcje cheatów rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_COUNTERS:
|
||||
return "Liczniki rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_ENABLE:
|
||||
return "Wyświetlaj nazwę rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFORMATION:
|
||||
return "Informacje o rdzeniu";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_AUTHORS:
|
||||
return "Autorzy";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_CATEGORIES:
|
||||
return "Kategorie";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_LABEL:
|
||||
return "Oznaczenie rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_CORE_NAME:
|
||||
return "Nazwa rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_FIRMWARE:
|
||||
return "Firmware(s)";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_LICENSES:
|
||||
return "Licencja(-e)";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_PERMISSIONS:
|
||||
return "Zezwolenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_SUPPORTED_EXTENSIONS:
|
||||
return "Wspierane rozszerzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_MANUFACTURER:
|
||||
return "Producent systemu";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INFO_SYSTEM_NAME:
|
||||
return "Nazwa systemu";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_INPUT_REMAPPING_OPTIONS:
|
||||
return "Opcje remapowania kontrolera rdzenia"; /* this is quite bad */
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_LIST:
|
||||
return "Wczytaj rdzeń";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_OPTIONS:
|
||||
return "Opcje";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_SETTINGS:
|
||||
return "Ustawienia rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_SET_SUPPORTS_NO_CONTENT_ENABLE: /* TODO/FIXME */
|
||||
return "Nie uruchamiaj rdzenia automatycznie";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_UPDATER_AUTO_EXTRACT_ARCHIVE:
|
||||
return "Automatycznie wypakowuj pobierane archiwa";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_UPDATER_BUILDBOT_URL:
|
||||
return "URL rdzeni buildbota";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_UPDATER_LIST:
|
||||
return "Aktualizator rdzeni";
|
||||
case MENU_ENUM_LABEL_VALUE_CORE_UPDATER_SETTINGS:
|
||||
return "Ustawienia aktualizatora";
|
||||
case MENU_ENUM_LABEL_VALUE_CURSOR_DIRECTORY:
|
||||
return "Katalog z kursorami";
|
||||
case MENU_ENUM_LABEL_VALUE_CURSOR_MANAGER:
|
||||
return "Menedżer kursorów";
|
||||
case MENU_ENUM_LABEL_VALUE_CUSTOM_RATIO:
|
||||
return "Włąsny współczynnik";
|
||||
case MENU_ENUM_LABEL_VALUE_DATABASE_MANAGER:
|
||||
return "Menedżer bazy danych";
|
||||
case MENU_ENUM_LABEL_VALUE_FAVORITES: /* TODO/FIXME - update */
|
||||
return "Wybierz plik i dopasuj rdzeń";
|
||||
case MENU_ENUM_LABEL_VALUE_DIRECTORY_CONTENT:
|
||||
return "<Katalog treści>";
|
||||
case MENU_ENUM_LABEL_VALUE_DIRECTORY_DEFAULT:
|
||||
return "<Domyślny>";
|
||||
case MENU_ENUM_LABEL_VALUE_DIRECTORY_NONE:
|
||||
return "<Żaden>";
|
||||
case MENU_ENUM_LABEL_VALUE_DIRECTORY_NOT_FOUND:
|
||||
return "Nie znaleziono katalogu.";
|
||||
case MENU_ENUM_LABEL_VALUE_DIRECTORY_SETTINGS:
|
||||
return "Ustawienia katalogów";
|
||||
case MENU_ENUM_LABEL_VALUE_DISABLED:
|
||||
return "Wyłączone";
|
||||
case MENU_ENUM_LABEL_VALUE_DISK_CYCLE_TRAY_STATUS:
|
||||
return "Disk Cycle Tray Status";
|
||||
case MENU_ENUM_LABEL_VALUE_DISK_IMAGE_APPEND:
|
||||
return "Dopisz do obrazu dysku";
|
||||
case MENU_ENUM_LABEL_VALUE_DISK_INDEX:
|
||||
return "Indeks dysku";
|
||||
case MENU_ENUM_LABEL_VALUE_DISK_OPTIONS:
|
||||
return "Opcje dysku rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_DONT_CARE:
|
||||
return "Bez znaczenia";
|
||||
case MENU_ENUM_LABEL_VALUE_DOWNLOADED_FILE_DETECT_CORE_LIST:
|
||||
return "Wybierz pobrany plik i dopasuj rdzeń"; /* TODO/FIXME - rewrite */
|
||||
case MENU_ENUM_LABEL_VALUE_DOWNLOAD_CORE_CONTENT:
|
||||
return "Pobierz treści";
|
||||
case MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_ENABLE:
|
||||
return "Pomiń wykryte DPI";
|
||||
case MENU_ENUM_LABEL_VALUE_DPI_OVERRIDE_VALUE:
|
||||
return "Własne DPI";
|
||||
case MENU_ENUM_LABEL_VALUE_DRIVER_SETTINGS:
|
||||
return "Ustawienia kontrolerów";
|
||||
case MENU_ENUM_LABEL_VALUE_DUMMY_ON_CORE_SHUTDOWN:
|
||||
return "Atrapa rdzenia przy zatrzymaniu rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPER:
|
||||
return "Dynamiczna tapeta";
|
||||
case MENU_ENUM_LABEL_VALUE_DYNAMIC_WALLPAPERS_DIRECTORY:
|
||||
return "Katalog dynamicznych tapet";
|
||||
case MENU_ENUM_LABEL_VALUE_ENTRY_HOVER_COLOR:
|
||||
return "Kolor zaznaczonego elementu menu";
|
||||
case MENU_ENUM_LABEL_VALUE_ENTRY_NORMAL_COLOR:
|
||||
return "Zwykły kolor elementu menu";
|
||||
case MENU_ENUM_LABEL_VALUE_FALSE:
|
||||
return "Fałsz";
|
||||
case MENU_ENUM_LABEL_VALUE_FASTFORWARD_RATIO:
|
||||
return "Maksymalna szybkość działania";
|
||||
case MENU_ENUM_LABEL_VALUE_FPS_SHOW:
|
||||
return "Wyświetlaj FPS";
|
||||
case MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_ENABLE:
|
||||
return "Limituj maksymalną szybkość działania";
|
||||
case MENU_ENUM_LABEL_VALUE_FRAME_THROTTLE_SETTINGS:
|
||||
return "Frame Throttle Settings";
|
||||
case MENU_ENUM_LABEL_VALUE_FRONTEND_COUNTERS:
|
||||
return "Liczniki frontendu";
|
||||
case MENU_ENUM_LABEL_VALUE_HELP:
|
||||
return "Pooc";
|
||||
case MENU_ENUM_LABEL_VALUE_HISTORY_LIST_ENABLE:
|
||||
return "Włącz historię treści";
|
||||
case MENU_ENUM_LABEL_VALUE_HORIZONTAL_MENU: /* Don't change. Breaks everything. (Would be: "Menu poziome") */
|
||||
return "Horizontal Menu";
|
||||
case MENU_ENUM_LABEL_VALUE_INFORMATION_LIST:
|
||||
return "Informacje";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_AUTODETECT_ENABLE:
|
||||
return "Włącz autokonfigurację";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_AXIS_THRESHOLD:
|
||||
return "Próg osi";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_HIDE_UNBOUND:
|
||||
return "Ukryj nieprzypisane przyciski";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_DESCRIPTOR_LABEL_SHOW:
|
||||
return "Wyświetl opisy przycisków dla tego rdzenia"; /* UPDATE/FIXME */
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_DRIVER:
|
||||
return "Kontroler wejścia";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_DUTY_CYCLE:
|
||||
return "Cykl zmian";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_HOTKEY_BINDS:
|
||||
return "Input Hotkey Binds";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_MAX_USERS:
|
||||
return "Maksymalna liczba użytkowników";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_OSK_OVERLAY_ENABLE:
|
||||
return "Wyświetlaj klawiaturę ekranową";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_OVERLAY_ENABLE:
|
||||
return "Wyświetlaj nakładkę";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_REMAPPING_DIRECTORY:
|
||||
return "Katalog plików remapowania";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_REMAP_BINDS_ENABLE:
|
||||
return "Włącz remapowanie bindów";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_SETTINGS:
|
||||
return "Ustawienia wprowadzania";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_TURBO_PERIOD:
|
||||
return "Okres turbo";
|
||||
case MENU_ENUM_LABEL_VALUE_INPUT_USER_BINDS:
|
||||
return "Wprowadź bindy dla użytkownika %u";
|
||||
case MENU_ENUM_LABEL_VALUE_JOYPAD_AUTOCONFIG_DIR:
|
||||
return "Katalog autokonfiguracji kontrolerów gier";
|
||||
case MENU_ENUM_LABEL_VALUE_JOYPAD_DRIVER:
|
||||
return "Kontroler gamepadów";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_CHINESE_SIMPLIFIED:
|
||||
return "chińśki (Uproszczony)";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_CHINESE_TRADITIONAL:
|
||||
return "chiński (Tradycyjny)";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_DUTCH:
|
||||
return "duński";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_ENGLISH:
|
||||
return "angielski";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_ESPERANTO:
|
||||
return "esperanto";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_FRENCH:
|
||||
return "francuski";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_GERMAN:
|
||||
return "niemiecki";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_ITALIAN:
|
||||
return "włoski";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_JAPANESE:
|
||||
return "japoński";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_KOREAN:
|
||||
return "koreański";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_BRAZIL:
|
||||
return "portugalski (brazil)";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_PORTUGUESE_PORTUGAL:
|
||||
return "portugalski (portugal)";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_RUSSIAN:
|
||||
return "rosyjski";
|
||||
case MENU_ENUM_LABEL_VALUE_LANG_SPANISH:
|
||||
return "hiszpański";
|
||||
case MENU_ENUM_LABEL_VALUE_LEFT_ANALOG:
|
||||
return "Lewy analog";
|
||||
case MENU_ENUM_LABEL_VALUE_LIBRETRO_DIR_PATH:
|
||||
return "Katalog rdzeni";
|
||||
case MENU_ENUM_LABEL_VALUE_LIBRETRO_INFO_PATH:
|
||||
return "Katalog informacji o rdzeniach";
|
||||
case MENU_ENUM_LABEL_VALUE_LIBRETRO_LOG_LEVEL:
|
||||
return "Poziom logowania rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_LINEAR:
|
||||
return "Liniowe";
|
||||
case MENU_ENUM_LABEL_VALUE_LOAD_ARCHIVE:
|
||||
return "Wczytaj archiwum";
|
||||
case MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_HISTORY:
|
||||
return "Wczytaj z ostatnio używanych";
|
||||
case MENU_ENUM_LABEL_VALUE_LOAD_CONTENT_LIST:
|
||||
return "Wczytaj treść";
|
||||
case MENU_ENUM_LABEL_VALUE_LOAD_STATE:
|
||||
return "Wczytaj stan";
|
||||
case MENU_ENUM_LABEL_VALUE_LOCATION_ALLOW:
|
||||
return "Zezwalaj na dostęp do lokalizacji";
|
||||
case MENU_ENUM_LABEL_VALUE_LOCATION_DRIVER:
|
||||
return "Kontroler lokalizacji";
|
||||
case MENU_ENUM_LABEL_VALUE_LOGGING_SETTINGS:
|
||||
return "Ustawienia logowania";
|
||||
case MENU_ENUM_LABEL_VALUE_LOG_VERBOSITY:
|
||||
return "Szczegółowość logowania";
|
||||
case MENU_ENUM_LABEL_VALUE_MAIN_MENU:
|
||||
return "Menu główne";
|
||||
case MENU_ENUM_LABEL_VALUE_MANAGEMENT:
|
||||
return "Ustawienia bazy danych";
|
||||
case MENU_ENUM_LABEL_VALUE_MENU_DRIVER:
|
||||
return "Kontroler menu";
|
||||
case MENU_ENUM_LABEL_VALUE_MENU_FILE_BROWSER_SETTINGS:
|
||||
return "Menu File Browser Settings";
|
||||
case MENU_ENUM_LABEL_VALUE_MENU_SETTINGS:
|
||||
return "Ustawienia menu";
|
||||
case MENU_ENUM_LABEL_VALUE_MENU_WALLPAPER:
|
||||
return "Tapeta menu";
|
||||
case MENU_ENUM_LABEL_VALUE_MISSING:
|
||||
return "Brak";
|
||||
case MENU_ENUM_LABEL_VALUE_MOUSE_ENABLE:
|
||||
return "Obsługa myszy";
|
||||
case MENU_ENUM_LABEL_VALUE_MULTIMEDIA_SETTINGS:
|
||||
return "Ustawienia multimediów";
|
||||
case MENU_ENUM_LABEL_VALUE_NAVIGATION_BROWSER_FILTER_SUPPORTED_EXTENSIONS_ENABLE:
|
||||
return "Filtruj według wspieranych rozszerzeń"; /* TODO/FIXME - rewrite */
|
||||
case MENU_ENUM_LABEL_VALUE_NAVIGATION_WRAPAROUND:
|
||||
return "Zawijanie nawigacji";
|
||||
case MENU_ENUM_LABEL_VALUE_NEAREST:
|
||||
return "Najbliższe";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_CLIENT_SWAP_INPUT: /* TODO: Original string changed */
|
||||
return "Zamień kontrolery w grze sieciowej";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_DELAY_FRAMES:
|
||||
return "Opóxnione klatki w grze sieciowej";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_ENABLE:
|
||||
return "Włącz grę sieciową";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_IP_ADDRESS: /* TODO: Original string changed */
|
||||
return "Adres IP";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_MODE:
|
||||
return "Tryb klienta gry sieciowej";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_NICKNAME:
|
||||
return "Nazwa użytkownika";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_SPECTATOR_MODE_ENABLE:
|
||||
return "Tryb obserwatora gry sieciowej";
|
||||
case MENU_ENUM_LABEL_VALUE_NETPLAY_TCP_UDP_PORT:
|
||||
return "Port TCP/UDP gry sieciowej";
|
||||
case MENU_ENUM_LABEL_VALUE_NETWORK_CMD_ENABLE:
|
||||
return "Komendy sieciowe";
|
||||
case MENU_ENUM_LABEL_VALUE_NETWORK_CMD_PORT:
|
||||
return "Port dla komend sieciowych";
|
||||
case MENU_ENUM_LABEL_VALUE_NETWORK_SETTINGS:
|
||||
return "Ustawienia sieci";
|
||||
case MENU_ENUM_LABEL_VALUE_NO:
|
||||
return "Nie";
|
||||
case MENU_ENUM_LABEL_VALUE_NONE:
|
||||
return "Żaden";
|
||||
case MENU_ENUM_LABEL_VALUE_NOT_AVAILABLE:
|
||||
return "B/D";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_CORE:
|
||||
return "Brak rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_CORES_AVAILABLE:
|
||||
return "Brak dostępnych rdzeni.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_CORE_INFORMATION_AVAILABLE:
|
||||
return "Brak informacji o rdzeniu.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_CORE_OPTIONS_AVAILABLE:
|
||||
return "Brak dostępnych opcji rdzenia.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_INFORMATION_AVAILABLE:
|
||||
return "Brak dostępnych informacji.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_ITEMS:
|
||||
return "Brak elementów.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_PERFORMANCE_COUNTERS:
|
||||
return "Brak liczników wydajności.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_PLAYLIST_ENTRIES_AVAILABLE:
|
||||
return "Brak wpisów w playliście.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_SETTINGS_FOUND:
|
||||
return "Nie znaleziono ustawień.";
|
||||
case MENU_ENUM_LABEL_VALUE_NO_SHADER_PARAMETERS:
|
||||
return "Brak parametrów shadera.";
|
||||
case MENU_ENUM_LABEL_VALUE_OFF: /* Don't change. Needed for XMB atm. (Would be: "WYŁĄCZONE") */
|
||||
return "OFF";
|
||||
case MENU_ENUM_LABEL_VALUE_ON: /* Don't change. Needed for XMB atm. (Would be: "WŁĄCZONE") */
|
||||
return "ON";
|
||||
case MENU_ENUM_LABEL_VALUE_ONLINE_UPDATER:
|
||||
return "Aktualizator sieciowy";
|
||||
case MENU_ENUM_LABEL_VALUE_ONSCREEN_DISPLAY_SETTINGS:
|
||||
return "Ustawienia OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_OPEN_ARCHIVE:
|
||||
return "Otwórz archiwum";
|
||||
case MENU_ENUM_LABEL_VALUE_OPTIONAL:
|
||||
return "Opcjonalny";
|
||||
case MENU_ENUM_LABEL_VALUE_OSK_OVERLAY_DIRECTORY:
|
||||
return "Katalog klawiatur ekranowych";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_AUTOLOAD_PREFERRED:
|
||||
return "Automatycznie wczytaj preferowaną nakładkę";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_DIRECTORY:
|
||||
return "Katalog nakładek";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_OPACITY:
|
||||
return "Nieprzeźroczystość nakładki";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_PRESET:
|
||||
return "Preset nakładki";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_SCALE:
|
||||
return "Skala nakładki";
|
||||
case MENU_ENUM_LABEL_VALUE_OVERLAY_SETTINGS:
|
||||
return "Ustawienia przycisków ekranowych";
|
||||
case MENU_ENUM_LABEL_VALUE_PAL60_ENABLE:
|
||||
return "Użyj trybu PAL60";
|
||||
case MENU_ENUM_LABEL_VALUE_PAUSE_LIBRETRO:
|
||||
return "Pauzuj przy wejściu do menu";
|
||||
case MENU_ENUM_LABEL_VALUE_PAUSE_NONACTIVE:
|
||||
return "Wstrzymaj gdy w tle";
|
||||
case MENU_ENUM_LABEL_VALUE_PERFCNT_ENABLE:
|
||||
return "Liczniki wydajności";
|
||||
case MENU_ENUM_LABEL_VALUE_PLAYLIST_DIRECTORY:
|
||||
return "Katalog historii";
|
||||
case MENU_ENUM_LABEL_VALUE_PLAYLIST_SETTINGS:
|
||||
return "Ustawienia playlisty";
|
||||
case MENU_ENUM_LABEL_VALUE_POINTER_ENABLE:
|
||||
return "Obsługa dotyku";
|
||||
case MENU_ENUM_LABEL_VALUE_PORT:
|
||||
return "Port";
|
||||
case MENU_ENUM_LABEL_VALUE_PRESENT:
|
||||
return "Obecny";
|
||||
case MENU_ENUM_LABEL_VALUE_PRIVACY_SETTINGS:
|
||||
return "Ustawienia prywatności";
|
||||
case MENU_ENUM_LABEL_VALUE_QUIT_RETROARCH:
|
||||
return "Opuść RetroArch";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_CRC32:
|
||||
return "CRC32";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DESCRIPTION:
|
||||
return "Opis";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_DEVELOPER:
|
||||
return "Deweloper";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_FRANCHISE:
|
||||
return "Franczyza";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_MD5:
|
||||
return "MD5";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_NAME:
|
||||
return "Nazwa";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_ORIGIN:
|
||||
return "Pochodzenie";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_PUBLISHER:
|
||||
return "Wydawca";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_MONTH:
|
||||
return "Miesiąc wydania";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_RELEASE_YEAR:
|
||||
return "Rok wydania";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_SHA1:
|
||||
return "SHA1";
|
||||
case MENU_ENUM_LABEL_VALUE_RDB_ENTRY_START_CONTENT:
|
||||
return "Uruchom treść";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORDING_CONFIG_DIRECTORY:
|
||||
return "Katalog konfiguracji nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORDING_OUTPUT_DIRECTORY:
|
||||
return "Katalog wyjściowy nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORDING_SETTINGS:
|
||||
return "Ustawienia nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORD_CONFIG:
|
||||
return "Konfiguracja nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORD_DRIVER:
|
||||
return "Kontroler nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORD_ENABLE:
|
||||
return "Włącz nagrywanie";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORD_PATH: /* FIXME/UPDATE */
|
||||
return "Ścieżka nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_RECORD_USE_OUTPUT_DIRECTORY:
|
||||
return "Używaj katalogu wyjściowego nagrywania";
|
||||
case MENU_ENUM_LABEL_VALUE_REMAP_FILE_LOAD:
|
||||
return "Wczytaj plik remapowania";
|
||||
case MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_CORE:
|
||||
return "Zapisz plik remapowania dla rdzenia";
|
||||
case MENU_ENUM_LABEL_VALUE_REMAP_FILE_SAVE_GAME:
|
||||
return "Zapisz plik remapowania dla gry";
|
||||
case MENU_ENUM_LABEL_VALUE_REQUIRED:
|
||||
return "Wymagany";
|
||||
case MENU_ENUM_LABEL_VALUE_RESTART_CONTENT:
|
||||
return "Restartuj";
|
||||
case MENU_ENUM_LABEL_VALUE_RESTART_RETROARCH:
|
||||
return "Uruchom ponownie RetroArch";
|
||||
case MENU_ENUM_LABEL_VALUE_RESUME:
|
||||
return "Wznów";
|
||||
case MENU_ENUM_LABEL_VALUE_RESUME_CONTENT:
|
||||
return "Wznów";
|
||||
case MENU_ENUM_LABEL_VALUE_RETROKEYBOARD:
|
||||
return "RetroKeyboard";
|
||||
case MENU_ENUM_LABEL_VALUE_RETROPAD:
|
||||
return "RetroPad";
|
||||
case MENU_ENUM_LABEL_VALUE_REWIND_ENABLE:
|
||||
return "Włącz przewijanie";
|
||||
case MENU_ENUM_LABEL_VALUE_REWIND_GRANULARITY:
|
||||
return "Płynność przewijania";
|
||||
case MENU_ENUM_LABEL_VALUE_REWIND_SETTINGS:
|
||||
return "Ustawienia przewijania";
|
||||
case MENU_ENUM_LABEL_VALUE_RGUI_BROWSER_DIRECTORY:
|
||||
return "Katalog przeglądarki";
|
||||
case MENU_ENUM_LABEL_VALUE_RGUI_CONFIG_DIRECTORY:
|
||||
return "Katalog zapisanych konfiguracji";
|
||||
case MENU_ENUM_LABEL_VALUE_RGUI_SHOW_START_SCREEN:
|
||||
return "Pokazuj ekran startowy";
|
||||
case MENU_ENUM_LABEL_VALUE_RIGHT_ANALOG:
|
||||
return "Prawy analog";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVEFILE_DIRECTORY:
|
||||
return "Katalog zapisów treści";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_INDEX:
|
||||
return "Indeks automatycznie zapisywanego stanu";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_LOAD:
|
||||
return "Automatyczne wczytywanie stanu";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVESTATE_AUTO_SAVE:
|
||||
return "Automatyczny zapis stanu";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVESTATE_DIRECTORY:
|
||||
return "Katalog zapisanych stanów";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVE_NEW_CONFIG:
|
||||
return "Zapisz nową konfigurację";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVE_STATE:
|
||||
return "Zapisz stan";
|
||||
case MENU_ENUM_LABEL_VALUE_SAVING_SETTINGS:
|
||||
return "Ustawienia zapisywania";
|
||||
case MENU_ENUM_LABEL_VALUE_SCAN_DIRECTORY:
|
||||
return "Przeszukaj katalog";
|
||||
case MENU_ENUM_LABEL_VALUE_SCAN_FILE:
|
||||
return "Skanuj plik";
|
||||
case MENU_ENUM_LABEL_VALUE_SCAN_THIS_DIRECTORY:
|
||||
return "<Przeszukaj ten katalog>";
|
||||
case MENU_ENUM_LABEL_VALUE_SCREENSHOT_DIRECTORY:
|
||||
return "Katalog zrzutów";
|
||||
case MENU_ENUM_LABEL_VALUE_SCREEN_RESOLUTION:
|
||||
return "Rozdzielczość ekranu";
|
||||
case MENU_ENUM_LABEL_VALUE_SEARCH:
|
||||
return "Szukaj:";
|
||||
case MENU_ENUM_LABEL_VALUE_SECONDS:
|
||||
return "sekund";
|
||||
case MENU_ENUM_LABEL_VALUE_SETTINGS:
|
||||
return "Ustawienia";
|
||||
case MENU_ENUM_LABEL_VALUE_SHADER:
|
||||
return "Shader";
|
||||
case MENU_ENUM_LABEL_VALUE_SHADER_APPLY_CHANGES:
|
||||
return "Zastosuj zmiany shaderów";
|
||||
case MENU_ENUM_LABEL_VALUE_SHADER_OPTIONS:
|
||||
return "Opcje shadera";
|
||||
case MENU_ENUM_LABEL_VALUE_SHOW_ADVANCED_SETTINGS:
|
||||
return "Pokaż zaawansowane ustawienia";
|
||||
case MENU_ENUM_LABEL_VALUE_SLOWMOTION_RATIO:
|
||||
return "Współczynnik spowolnienia";
|
||||
case MENU_ENUM_LABEL_VALUE_SORT_SAVEFILES_ENABLE:
|
||||
return "Sortuj zapisy w folderach";
|
||||
case MENU_ENUM_LABEL_VALUE_SORT_SAVESTATES_ENABLE:
|
||||
return "Sortuj zapisane stany w folderach";
|
||||
case MENU_ENUM_LABEL_VALUE_STATUS:
|
||||
return "Status";
|
||||
case MENU_ENUM_LABEL_VALUE_STDIN_CMD_ENABLE:
|
||||
return "Komendy stdin";
|
||||
case MENU_ENUM_LABEL_VALUE_SUSPEND_SCREENSAVER_ENABLE:
|
||||
return "Wstrzymaj wygaszacz";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_BGM_ENABLE:
|
||||
return "Włącz BGM systemu";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_DIRECTORY:
|
||||
return "Katalog systemu";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFORMATION:
|
||||
return "Informacje o systemie";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_7ZIP_SUPPORT:
|
||||
return "Wsparcie 7zip";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ALSA_SUPPORT:
|
||||
return "Wsparcie ALSA";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_BUILD_DATE:
|
||||
return "Data kompilacji";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CG_SUPPORT:
|
||||
return "Wsparcie Cg";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COCOA_SUPPORT:
|
||||
return "Wsparcie Cocoa";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_COMMAND_IFACE_SUPPORT:
|
||||
return "Wsparcie interfejsu wiersza poleceń";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CORETEXT_SUPPORT:
|
||||
return "Wsparcie CoreText";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_CPU_FEATURES:
|
||||
return "Właściwości CPU";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_DPI:
|
||||
return "Metryczne DPI wyświetlacza";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_HEIGHT:
|
||||
return "Metryczna wysokość wyświetlacza (mm)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DISPLAY_METRIC_MM_WIDTH:
|
||||
return "Metryczna szerokość wyświetlacza (mm)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DSOUND_SUPPORT:
|
||||
return "Wsparcie DirectSound";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WASAPI_SUPPORT:
|
||||
return "Wsparcie WASAPI";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_DYLIB_SUPPORT:
|
||||
return "Wsparcie bibliotek dynamicznych";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_EGL_SUPPORT:
|
||||
return "Wsparcie EGL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FBO_SUPPORT:
|
||||
return "Wsparcie renderowania do tekstury w OpenGL/Direct3D (wielokrotne przebiegi shaderów)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FFMPEG_SUPPORT:
|
||||
return "Wsparcie FFmpeg";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FREETYPE_SUPPORT:
|
||||
return "Wsparcie FreeType";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_IDENTIFIER:
|
||||
return "Identyfikator frontendu";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_NAME:
|
||||
return "Nazwa frontendu";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_FRONTEND_OS:
|
||||
return "System operacyjny hosta:";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GIT_VERSION:
|
||||
return "Wersja git";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_GLSL_SUPPORT:
|
||||
return "Wsparcie GLSL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_HLSL_SUPPORT:
|
||||
return "Wsparcie HLSL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_JACK_SUPPORT:
|
||||
return "Wsparcie JACK";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_KMS_SUPPORT:
|
||||
return "Wsparcie KMS/EGL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBRETRODB_SUPPORT:
|
||||
return "Wsparcie LibretroDB";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBUSB_SUPPORT:
|
||||
return "Wsparcie libusb";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_LIBXML2_SUPPORT:
|
||||
return "Wsparcie parsowania XML libxml2";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETPLAY_SUPPORT:
|
||||
return "Wsparcie Netplay (peer-to-peer)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_NETWORK_COMMAND_IFACE_SUPPORT:
|
||||
return "Wsparcie interfejsu komend sieciowych";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENAL_SUPPORT:
|
||||
return "Wsparcie OpenAL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGLES_SUPPORT:
|
||||
return "Wsparcie OpenGL ES";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENGL_SUPPORT:
|
||||
return "Wsparcie OpenGL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENSL_SUPPORT:
|
||||
return "Wsparcie OpenSL";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OPENVG_SUPPORT:
|
||||
return "Wsparcie OpenVG";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OSS_SUPPORT:
|
||||
return "Wsparcie OSS";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_OVERLAY_SUPPORT:
|
||||
return "Wsparcie nakładek graficznych";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE:
|
||||
return "Źródło zasilania";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGED:
|
||||
return "Naładowano";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_CHARGING:
|
||||
return "Ładowanie";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_DISCHARGING:
|
||||
return "Na baterii";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_POWER_SOURCE_NO_SOURCE:
|
||||
return "Brak źródła";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PULSEAUDIO_SUPPORT:
|
||||
return "Wsparcie PulseAudio";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_PYTHON_SUPPORT:
|
||||
return "Wsparcie Pythona (skrypty w shaderach)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RETRORATING_LEVEL:
|
||||
return "Poziom RetroRating";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ROARAUDIO_SUPPORT:
|
||||
return "Wsparcie RoarAudio";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RPNG_SUPPORT:
|
||||
return "Wsparcie PNG (RPNG)";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_RSOUND_SUPPORT:
|
||||
return "Wsparcie RSound";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL2_SUPPORT:
|
||||
return "Wsparcie SDL2";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_IMAGE_SUPPORT:
|
||||
return "Wsparcie SDL image";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_SDL_SUPPORT:
|
||||
return "Wsparcie SDL1.2";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_THREADING_SUPPORT:
|
||||
return "Wsparcie wielu wątków";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_UDEV_SUPPORT:
|
||||
return "Wsparcie Udev";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_V4L2_SUPPORT:
|
||||
return "Wsparcie Video4Linux2";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_VIDEO_CONTEXT_DRIVER:
|
||||
return "Kontroler wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_WAYLAND_SUPPORT:
|
||||
return "Wsparcie Wayland";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_X11_SUPPORT:
|
||||
return "Wsparcie X11";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XAUDIO2_SUPPORT:
|
||||
return "Wsparcie XAudio2";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_XVIDEO_SUPPORT:
|
||||
return "Wsparcie XVideo";
|
||||
case MENU_ENUM_LABEL_VALUE_SYSTEM_INFO_ZLIB_SUPPORT:
|
||||
return "Wsparcie Zlib";
|
||||
case MENU_ENUM_LABEL_VALUE_TAKE_SCREENSHOT:
|
||||
return "Zapisz zrzut";
|
||||
case MENU_ENUM_LABEL_VALUE_THREADED_DATA_RUNLOOP_ENABLE: /* TODO/FIXME - update */
|
||||
return "Osobny wątek odbierania danych";
|
||||
case MENU_ENUM_LABEL_VALUE_TIMEDATE_ENABLE:
|
||||
return "Wyświetl czas/datę";
|
||||
case MENU_ENUM_LABEL_VALUE_TITLE_COLOR:
|
||||
return "Kolor tytułu menu";
|
||||
case MENU_ENUM_LABEL_VALUE_TRUE:
|
||||
return "Prawda";
|
||||
case MENU_ENUM_LABEL_VALUE_UI_COMPANION_START_ON_BOOT:
|
||||
return "UI Companion Start On Boot";
|
||||
case MENU_ENUM_LABEL_VALUE_UI_MENUBAR_ENABLE:
|
||||
return "Pasek menu";
|
||||
case MENU_ENUM_LABEL_VALUE_UNABLE_TO_READ_COMPRESSED_FILE:
|
||||
return "Nie udało się odczytać skompresowanego pliku.";
|
||||
case MENU_ENUM_LABEL_VALUE_UNKNOWN:
|
||||
return "Nieznane";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_ASSETS:
|
||||
return "Aktualizuj assety";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_AUTOCONFIG_PROFILES:
|
||||
return "Aktualizuj profile autokonfiguracji";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_CG_SHADERS:
|
||||
return "Aktualizuj shadery Cg";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_CHEATS:
|
||||
return "Aktualizuj cheaty";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_CORE_INFO_FILES:
|
||||
return "Aktualizuj pliki informacji o rdzeniach";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_DATABASES:
|
||||
return "Aktualizuj bazy danych";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_GLSL_SHADERS:
|
||||
return "Aktualizuj shadery GLSL";
|
||||
case MENU_ENUM_LABEL_VALUE_UPDATE_OVERLAYS:
|
||||
return "Aktualizuj nakładki graficzne";
|
||||
case MENU_ENUM_LABEL_VALUE_USER:
|
||||
return "Użytkownik";
|
||||
case MENU_ENUM_LABEL_VALUE_USER_INTERFACE_SETTINGS:
|
||||
return "Ustawienia interfejsu użytkownika";
|
||||
case MENU_ENUM_LABEL_VALUE_USER_LANGUAGE:
|
||||
return "Język";
|
||||
case MENU_ENUM_LABEL_VALUE_USER_SETTINGS:
|
||||
return "Ustawienia użytkownika";
|
||||
case MENU_ENUM_LABEL_VALUE_USE_BUILTIN_IMAGE_VIEWER:
|
||||
return "Użyj wbudowanej przeglądarki obrazów";
|
||||
case MENU_ENUM_LABEL_VALUE_USE_BUILTIN_PLAYER:
|
||||
return "Użyj wbudowanego odtwarzacza mediów";
|
||||
case MENU_ENUM_LABEL_VALUE_USE_THIS_DIRECTORY:
|
||||
return "<Użyj tego katalogu>";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_ALLOW_ROTATE:
|
||||
return "Zezwól na obrót";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_AUTO:
|
||||
return "Auto współczynnik proporcji";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_ASPECT_RATIO_INDEX:
|
||||
return "łczynnika proporcji";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_BLACK_FRAME_INSERTION:
|
||||
return "Wstawiaj czarne klatki";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_CROP_OVERSCAN:
|
||||
return "Wytnij overscan (restart)";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_DISABLE_COMPOSITION:
|
||||
return "Wyłącz efekty kompozycji pulpitu";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_DRIVER:
|
||||
return "Kontroler wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FILTER:
|
||||
return "Filtr obrazu";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_DIR:
|
||||
return "Katalog filtrów wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FILTER_FLICKER:
|
||||
return "Filtr migotania";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FONT_ENABLE:
|
||||
return "Wyświetlaj wiadomości OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FONT_PATH:
|
||||
return "Czcionka wiadomości OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FONT_SIZE:
|
||||
return "Rozmiar wiadomości OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_ASPECT:
|
||||
return "Wymuś współczynnik proporcji";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE:
|
||||
return "Wymuś wyłączenie sRGB FBO";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY:
|
||||
return "Opóźnienie klatek";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN:
|
||||
return "Pełny ekran";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA:
|
||||
return "Gamma wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD:
|
||||
return "Włącz nagrywanie z użyciem GPU";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_GPU_SCREENSHOT:
|
||||
return "Wykonuj zrzuty ekranu z wykorzystaniem GPU";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC:
|
||||
return "Ścisła synchronizacja GPU";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_HARD_SYNC_FRAMES:
|
||||
return "Hard GPU Sync Frames";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_X:
|
||||
return "Współrzędna X dla wiadomości OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_MESSAGE_POS_Y:
|
||||
return "Współrzędna Y dla wiadomości OSD";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_MONITOR_INDEX:
|
||||
return "Indeks monitora";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_POST_FILTER_RECORD:
|
||||
return "Nagrywaj wraz z zaaplikowanymi filtrami";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE:
|
||||
return "Częstotliwość odświeżania";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_REFRESH_RATE_AUTO:
|
||||
return "Szacowana częstotliwość odświeżania monitora";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_ROTATION:
|
||||
return "Obrót";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SCALE:
|
||||
return "Skala w oknie";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SCALE_INTEGER:
|
||||
return "Skaluj w liczbach całkowitych";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SETTINGS:
|
||||
return "Ustawienia wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_DIR:
|
||||
return "Katalog shaderów";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_NUM_PASSES:
|
||||
return "Liczba przebiegów shadera";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PARAMETERS:
|
||||
return "Podgląd parametrów shadera";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET:
|
||||
return "Wczytaj preset shaderów";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_PARAMETERS:
|
||||
return "Parametry shadera menu";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHADER_PRESET_SAVE_AS:
|
||||
return "Zapisz preset shadera jako";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SHARED_CONTEXT:
|
||||
return "Enable Hardware Shared Context";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SMOOTH:
|
||||
return "Sprzętowe filtrowanie dwuliniowe";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SOFT_FILTER:
|
||||
return "Włącz filtr programowy";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_SWAP_INTERVAL:
|
||||
return "VSync Swap Interval";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_THREADED:
|
||||
return "Osobny wątek wideo";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_VFILTER:
|
||||
return "Redukcja migotania";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_VI_WIDTH:
|
||||
return "Set VI Screen Width";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_VSYNC:
|
||||
return "Synchronizacja pionowa";
|
||||
case MENU_ENUM_LABEL_VALUE_VIDEO_WINDOWED_FULLSCREEN:
|
||||
return "Tryb pełnego ekranu w oknie";
|
||||
case MENU_ENUM_LABEL_VALUE_YES:
|
||||
return "Tak";
|
||||
case MSG_APPENDED_DISK:
|
||||
return "Dopisano do dysku";
|
||||
case MSG_APPLYING_CHEAT:
|
||||
return "Applying cheat changes.";
|
||||
case MSG_APPLYING_SHADER:
|
||||
return "Aplikowanie shadera";
|
||||
case MSG_AUDIO_MUTED:
|
||||
return "Wyciszono dźwięk.";
|
||||
case MSG_AUDIO_UNMUTED:
|
||||
return "Przywrócono dźwięk.";
|
||||
case MSG_AUTOSAVE_FAILED:
|
||||
return "Nie udało się zainicjalizować automatycznego zapisu.";
|
||||
case MSG_BLOCKING_SRAM_OVERWRITE:
|
||||
return "Blokowanie nadpisania SRAM";
|
||||
case MSG_BYTES:
|
||||
return "bajtów";
|
||||
case MSG_CONFIG_DIRECTORY_NOT_SET:
|
||||
return "Nie ustawiono katalogu konfiguracji. Nie można zapisać nowej konfiguracji.";
|
||||
case MSG_CORE_DOES_NOT_SUPPORT_SAVESTATES:
|
||||
return "Rdzeń nie wspiera zapisów stanu.";
|
||||
case MSG_COULD_NOT_READ_CONTENT_FILE:
|
||||
return "Nie udało się odczytać pliku treści";
|
||||
case MSG_CUSTOM_TIMING_GIVEN:
|
||||
return "Wprowadzono niestandardowy timing";
|
||||
case MSG_DETECTED_VIEWPORT_OF:
|
||||
return "Wykrywanie viewportu";
|
||||
case MSG_FAILED_TO:
|
||||
return "Nie udało się";
|
||||
case MSG_FAILED_TO_APPLY_SHADER:
|
||||
return "Nie udało się zaaplikować shadera.";
|
||||
case MSG_FAILED_TO_LOAD_CONTENT:
|
||||
return "Nie udało się wczytać treści";
|
||||
case MSG_FAILED_TO_LOAD_MOVIE_FILE:
|
||||
return "Nie udało się wczytać pliku filmu";
|
||||
case MSG_FAILED_TO_LOAD_OVERLAY:
|
||||
return "Nie udało się wczytać nakładki.";
|
||||
case MSG_FAILED_TO_LOAD_STATE:
|
||||
return "Nie udało się wczytać stanu z";
|
||||
case MSG_FAILED_TO_REMOVE_DISK_FROM_TRAY:
|
||||
return "Nie udało się usunąć dysku z tacki.";
|
||||
case MSG_FAILED_TO_REMOVE_TEMPORARY_FILE:
|
||||
return "Nie udało się usunąć pliku tymczasowego";
|
||||
case MSG_FAILED_TO_SAVE_SRAM:
|
||||
return "Nie udało się zapisać SRAM";
|
||||
case MSG_FAILED_TO_SAVE_STATE_TO:
|
||||
return "Nie udało się zapisać stanu do";
|
||||
case MSG_FAILED_TO_START_MOVIE_RECORD:
|
||||
return "Nie udało się rozpocząć nagrywania filmu.";
|
||||
case MSG_FAILED_TO_START_RECORDING:
|
||||
return "Nie udało się rozpocząć nagrywania.";
|
||||
case MSG_FAILED_TO_TAKE_SCREENSHOT:
|
||||
return "Nie udało się zapisać zrzutu.";
|
||||
case MSG_FAILED_TO_UNMUTE_AUDIO:
|
||||
return "Nie udało się przywrócić dźwięku.";
|
||||
case MSG_FOUND_SHADER:
|
||||
return "Znaleziono shader";
|
||||
case MSG_GOT_INVALID_DISK_INDEX:
|
||||
return "Otrzymano nieprawidłowy indeks dysku.";
|
||||
case MSG_GRAB_MOUSE_STATE:
|
||||
return "Grab mouse state";
|
||||
case MSG_HW_RENDERED_MUST_USE_POSTSHADED_RECORDING:
|
||||
return "Ten rdzeń libretro używa renderowania sprzętowego. Konieczne jest użycie nagrywania wraz z zaaplikowanymi shaderami.";
|
||||
case MSG_LIBRETRO_ABI_BREAK:
|
||||
return "został skompilowany dla innej wersji libretro, różnej od obecnie używanej.";
|
||||
case MSG_LOADED_STATE_FROM_SLOT:
|
||||
return "Wczytano stan ze slotu #%d.";
|
||||
case MSG_LOADED_STATE_FROM_SLOT_AUTO:
|
||||
return "Wczytano stan ze slotu #-1 (auto).";
|
||||
case MSG_LOADING_CONTENT_FILE:
|
||||
return "Wczytywanie pliku treści";
|
||||
case MSG_LOADING_STATE:
|
||||
return "Wczytywanie stanu";
|
||||
case MSG_MOVIE_PLAYBACK_ENDED:
|
||||
return "Zakończono odtwarzanie filmu.";
|
||||
case MSG_MOVIE_RECORD_STOPPED:
|
||||
return "Zatrzymano nagrywanie filmu.";
|
||||
case MSG_NETPLAY_FAILED:
|
||||
return "Nie udało się zainicjalizować gry sieciowej.";
|
||||
case MSG_PAUSED:
|
||||
return "Wstrzymano.";
|
||||
case MSG_PROGRAM:
|
||||
return "RetroArch";
|
||||
case MSG_RECEIVED:
|
||||
return "otrzymano";
|
||||
case MSG_RECORDING_TERMINATED_DUE_TO_RESIZE:
|
||||
return "Przerwano nagrywanie z powodu zmiany rozmiaru.";
|
||||
case MSG_RECORDING_TO:
|
||||
return "Nagrywanie do";
|
||||
case MSG_REDIRECTING_CHEATFILE_TO:
|
||||
return "Przekierowywanie pliku cheatów do";
|
||||
case MSG_REDIRECTING_SAVEFILE_TO:
|
||||
return "Przekierowywanie pliku zapisu do";
|
||||
case MSG_REDIRECTING_SAVESTATE_TO:
|
||||
return "Przekierowywanie zapisu stanu do"; /* TODO */
|
||||
case MSG_REMOVED_DISK_FROM_TRAY:
|
||||
return "Usunięto dysk z tacki.";
|
||||
case MSG_REMOVING_TEMPORARY_CONTENT_FILE:
|
||||
return "Usuwanie tymczasowego pliku treści";
|
||||
case MSG_RESET:
|
||||
return "Reset";
|
||||
case MSG_RESTARTING_RECORDING_DUE_TO_DRIVER_REINIT:
|
||||
return "Ponowne rozpoczęcie nagrywania z powodu reinicjalizacji kontrolera.";
|
||||
case MSG_REWINDING:
|
||||
return "Przewijanie.";
|
||||
case MSG_REWIND_INIT:
|
||||
return "Inicjalizowanie bufora przewijania o rozmiarze";
|
||||
case MSG_REWIND_INIT_FAILED:
|
||||
return "Nie udało się zainicjalizować bufora przewijania. Przewijanie zostanie wyłączone.";
|
||||
case MSG_REWIND_INIT_FAILED_THREADED_AUDIO:
|
||||
return "Implementacja używa osobnego wątku do przetwarzania dźwięku. Przewijanie nie jest możliwe.";
|
||||
case MSG_REWIND_REACHED_END:
|
||||
return "W buforze przewijania nie ma więcej danych.";
|
||||
case MSG_SAVED_STATE_TO_SLOT:
|
||||
return "Zapisano stan w slocie #%d.";
|
||||
case MSG_SAVED_STATE_TO_SLOT_AUTO:
|
||||
return "Zapisano stan w slocie #-1 (auto).";
|
||||
case MSG_SAVED_SUCCESSFULLY_TO:
|
||||
return "Pomyślnie zapisano do";
|
||||
case MSG_SAVING_RAM_TYPE:
|
||||
return "Zapisywanie typu RAM";
|
||||
case MSG_SAVING_STATE:
|
||||
return "Zapisywanie stanu";
|
||||
case MSG_SCANNING:
|
||||
return "Skanowanie";
|
||||
case MSG_SCANNING_OF_DIRECTORY_FINISHED:
|
||||
return "Zakończono skanowanie katalogu";
|
||||
case MSG_SENDING_COMMAND:
|
||||
return "Wysyłanie komendy";
|
||||
case MSG_SHADER:
|
||||
return "Shader";
|
||||
case MSG_SKIPPING_SRAM_LOAD:
|
||||
return "Pomijanie wczytywania SRAM.";
|
||||
case MSG_SLOW_MOTION:
|
||||
return "Spowolnione tempo.";
|
||||
case MSG_FAST_FORWARD:
|
||||
return "Szybko do przodu.";
|
||||
case MSG_SLOW_MOTION_REWIND:
|
||||
return "Przewijanie w spowolnionym tempie.";
|
||||
case MSG_SRAM_WILL_NOT_BE_SAVED:
|
||||
return "SRAM nie zostanie zapisany.";
|
||||
case MSG_STARTING_MOVIE_PLAYBACK:
|
||||
return "Rozpoczynanie odtwarzania filmu.";
|
||||
case MSG_STARTING_MOVIE_RECORD_TO:
|
||||
return "Rozpoczynanie zapisu filmu do";
|
||||
case MSG_STATE_SIZE:
|
||||
return "Rozmiar stanu";
|
||||
case MSG_STATE_SLOT:
|
||||
return "Slot zapisu";
|
||||
case MSG_TAKING_SCREENSHOT:
|
||||
return "Zapisywanie zrzutu.";
|
||||
case MSG_TO:
|
||||
return "do";
|
||||
case MSG_UNKNOWN:
|
||||
return "Nieznane";
|
||||
case MSG_UNPAUSED:
|
||||
return "Wznowiono.";
|
||||
case MSG_UNRECOGNIZED_COMMAND:
|
||||
return "Nieznana komenda";
|
||||
case MSG_USING_LIBRETRO_DUMMY_CORE_RECORDING_SKIPPED:
|
||||
return "Atrapa rdzenia w użyciu. Pomijanie nagrywania.";
|
||||
case MSG_VIEWPORT_SIZE_CALCULATION_FAILED:
|
||||
return "Obliczanie rozmiaru viewportu nie powiodło się! Kontynuowanie z użyciem surowych danych. Prawdopodobnie nie będzie to działało poprawnie...";
|
||||
case MSG_VIRTUAL_DISK_TRAY:
|
||||
return "wirtualna tacka."; /* this is funny */
|
||||
#include "msg_hash_pl.h"
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -1670,7 +1670,7 @@ MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FORCE_SRGB_DISABLE,
|
|||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FRAME_DELAY,
|
||||
"Frame Delay")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_FULLSCREEN,
|
||||
"Use Fullscreen Mode")
|
||||
"Start in Fullscreen Mode")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GAMMA,
|
||||
"Video Gamma")
|
||||
MSG_HASH(MENU_ENUM_LABEL_VALUE_VIDEO_GPU_RECORD,
|
||||
|
@ -2618,7 +2618,7 @@ MSG_HASH(
|
|||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_VIDEO_FULLSCREEN,
|
||||
"Start in fullscreen. Can be changed at runtime."
|
||||
"Start in fullscreen. Can be changed at runtime. Can be overriden by a command line switch"
|
||||
)
|
||||
MSG_HASH(
|
||||
MENU_ENUM_SUBLABEL_VIDEO_WINDOWED_FULLSCREEN,
|
||||
|
|
|
@ -111,20 +111,23 @@ void audio_mix_free_chunk(audio_chunk_t *chunk)
|
|||
audio_chunk_t* audio_mix_load_wav_file(const char *path, int sample_rate)
|
||||
{
|
||||
int sample_size;
|
||||
ssize_t len = 0;
|
||||
void *buf = NULL;
|
||||
audio_chunk_t *chunk = (audio_chunk_t*)calloc(1, sizeof(*chunk));
|
||||
|
||||
if (!chunk)
|
||||
return NULL;
|
||||
|
||||
chunk->sample_rate = sample_rate;
|
||||
|
||||
if (!filestream_read_file(path, &chunk->buf, &chunk->len))
|
||||
if (!filestream_read_file(path, &buf, &len))
|
||||
{
|
||||
printf("Could not open WAV file for reading.\n");
|
||||
goto error;
|
||||
}
|
||||
|
||||
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
|
||||
chunk->sample_rate = sample_rate;
|
||||
chunk->buf = buf;
|
||||
chunk->len = len;
|
||||
chunk->rwav = (rwav_t*)malloc(sizeof(rwav_t));
|
||||
|
||||
if (rwav_load(chunk->rwav, chunk->buf, chunk->len) == RWAV_ITERATE_ERROR)
|
||||
{
|
||||
|
|
|
@ -44,7 +44,6 @@
|
|||
#include <file/file_path.h>
|
||||
#include <lists/string_list.h>
|
||||
#include <string/stdstring.h>
|
||||
#include <streams/file_stream.h>
|
||||
|
||||
#define MAX_INCLUDE_DEPTH 16
|
||||
|
||||
|
@ -78,6 +77,40 @@ struct config_file
|
|||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth);
|
||||
|
||||
static char *getaline(FILE *file)
|
||||
{
|
||||
char* newline = (char*)malloc(9);
|
||||
char* newline_tmp = NULL;
|
||||
size_t cur_size = 8;
|
||||
size_t idx = 0;
|
||||
int in = fgetc(file);
|
||||
|
||||
if (!newline)
|
||||
return NULL;
|
||||
|
||||
while (in != EOF && in != '\n')
|
||||
{
|
||||
if (idx == cur_size)
|
||||
{
|
||||
cur_size *= 2;
|
||||
newline_tmp = (char*)realloc(newline, cur_size + 1);
|
||||
|
||||
if (!newline_tmp)
|
||||
{
|
||||
free(newline);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
newline = newline_tmp;
|
||||
}
|
||||
|
||||
newline[idx++] = in;
|
||||
in = fgetc(file);
|
||||
}
|
||||
newline[idx] = '\0';
|
||||
return newline;
|
||||
}
|
||||
|
||||
static char *strip_comment(char *str)
|
||||
{
|
||||
/* Remove everything after comment.
|
||||
|
@ -190,7 +223,7 @@ static void add_child_list(config_file_t *parent, config_file_t *child)
|
|||
/* Rebase tail. */
|
||||
if (parent->entries)
|
||||
{
|
||||
struct config_entry_list *head =
|
||||
struct config_entry_list *head =
|
||||
(struct config_entry_list*)parent->entries;
|
||||
|
||||
while (head->next)
|
||||
|
@ -311,11 +344,10 @@ static bool parse_line(config_file_t *conf,
|
|||
|
||||
key[idx++] = *line++;
|
||||
}
|
||||
key[idx] = '\0';
|
||||
list->key = key;
|
||||
|
||||
list->value = extract_value(line, true);
|
||||
key[idx] = '\0';
|
||||
list->key = key;
|
||||
|
||||
list->value = extract_value(line, true);
|
||||
if (!list->value)
|
||||
{
|
||||
list->key = NULL;
|
||||
|
@ -332,7 +364,7 @@ error:
|
|||
static config_file_t *config_file_new_internal(
|
||||
const char *path, unsigned depth)
|
||||
{
|
||||
RFILE *file = NULL;
|
||||
FILE *file = NULL;
|
||||
struct config_file *conf = (struct config_file*)malloc(sizeof(*conf));
|
||||
if (!conf)
|
||||
return NULL;
|
||||
|
@ -354,9 +386,7 @@ static config_file_t *config_file_new_internal(
|
|||
goto error;
|
||||
|
||||
conf->include_depth = depth;
|
||||
file = filestream_open(path,
|
||||
RETRO_VFS_FILE_ACCESS_READ,
|
||||
RETRO_VFS_FILE_ACCESS_HINT_NONE);
|
||||
file = fopen_utf8(path, "r");
|
||||
|
||||
if (!file)
|
||||
{
|
||||
|
@ -364,7 +394,7 @@ static config_file_t *config_file_new_internal(
|
|||
goto error;
|
||||
}
|
||||
|
||||
while (!filestream_eof(file))
|
||||
while (!feof(file))
|
||||
{
|
||||
char *line = NULL;
|
||||
struct config_entry_list *list = (struct config_entry_list*)malloc(sizeof(*list));
|
||||
|
@ -372,7 +402,7 @@ static config_file_t *config_file_new_internal(
|
|||
if (!list)
|
||||
{
|
||||
config_file_free(conf);
|
||||
filestream_close(file);
|
||||
fclose(file);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
@ -381,7 +411,7 @@ static config_file_t *config_file_new_internal(
|
|||
list->value = NULL;
|
||||
list->next = NULL;
|
||||
|
||||
line = filestream_getline(file);
|
||||
line = getaline(file);
|
||||
|
||||
if (!line)
|
||||
{
|
||||
|
@ -405,7 +435,7 @@ static config_file_t *config_file_new_internal(
|
|||
free(list);
|
||||
}
|
||||
|
||||
filestream_close(file);
|
||||
fclose(file);
|
||||
|
||||
return conf;
|
||||
|
||||
|
@ -490,7 +520,7 @@ config_file_t *config_file_new_from_string(const char *from_string)
|
|||
conf->tail = NULL;
|
||||
conf->includes = NULL;
|
||||
conf->include_depth = 0;
|
||||
|
||||
|
||||
lines = string_split(from_string, "\n");
|
||||
if (!lines)
|
||||
return conf;
|
||||
|
@ -542,8 +572,11 @@ config_file_t *config_file_new(const char *path)
|
|||
static struct config_entry_list *config_get_entry(const config_file_t *conf,
|
||||
const char *key, struct config_entry_list **prev)
|
||||
{
|
||||
struct config_entry_list *entry = NULL;
|
||||
struct config_entry_list *previous = prev ? *prev : NULL;
|
||||
struct config_entry_list *entry;
|
||||
struct config_entry_list *previous = NULL;
|
||||
|
||||
if (prev)
|
||||
previous = *prev;
|
||||
|
||||
for (entry = conf->entries; entry; entry = entry->next)
|
||||
{
|
||||
|
@ -869,32 +902,9 @@ void config_set_bool(config_file_t *conf, const char *key, bool val)
|
|||
config_set_string(conf, key, val ? "true" : "false");
|
||||
}
|
||||
|
||||
bool config_file_write(config_file_t *conf, const char *path)
|
||||
{
|
||||
if (!string_is_empty(path))
|
||||
{
|
||||
void* buf = NULL;
|
||||
FILE *file = fopen_utf8(path, "wb");
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
/* TODO: this is only useful for a few platforms, find which and add ifdef */
|
||||
buf = calloc(1, 0x4000);
|
||||
setvbuf(file, (char*)buf, _IOFBF, 0x4000);
|
||||
|
||||
config_file_dump(conf, file);
|
||||
|
||||
if (file != stdout)
|
||||
fclose(file);
|
||||
free(buf);
|
||||
}
|
||||
else
|
||||
config_file_dump(conf, stdout);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void config_file_dump(config_file_t *conf, FILE *file)
|
||||
/* Dump the current config to an already opened file.
|
||||
* Does not close the file. */
|
||||
static void config_file_dump(config_file_t *conf, FILE *file)
|
||||
{
|
||||
struct config_entry_list *list = NULL;
|
||||
struct config_include_list *includes = conf->includes;
|
||||
|
@ -915,6 +925,33 @@ void config_file_dump(config_file_t *conf, FILE *file)
|
|||
}
|
||||
}
|
||||
|
||||
bool config_file_write(config_file_t *conf, const char *path)
|
||||
{
|
||||
void* buf = NULL;
|
||||
FILE *file = !string_is_empty(path) ? fopen_utf8(path, "wb") : stdout;
|
||||
|
||||
if (!file)
|
||||
return false;
|
||||
|
||||
/* TODO: this is only useful for a few platforms, find which and add ifdef */
|
||||
if (file != stdout)
|
||||
{
|
||||
buf = calloc(1, 0x4000);
|
||||
setvbuf(file, (char*)buf, _IOFBF, 0x4000);
|
||||
}
|
||||
|
||||
config_file_dump(conf, file);
|
||||
|
||||
if (file != stdout)
|
||||
{
|
||||
fclose(file);
|
||||
free(buf);
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
bool config_entry_exists(config_file_t *conf, const char *entry)
|
||||
{
|
||||
struct config_entry_list *list = conf->entries;
|
||||
|
|
|
@ -154,10 +154,6 @@ void config_set_bool(config_file_t *conf, const char *entry, bool val);
|
|||
/* Write the current config to a file. */
|
||||
bool config_file_write(config_file_t *conf, const char *path);
|
||||
|
||||
/* Dump the current config to an already opened file.
|
||||
* Does not close the file. */
|
||||
void config_file_dump(config_file_t *conf, FILE *file);
|
||||
|
||||
bool config_file_exists(const char *path);
|
||||
|
||||
RETRO_END_DECLS
|
||||
|
|
|
@ -156,8 +156,10 @@ static INLINE bool isagain(int bytes)
|
|||
if (WSAGetLastError() != WSAEWOULDBLOCK)
|
||||
return false;
|
||||
return true;
|
||||
#elif defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
return (sys_net_errno == SYS_NET_EWOULDBLOCK) || (sys_net_errno == SYS_NET_EAGAIN);//35
|
||||
#elif defined(VITA)
|
||||
return (bytes<0 && (bytes == SCE_NET_ERROR_EAGAIN || bytes == SCE_NET_ERROR_EWOULDBLOCK));
|
||||
return (bytes<0 && (bytes == SCE_NET_ERROR_EAGAIN || bytes == SCE_NET_ERROR_EWOULDBLOCK));
|
||||
#elif defined(WIIU)
|
||||
return (bytes == -1) && ((socketlasterr() == SO_SUCCESS) || (socketlasterr() == SO_EWOULDBLOCK));
|
||||
#else
|
||||
|
|
|
@ -36,12 +36,23 @@
|
|||
#include <Xtl.h>
|
||||
#endif
|
||||
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#include <sys/fs_external.h>
|
||||
#endif
|
||||
|
||||
#include <limits.h>
|
||||
|
||||
#ifdef _MSC_VER
|
||||
#include <compat/msvc.h>
|
||||
#endif
|
||||
|
||||
static INLINE void bits_or_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < count;i++)
|
||||
a[i] |= b[i];
|
||||
}
|
||||
|
||||
static INLINE void bits_clear_bits(uint32_t *a, uint32_t *b, uint32_t count)
|
||||
{
|
||||
uint32_t i;
|
||||
|
@ -61,7 +72,9 @@ static INLINE bool bits_any_set(uint32_t* ptr, uint32_t count)
|
|||
}
|
||||
|
||||
#ifndef PATH_MAX_LENGTH
|
||||
#if defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)|| defined(WIIU)
|
||||
#if defined(__CELLOS_LV2__)
|
||||
#define PATH_MAX_LENGTH CELL_FS_MAX_FS_PATH_LENGTH
|
||||
#elif defined(_XBOX1) || defined(_3DS) || defined(PSP) || defined(GEKKO)|| defined(WIIU)
|
||||
#define PATH_MAX_LENGTH 512
|
||||
#else
|
||||
#define PATH_MAX_LENGTH 4096
|
||||
|
|
|
@ -24,12 +24,11 @@
|
|||
#define __LIBRETRO_SDK_FILE_STREAM_TRANSFORMS_H
|
||||
|
||||
#include <retro_common_api.h>
|
||||
#include <streams/file_stream.h>
|
||||
#include <string.h>
|
||||
|
||||
RETRO_BEGIN_DECLS
|
||||
|
||||
typedef struct RFILE RFILE;
|
||||
|
||||
#define FILE RFILE
|
||||
|
||||
#undef fopen
|
||||
|
|
|
@ -193,12 +193,6 @@ int getaddrinfo_retro(const char *node, const char *service,
|
|||
in_addr->sin_family = AF_INET;
|
||||
in_addr->sin_port = inet_htons(strtoul(service, NULL, 0));
|
||||
|
||||
//sin_port seems to be the wrong endian for ps3
|
||||
#if defined(__CELLOS_LV2__) && !defined(__PSL1GHT__)
|
||||
in_addr->sin_port = (in_addr->sin_port>>8) | (in_addr->sin_port<<8);
|
||||
#endif
|
||||
|
||||
|
||||
if (!node && (hints->ai_flags & AI_PASSIVE))
|
||||
in_addr->sin_addr.s_addr = INADDR_ANY;
|
||||
else if (node && isdigit(*node))
|
||||
|
@ -212,7 +206,7 @@ int getaddrinfo_retro(const char *node, const char *service,
|
|||
|
||||
in_addr->sin_family = host->h_addrtype;
|
||||
|
||||
#ifdef AF_INET6
|
||||
#if defined(AF_INET6) && !defined(__CELLOS_LV2__)
|
||||
/* TODO/FIXME - In case we ever want to support IPv6 */
|
||||
in_addr->sin_addr.s_addr = inet_addr(host->h_addr_list[0]);
|
||||
#else
|
||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue