Fix GameCube memory card slot B detection and free-space check
CARD_Mount() alone reliably reports CARD_ERROR_NOCARD for a card physically present in slot B - unlike slot A, which the IPL polls automatically at boot, slot B needs an explicit CARD_Probe() first (the standard pattern in every official devkitPro CARD sample). Also fixes saveDeviceDolphinCardHasFreeSpace() treating CARD_GetDirectory()'s CARD_ERROR_NOFILE (a totally empty card, not an actual error) as a hard failure, which made any card with zero existing save files - slot B's in this case, since slot A already had leftover test data on it - get reported as full. Confirmed via Dolphin with slot A disabled/slot B set to a memory card: previously reported "no save device found", now correctly detects it. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
This commit is contained in:
@@ -52,6 +52,21 @@ void saveDeviceDolphinCardCheckAvailability(savedevice_t *device) {
|
||||
return saveDeviceFireCallback(device);
|
||||
}
|
||||
|
||||
// Slot A gets polled automatically by the IPL at boot, but slot B does
|
||||
// not - CARD_Mount() alone reliably reports CARD_ERROR_NOCARD for a
|
||||
// present slot B card unless CARD_Probe() is used to explicitly detect
|
||||
// it first (matches the probe-then-mount pattern in every official
|
||||
// devkitPro CARD sample, not something slot A happens to need too).
|
||||
do {
|
||||
result = CARD_Probe(platform->channel);
|
||||
} while(result == CARD_ERROR_BUSY);
|
||||
|
||||
if(result < 0) {
|
||||
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
|
||||
device->reasonKey = saveDeviceDolphinCardErrorReasonKey(result);
|
||||
return saveDeviceFireCallback(device);
|
||||
}
|
||||
|
||||
do {
|
||||
result = CARD_Mount(platform->channel, platform->cardBuffer, NULL);
|
||||
} while(result == CARD_ERROR_BUSY);
|
||||
@@ -59,20 +74,7 @@ void saveDeviceDolphinCardCheckAvailability(savedevice_t *device) {
|
||||
if(result < 0) {
|
||||
platform->mounted = false;
|
||||
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
|
||||
switch(result) {
|
||||
case CARD_ERROR_NOCARD:
|
||||
device->reasonKey = "save.dolphin.no_card";
|
||||
break;
|
||||
case CARD_ERROR_WRONGDEVICE:
|
||||
device->reasonKey = "save.dolphin.wrong_device";
|
||||
break;
|
||||
case CARD_ERROR_BROKEN:
|
||||
device->reasonKey = "save.dolphin.broken";
|
||||
break;
|
||||
default:
|
||||
device->reasonKey = "save.dolphin.mount_failed";
|
||||
break;
|
||||
}
|
||||
device->reasonKey = saveDeviceDolphinCardErrorReasonKey(result);
|
||||
return saveDeviceFireCallback(device);
|
||||
}
|
||||
platform->mounted = true;
|
||||
@@ -88,6 +90,15 @@ void saveDeviceDolphinCardCheckAvailability(savedevice_t *device) {
|
||||
saveDeviceFireCallback(device);
|
||||
}
|
||||
|
||||
const char_t *saveDeviceDolphinCardErrorReasonKey(const int32_t result) {
|
||||
switch(result) {
|
||||
case CARD_ERROR_NOCARD: return "save.dolphin.no_card";
|
||||
case CARD_ERROR_WRONGDEVICE: return "save.dolphin.wrong_device";
|
||||
case CARD_ERROR_BROKEN: return "save.dolphin.broken";
|
||||
default: return "save.dolphin.mount_failed";
|
||||
}
|
||||
}
|
||||
|
||||
bool_t saveDeviceDolphinCardHasFreeSpace(const int32_t channel) {
|
||||
uint16_t blockCount = 0;
|
||||
if(CARD_GetBlockCount(channel, &blockCount) < 0) return false;
|
||||
@@ -101,7 +112,12 @@ bool_t saveDeviceDolphinCardHasFreeSpace(const int32_t channel) {
|
||||
// game itself has already written.
|
||||
card_dir entries[CARD_MAXFILES];
|
||||
int32_t count = 0;
|
||||
if(CARD_GetDirectory(channel, entries, &count, true) < 0) return false;
|
||||
int32_t dirResult = CARD_GetDirectory(channel, entries, &count, true);
|
||||
// A totally empty card (no files at all yet) reports CARD_ERROR_NOFILE
|
||||
// here rather than success with count 0 - not a real error, and by far
|
||||
// the most common state for a card nobody has saved to yet.
|
||||
if(dirResult < 0 && dirResult != CARD_ERROR_NOFILE) return false;
|
||||
if(dirResult == CARD_ERROR_NOFILE) count = 0;
|
||||
if(count >= CARD_MAXFILES) return false;// No free file entry left either.
|
||||
|
||||
uint32_t usedBlocks = 0;
|
||||
|
||||
@@ -53,6 +53,15 @@ errorret_t saveDeviceDolphinCardUpdate(savedevice_t *device);
|
||||
*/
|
||||
void saveDeviceDolphinCardCheckAvailability(savedevice_t *device);
|
||||
|
||||
/**
|
||||
* Maps a libogc CARD_ERROR_* result (from CARD_Probe or CARD_Mount) to the
|
||||
* matching reasonKey.
|
||||
*
|
||||
* @param result The card_errors result code to map.
|
||||
* @return The matching reasonKey, or a generic fallback if unrecognized.
|
||||
*/
|
||||
const char_t *saveDeviceDolphinCardErrorReasonKey(const int32_t result);
|
||||
|
||||
/**
|
||||
* Returns whether the mounted memory card in the given slot has at least
|
||||
* one block of free space and one free file entry remaining, by summing
|
||||
|
||||
Reference in New Issue
Block a user