diff --git a/src/duskdolphin/save/savedevicedolphincard.c b/src/duskdolphin/save/savedevicedolphincard.c index e0fab1e4..3addfe05 100644 --- a/src/duskdolphin/save/savedevicedolphincard.c +++ b/src/duskdolphin/save/savedevicedolphincard.c @@ -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; diff --git a/src/duskdolphin/save/savedevicedolphincard.h b/src/duskdolphin/save/savedevicedolphincard.h index 8c3c2f29..71de92f0 100644 --- a/src/duskdolphin/save/savedevicedolphincard.h +++ b/src/duskdolphin/save/savedevicedolphincard.h @@ -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