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);
|
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 {
|
do {
|
||||||
result = CARD_Mount(platform->channel, platform->cardBuffer, NULL);
|
result = CARD_Mount(platform->channel, platform->cardBuffer, NULL);
|
||||||
} while(result == CARD_ERROR_BUSY);
|
} while(result == CARD_ERROR_BUSY);
|
||||||
@@ -59,20 +74,7 @@ void saveDeviceDolphinCardCheckAvailability(savedevice_t *device) {
|
|||||||
if(result < 0) {
|
if(result < 0) {
|
||||||
platform->mounted = false;
|
platform->mounted = false;
|
||||||
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
|
device->state = SAVE_DEVICE_STATE_UNAVAILABLE;
|
||||||
switch(result) {
|
device->reasonKey = saveDeviceDolphinCardErrorReasonKey(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;
|
|
||||||
}
|
|
||||||
return saveDeviceFireCallback(device);
|
return saveDeviceFireCallback(device);
|
||||||
}
|
}
|
||||||
platform->mounted = true;
|
platform->mounted = true;
|
||||||
@@ -88,6 +90,15 @@ void saveDeviceDolphinCardCheckAvailability(savedevice_t *device) {
|
|||||||
saveDeviceFireCallback(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) {
|
bool_t saveDeviceDolphinCardHasFreeSpace(const int32_t channel) {
|
||||||
uint16_t blockCount = 0;
|
uint16_t blockCount = 0;
|
||||||
if(CARD_GetBlockCount(channel, &blockCount) < 0) return false;
|
if(CARD_GetBlockCount(channel, &blockCount) < 0) return false;
|
||||||
@@ -101,7 +112,12 @@ bool_t saveDeviceDolphinCardHasFreeSpace(const int32_t channel) {
|
|||||||
// game itself has already written.
|
// game itself has already written.
|
||||||
card_dir entries[CARD_MAXFILES];
|
card_dir entries[CARD_MAXFILES];
|
||||||
int32_t count = 0;
|
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.
|
if(count >= CARD_MAXFILES) return false;// No free file entry left either.
|
||||||
|
|
||||||
uint32_t usedBlocks = 0;
|
uint32_t usedBlocks = 0;
|
||||||
|
|||||||
@@ -53,6 +53,15 @@ errorret_t saveDeviceDolphinCardUpdate(savedevice_t *device);
|
|||||||
*/
|
*/
|
||||||
void saveDeviceDolphinCardCheckAvailability(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
|
* 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
|
* one block of free space and one free file entry remaining, by summing
|
||||||
|
|||||||
Reference in New Issue
Block a user