Add PSP/GameCube/Wii save-device availability checks

PSP checks memory-stick reachability via sceIoGetstat. GameCube gets two
devices (CARD_SLOTA/CARD_SLOTB), each mounted via CARD_Init/CARD_Mount and
checked for free space via CARD_GetDirectory/CARD_GetBlockCount. Wii picks
between three storage methods at compile time (DUSK_SAVE_WII_METHOD =
NAND/CARD/SD in wii.cmake, default NAND via ISFS) since real hardware
behavior for the default is unverified.

Also fixes two pre-existing bugs found while build/runtime-testing this
across PPSSPP and Dolphin: wrong libogc language macros in
systemGetLocaleDolphin, and a missing SYS_STDIO_Report(true) call that
silently swallowed all guest console output in Dolphin.

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
2026-08-14 16:20:28 -05:00
parent 45331c2a60
commit d7223d7387
16 changed files with 670 additions and 2 deletions
+1
View File
@@ -21,5 +21,6 @@ add_subdirectory(log)
if(DUSK_NETWORK)
add_subdirectory(network)
endif()
add_subdirectory(save)
add_subdirectory(system)
add_subdirectory(time)
+9
View File
@@ -0,0 +1,9 @@
# Copyright (c) 2026 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DUSK_LIBRARY_TARGET_NAME}
PUBLIC
savedevicepsp.c
)
+16
View File
@@ -0,0 +1,16 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "savedevicepsp.h"
#define SAVE_DEVICE_COUNT 1
#define saveDevicePlatformInit saveDevicePSPInit
#define saveDevicePlatformUpdate saveDevicePSPUpdate
#define saveDeviceCheckAvailabilityPlatform saveDevicePSPCheckAvailability
#define saveDevicePlatformDispose saveDevicePSPDispose
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "save/savedevice.h"
#include "save/savedevicepsp.h"
#include "assert/assert.h"
#include <pspiofilemgr.h>
errorret_t saveDevicePSPInit(savedevice_t *device) {
assertNotNull(device, "device cannot be null");
device->state = SAVE_DEVICE_STATE_UNKNOWN;
errorOk();
}
errorret_t saveDevicePSPUpdate(savedevice_t *device) {
assertNotNull(device, "device cannot be null");
assertIsMainThread("Invalid thread");
errorOk();
}
void saveDevicePSPCheckAvailability(savedevice_t *device) {
assertNotNull(device, "device cannot be null");
assertIsMainThread("Invalid thread");
assertTrue(
device->state == SAVE_DEVICE_STATE_CHECKING_AVAILABILITY,
"Device state incorrect?"
);
// Confirm the memory stick is actually reachable - the real save/load
// (via sceUtilitySavedata) only reports failure once a save/load is
// attempted, so this is checked separately up front.
SceIoStat stat;
if(sceIoGetstat(SAVE_DEVICE_PSP_ROOT, &stat) < 0) {
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
device->reasonKey = "save.psp.no_memory_stick";
return saveDeviceFireCallback(device);
}
device->state = SAVE_DEVICE_STATE_AVAILABLE;
device->reasonKey = NULL;
saveDeviceFireCallback(device);
}
errorret_t saveDevicePSPDispose(savedevice_t *device) {
errorOk();
}
+52
View File
@@ -0,0 +1,52 @@
/**
* Copyright (c) 2026 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "error/error.h"
// PSP only ever exposes one save device - the memory stick.
#ifndef SAVE_DEVICE_PSP_ROOT
#define SAVE_DEVICE_PSP_ROOT "ms0:/"
#endif
typedef struct {
void *nothing;
} savedeviceplatform_t;
typedef struct savedevice_s savedevice_t;
/**
* Initializes the save device platform.
*
* @param device The save device platform to initialize.
* @return Error state if any.
*/
errorret_t saveDevicePSPInit(savedevice_t *device);
/**
* Updates the save device platform.
*
* @param device The save device platform to update.
* @return Error state if any.
*/
errorret_t saveDevicePSPUpdate(savedevice_t *device);
/**
* Requests the device to check its availability, this will call the callback
* whence completed.
*
* @param device The save device platform to check availability.
*/
void saveDevicePSPCheckAvailability(savedevice_t *device);
/**
* Disposes of the save device platform.
*
* @param device The save device platform to dispose.
* @return Error state if any.
*/
errorret_t saveDevicePSPDispose(savedevice_t *device);