From a9a29204ab60f9a690e901d79971cb8eb7ba8968 Mon Sep 17 00:00:00 2001 From: Pk11 Date: Mon, 3 Jan 2022 21:08:43 -0600 Subject: [PATCH] Improve unmounting and various other bug fixes (#137) * Various improvements to drive unmounting drives * Add mounting DSiWare saves They're FAT12 images, but libfat doens't like them without a little tweak since they don't have the 'FAT' identifier text * Don't try to send DSi SD card status on regular DS Fixes X and Y buttons being unresponsive --- arm7/source/main.c | 3 +- arm9/source/driveMenu.cpp | 48 ++++++--------- arm9/source/driveOperations.cpp | 48 +++++++++++++-- arm9/source/driveOperations.h | 5 +- arm9/source/file_browse.cpp | 38 ++++++------ arm9/source/hexEditor.cpp | 2 +- arm9/source/imgio.c | 77 ++++++++++++++++++------- arm9/source/imgio.h | 11 ++++ arm9/source/language.inl | 3 +- arm9/source/main.cpp | 14 ++--- nitrofiles/languages/en-US/language.ini | 3 +- 11 files changed, 159 insertions(+), 93 deletions(-) diff --git a/arm7/source/main.c b/arm7/source/main.c index 3adfe58..cb288c4 100644 --- a/arm7/source/main.c +++ b/arm7/source/main.c @@ -191,7 +191,8 @@ int main() { resyncClock(); // Send SD status - fifoSendValue32(FIFO_USER_04, SD_IRQ_STATUS); + if(isDSiMode() || *(u16*)(0x4004700) != 0) + fifoSendValue32(FIFO_USER_04, SD_IRQ_STATUS); // Dump EEPROM save if(fifoCheckAddress(FIFO_USER_01)) { diff --git a/arm9/source/driveMenu.cpp b/arm9/source/driveMenu.cpp index cb1cd5a..a675f5e 100644 --- a/arm9/source/driveMenu.cpp +++ b/arm9/source/driveMenu.cpp @@ -64,6 +64,7 @@ static char romTitle[13] = {0}; static u32 romSize, romSizeTrimmed; static u8 gbaFixedValue = 0; +static u8 stored_SCFG_MC = 0; extern bool arm7SCFGLocked; @@ -103,27 +104,11 @@ void dm_drawTopScreen(void) { break; case DriveMenuOperation::nitroFs: font->print(0, i + 1, true, STR_NITROFS_LABEL, Alignment::left, pal); - - if (!((sdMounted && nitroCurrentDrive == Drive::sdCard) - || (flashcardMounted && nitroCurrentDrive == Drive::flashcard) - || (ramdriveMounted && nitroCurrentDrive == Drive::ramDrive) - || (nandMounted && nitroCurrentDrive == Drive::nand) - || (imgMounted && nitroCurrentDrive == Drive::fatImg))) - font->print(-1, i + 1, true, "[x]", Alignment::right, pal); - else - font->print(-1, i + 1, true, "[R]", Alignment::right, pal); + font->print(-1, i + 1, true, "[R]", Alignment::right, pal); break; case DriveMenuOperation::fatImage: - if ((sdMounted && imgCurrentDrive == Drive::sdCard) - || (flashcardMounted && imgCurrentDrive == Drive::flashcard) - || (ramdriveMounted && imgCurrentDrive == Drive::ramDrive) - || (nandMounted && imgCurrentDrive == Drive::nand)) { - font->printf(0, i + 1, true, Alignment::left, pal, STR_FAT_LABEL_NAMED.c_str(), imgLabel[0] == 0 ? STR_UNTITLED.c_str() : imgLabel); - font->print(-1, i + 1, true, "[R]", Alignment::right, pal); - } else { - font->print(0, i + 1, true, STR_FAT_LABEL, Alignment::left, pal); - font->print(-1, i + 1, true, "[x]", Alignment::right, pal); - } + font->printf(0, i + 1, true, Alignment::left, pal, STR_FAT_LABEL.c_str(), imgLabel[0] == 0 ? STR_UNTITLED.c_str() : imgLabel); + font->print(-1, i + 1, true, "[R]", Alignment::right, pal); break; case DriveMenuOperation::gbaCart: font->printf(0, i + 1, true, Alignment::left, pal, STR_GBA_GAMECART.c_str(), romTitle); @@ -164,7 +149,8 @@ void dm_drawBottomScreen(void) { font->print(0, row--, false, STR_SCREENSHOTTEXT); } - font->print(0, row--, false, STR_IMAGETEXT); + if(dmOperations[dmCursorPosition] == DriveMenuOperation::nitroFs || dmOperations[dmCursorPosition] == DriveMenuOperation::fatImage) + font->print(0, row--, false, STR_IMAGETEXT); font->print(0, row--, false, titleName); switch(dmOperations[dmCursorPosition]) { @@ -201,7 +187,7 @@ void dm_drawBottomScreen(void) { font->printf(0, 2, false, Alignment::left, Palette::white, STR_N_FREE.c_str(), getDriveBytes(getBytesFree("nand:/")).c_str()); break; case DriveMenuOperation::fatImage: - font->print(0, 0, false, STR_FAT_LABEL); + font->printf(0, 0, false, Alignment::left, Palette::white, STR_FAT_LABEL.c_str(), imgLabel[0] == 0 ? STR_UNTITLED.c_str() : imgLabel); font->printf(0, 1, false, Alignment::left, Palette::white, STR_FAT_IMAGE.c_str(), getDriveBytes(imgSize).c_str()); break; case DriveMenuOperation::none: @@ -221,11 +207,11 @@ void driveMenu (void) { } dmOperations.clear(); - if (sdMounted) + if (sdMounted && !sdRemoved) dmOperations.push_back(DriveMenuOperation::sdCard); if (nandMounted) dmOperations.push_back(DriveMenuOperation::sysNand); - if (flashcardMounted) + if (flashcardMounted && !driveRemoved(Drive::flashcard)) dmOperations.push_back(DriveMenuOperation::flashcard); if (ramdriveMounted) dmOperations.push_back(DriveMenuOperation::ramDrive); @@ -268,6 +254,9 @@ void driveMenu (void) { romSizeTrimmed = romSize = 0; } + if(dmCursorPosition >= (int)dmOperations.size()) + dmCursorPosition = dmOperations.size() - 1; + dm_drawBottomScreen(); dm_drawTopScreen(); @@ -289,7 +278,7 @@ void driveMenu (void) { break; } } else if (isDSiMode()) { - if (REG_SCFG_MC != stored_SCFG_MC) { + if ((REG_SCFG_MC != stored_SCFG_MC) || (flashcardMounted && driveRemoved(Drive::flashcard))) { break; } if (sdMounted && sdRemoved) { @@ -378,11 +367,11 @@ void driveMenu (void) { // Unmount/Remount FAT image if ((held & KEY_R) && (pressed & KEY_X)) { - if (nitroMounted) { + if (dmOperations[dmCursorPosition] == DriveMenuOperation::nitroFs) { currentDrive = Drive::nitroFS; chdir("nitro:/"); nitroUnmount(); - } else if (imgMounted) { + } else if (dmOperations[dmCursorPosition] == DriveMenuOperation::fatImage) { currentDrive = Drive::fatImg; chdir("img:/"); imgUnmount(); @@ -427,15 +416,16 @@ void driveMenu (void) { screenshot(); } - if (isDSiMode() && !flashcardMountSkipped && !pressed && !held) { - if (REG_SCFG_MC == 0x11) { + if (isDSiMode() && !flashcardMountSkipped) { + if (driveRemoved(Drive::flashcard)) { if (flashcardMounted) { flashcardUnmount(); + flashcardMountRan = false; } } else if (!flashcardMountRan) { + flashcardMountRan = true; flashcardMounted = flashcardMount(); // Try to mount flashcard } - flashcardMountRan = false; } } } diff --git a/arm9/source/driveOperations.cpp b/arm9/source/driveOperations.cpp index 76d0317..8011625 100644 --- a/arm9/source/driveOperations.cpp +++ b/arm9/source/driveOperations.cpp @@ -2,6 +2,7 @@ #include #include +#include #include #include #include @@ -25,8 +26,6 @@ static sNDSHeader nds; -u8 stored_SCFG_MC = 0; - static bool slot1Enabled = true; bool nandMounted = false; @@ -176,6 +175,11 @@ u64 getBytesFree(const char* drivePath) { } void sdUnmount(void) { + if(imgMounted && imgCurrentDrive == Drive::sdCard) + imgUnmount(); + if(nitroMounted && nitroCurrentDrive == Drive::sdCard) + nitroUnmount(); + fatUnmount("sd"); my_sdio_Shutdown(); sdLabel[0] = '\0'; @@ -327,6 +331,11 @@ bool flashcardMount(void) { } void flashcardUnmount(void) { + if(imgMounted && imgCurrentDrive == Drive::flashcard) + imgUnmount(); + if(nitroMounted && nitroCurrentDrive == Drive::flashcard) + nitroUnmount(); + fatUnmount("fat"); fatLabel[0] = '\0'; fatSize = 0; @@ -400,15 +409,19 @@ void ramdriveMount(bool ram32MB) { } void nitroUnmount(void) { + if(imgMounted && imgCurrentDrive == Drive::nitroFS) + imgUnmount(); + + ownNitroFSMounted = 2; fatUnmount("nitro"); nitroMounted = false; } -bool imgMount(const char* imgName) { - extern const char* currentImgName; +bool imgMount(const char* imgName, bool dsiwareSave) { + extern char currentImgName[PATH_MAX]; - currentImgName = imgName; - fatMountSimple("img", &io_img); + strcpy(currentImgName, imgName); + fatMountSimple("img", dsiwareSave ? &io_dsiware_save : &io_img); if (imgFound()) { fatGetVolumeLabel("img", imgLabel); fixLabel(imgLabel); @@ -422,7 +435,11 @@ bool imgMount(const char* imgName) { } void imgUnmount(void) { + if(nitroMounted && nitroCurrentDrive == Drive::fatImg) + nitroUnmount(); + fatUnmount("img"); + img_shutdown(); imgLabel[0] = '\0'; imgSize = 0; imgMounted = false; @@ -446,3 +463,22 @@ bool driveWritable(Drive drive) { return false; } + +bool driveRemoved(Drive drive) { + switch(drive) { + case Drive::sdCard: + return sdRemoved; + case Drive::flashcard: + return REG_SCFG_MC & BIT(0); + case Drive::ramDrive: + return !ramdriveMounted; + case Drive::nand: + return !nandMounted; + case Drive::nitroFS: + return driveRemoved(nitroCurrentDrive); + case Drive::fatImg: + return driveRemoved(imgCurrentDrive); + } + + return false; +} diff --git a/arm9/source/driveOperations.h b/arm9/source/driveOperations.h index 4763e32..53fccc6 100644 --- a/arm9/source/driveOperations.h +++ b/arm9/source/driveOperations.h @@ -13,8 +13,6 @@ enum class Drive : u8 { fatImg }; -extern u8 stored_SCFG_MC; - extern bool nandMounted; extern bool sdMounted; extern bool sdMountedDone; // true if SD mount is successful once @@ -53,9 +51,10 @@ extern bool flashcardMount(void); extern void flashcardUnmount(void); extern void ramdriveMount(bool ram32MB); extern void nitroUnmount(void); -extern bool imgMount(const char* imgName); +extern bool imgMount(const char* imgName, bool dsiwareSave); extern void imgUnmount(void); extern u64 getBytesFree(const char* drivePath); extern bool driveWritable(Drive drive); +extern bool driveRemoved(Drive drive); #endif //FLASHCARD_H diff --git a/arm9/source/file_browse.cpp b/arm9/source/file_browse.cpp index eafcd3a..38bfe1a 100644 --- a/arm9/source/file_browse.cpp +++ b/arm9/source/file_browse.cpp @@ -180,15 +180,19 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) { } } - if(extension(entry->name, {"nds", "dsi", "ids", "app"})) { - operations.push_back(FileOperation::mountNitroFS); + if(extension(entry->name, {"nds", "dsi", "ids", "app", "srl"})) { + if(currentDrive != Drive::nitroFS) + operations.push_back(FileOperation::mountNitroFS); operations.push_back(FileOperation::ndsInfo); operations.push_back(FileOperation::trimNds); - } else if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) { + } + if(extension(entry->name, {"sav", "sav1", "sav2", "sav3", "sav4", "sav5", "sav6", "sav7", "sav8", "sav9"})) { operations.push_back(FileOperation::restoreSave); - } else if(extension(entry->name, {"img", "sd"})) { + } + if(currentDrive != Drive::fatImg && extension(entry->name, {"img", "sd", "sav", "pub", "pu1", "pu2", "pu3", "pu4", "pu5", "pu6", "pu7", "pu8", "pu9", "prv", "pr1", "pr2", "pr3", "pr4", "pr5", "pr6", "pr7", "pr8", "pr9"})) { operations.push_back(FileOperation::mountImg); - } else if(extension(entry->name, {"frf"})) { + } + if(extension(entry->name, {"frf"})) { operations.push_back(FileOperation::loadFont); } @@ -282,7 +286,7 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) { held = keysHeld(); swiWaitForVBlank(); - if(currentDrive == Drive::sdCard && sdRemoved) + if(driveRemoved(currentDrive)) return FileOperation::none; } while (!(pressed & (KEY_UP| KEY_DOWN | KEY_A | KEY_B | KEY_L)) #ifdef SCREENSWAP @@ -378,6 +382,9 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) { chdir(sourceFolder); // For after copying a folder break; } case FileOperation::mountNitroFS: { + if(nitroMounted) + nitroUnmount(); + ownNitroFSMounted = 2; nitroMounted = nitroFSInit(entry->name.c_str()); if (nitroMounted) { @@ -396,7 +403,10 @@ FileOperation fileBrowse_A(DirEntry* entry, char path[PATH_MAX]) { changeFileAttribs(entry); break; } case FileOperation::mountImg: { - imgMounted = imgMount(entry->name.c_str()); + if(imgMounted) + imgUnmount(); + + imgMounted = imgMount(entry->name.c_str(), !extension(entry->name, {"img", "sd"})); if (imgMounted) { chdir("img:/"); imgCurrentDrive = currentDrive; @@ -639,8 +649,6 @@ std::string browseForFile (void) { fileBrowse_drawBottomScreen(entry); showDirectoryContents(dirContents, fileOffset, screenOffset); - stored_SCFG_MC = REG_SCFG_MC; - // Power saving loop. Only poll the keys once per frame and sleep the CPU if there is nothing else to do do { // Print time @@ -652,22 +660,12 @@ std::string browseForFile (void) { held = keysHeld(); swiWaitForVBlank(); - if (REG_SCFG_MC != stored_SCFG_MC) { - break; - } - - if(currentDrive == Drive::sdCard && sdRemoved) { + if(driveRemoved(currentDrive)) { screenMode = 0; return "null"; } } while (!(pressed & ~(KEY_R | KEY_TOUCH | KEY_LID))); - if (isDSiMode() && !pressed && currentDrive == Drive::flashcard && REG_SCFG_MC == 0x11 && flashcardMounted) { - flashcardUnmount(); - screenMode = 0; - return "null"; - } - if (pressed & KEY_UP) { fileOffset--; if(fileOffset < 0) diff --git a/arm9/source/hexEditor.cpp b/arm9/source/hexEditor.cpp index 45791a9..f2f0f1f 100644 --- a/arm9/source/hexEditor.cpp +++ b/arm9/source/hexEditor.cpp @@ -289,7 +289,7 @@ void hexEditor(const char *path, Drive drive) { font->print(-1, 0, true, RetTime(), Alignment::right, Palette::blackGreen); font->update(true); - if(currentDrive == Drive::sdCard && sdRemoved) + if(driveRemoved(currentDrive)) return; } while(!held); diff --git a/arm9/source/imgio.c b/arm9/source/imgio.c index 0741371..9fab93c 100644 --- a/arm9/source/imgio.c +++ b/arm9/source/imgio.c @@ -1,44 +1,57 @@ +#include "tonccpy.h" #include #include #include +#include #define SECTOR_SIZE 512 +// #define WRITABLE -const char* currentImgName; -static FILE* imgFile[2]; +char currentImgName[PATH_MAX]; +static FILE* imgFile; bool img_startup() { - imgFile[0] = fopen(currentImgName, "rb"); - if (imgFile[0]) { - //imgFile[1] = fopen(currentImgName, "wb"); - return true; - } - return false; +#ifdef WRITABLE + imgFile = fopen(currentImgName, "rb+"); +#else + imgFile = fopen(currentImgName, "rb"); +#endif + return imgFile != NULL; } bool img_is_inserted() { - if (imgFile[0]) { - return true; - } - return false; + return imgFile != NULL; } bool img_read_sectors(sec_t sector, sec_t numSectors, void *buffer) { - if (!imgFile[0]) return false; + if (!imgFile) return false; - fseek(imgFile[0], (sector << 9), SEEK_SET); - fread(buffer, 1, (numSectors << 9), imgFile[0]); + fseek(imgFile, (sector << 9), SEEK_SET); + fread(buffer, 1, (numSectors << 9), imgFile); + + return true; +} + +bool dsiware_read_sectors(sec_t sector, sec_t numSectors, void *buffer) { + if(!img_read_sectors(sector, numSectors, buffer)) return false; + + // DSiWare saves are FAT12 images, however they don't have the 'FAT' text + // in the bootsector so libfat rejects them + if (sector == 0) tonccpy(buffer + 0x36, "FAT", 3); return true; } bool img_write_sectors(sec_t sector, sec_t numSectors, const void *buffer) { - /*if (!imgFile[1]) return false; +#ifdef WRITABLE + if (!imgFile) return false; - fseek(imgFile[1], (sector << 9), SEEK_SET); - fwrite(buffer, 1, (numSectors << 9), imgFile[1]); - return true;*/ + fseek(imgFile, (sector << 9), SEEK_SET); + fwrite(buffer, 1, (numSectors << 9), imgFile); + return true; +#else return false; +#endif } bool img_clear_status() { @@ -46,15 +59,20 @@ bool img_clear_status() { } bool img_shutdown() { - fclose(imgFile[0]); - fclose(imgFile[1]); + if (imgFile) { + fclose(imgFile); + imgFile = NULL; + } return true; } const DISC_INTERFACE io_img = { ('I' << 24) | ('M' << 16) | ('G' << 8) | 'F', - //FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE, +#ifdef WRITABLE + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE, +#else FEATURE_MEDIUM_CANREAD, +#endif img_startup, img_is_inserted, img_read_sectors, @@ -62,3 +80,18 @@ const DISC_INTERFACE io_img = { img_clear_status, img_shutdown }; + +const DISC_INTERFACE io_dsiware_save = { + ('I' << 24) | ('M' << 16) | ('G' << 8) | 'F', +#ifdef WRITABLE + FEATURE_MEDIUM_CANREAD | FEATURE_MEDIUM_CANWRITE, +#else + FEATURE_MEDIUM_CANREAD, +#endif + img_startup, + img_is_inserted, + dsiware_read_sectors, + img_write_sectors, + img_clear_status, + img_shutdown +}; diff --git a/arm9/source/imgio.h b/arm9/source/imgio.h index a203e7e..6dac8b3 100644 --- a/arm9/source/imgio.h +++ b/arm9/source/imgio.h @@ -3,4 +3,15 @@ #include #include +#ifdef __cplusplus +extern "C" { +#endif + +bool img_shutdown(); + extern const DISC_INTERFACE io_img; +extern const DISC_INTERFACE io_dsiware_save; + +#ifdef __cplusplus +} +#endif diff --git a/arm9/source/language.inl b/arm9/source/language.inl index 7ebd67d..e0889e6 100644 --- a/arm9/source/language.inl +++ b/arm9/source/language.inl @@ -42,8 +42,7 @@ STRING(FLASHCARD_LABEL, "[fat:] FLASHCARD (%s)") STRING(RAMDRIVE_LABEL, "[ram:] RAMDRIVE") STRING(SYSNAND_LABEL, "[nand:] SYSNAND") STRING(NITROFS_LABEL, "[nitro:] NDS GAME IMAGE") -STRING(FAT_LABEL_NAMED, "[nitro:] FAT IMAGE (%s)") -STRING(FAT_LABEL, "[nitro:] FAT IMAGE") +STRING(FAT_LABEL, "[img:] FAT IMAGE (%s)") STRING(GBA_GAMECART, "GBA GAMECART (%s)") STRING(NDS_GAMECARD, "NDS GAMECARD (%s)") diff --git a/arm9/source/main.cpp b/arm9/source/main.cpp index 6da95e3..9b875d2 100644 --- a/arm9/source/main.cpp +++ b/arm9/source/main.cpp @@ -188,15 +188,15 @@ int main(int argc, char **argv) { // Try to init NitroFS ownNitroFSMounted = 0; - if (argc > 0 && nitroFSInit(argv[0])); - else if (nitroFSInit("GodMode9i.nds")); - else if (nitroFSInit("GodMode9i.dsi")); - else if (nitroFSInit("sd:/GodMode9i.nds")); - else if (nitroFSInit("sd:/GodMode9i.dsi")); - else if (nitroFSInit("fat:/GodMode9i.nds")); - else if (nitroFSInit("fat:/GodMode9i.dsi")); + nitroMounted = true; + if (argc > 0 && nitroFSInit(argv[0])) nitroCurrentDrive = argv[0][0] == 's' ? Drive::sdCard : Drive::flashcard; + else if (nitroFSInit("sd:/GodMode9i.nds")) nitroCurrentDrive = Drive::sdCard; + else if (nitroFSInit("sd:/GodMode9i.dsi")) nitroCurrentDrive = Drive::sdCard; + else if (nitroFSInit("fat:/GodMode9i.nds")) nitroCurrentDrive = Drive::flashcard; + else if (nitroFSInit("fat:/GodMode9i.dsi")) nitroCurrentDrive = Drive::flashcard; else { ownNitroFSMounted = 1; + nitroMounted = false; font->print(-2, -3, false, "NitroFS init failed...", Alignment::right); font->update(false); for (int i = 0; i < 30; i++) diff --git a/nitrofiles/languages/en-US/language.ini b/nitrofiles/languages/en-US/language.ini index 15edd62..8cd9bff 100644 --- a/nitrofiles/languages/en-US/language.ini +++ b/nitrofiles/languages/en-US/language.ini @@ -41,8 +41,7 @@ FLASHCARD_LABEL=[fat:] FLASHCARD (%s) RAMDRIVE_LABEL=[ram:] RAMDRIVE SYSNAND_LABEL=[nand:] SYSNAND NITROFS_LABEL=[nitro:] NDS GAME IMAGE -FAT_LABEL_NAMED=[nitro:] FAT IMAGE (%s) -FAT_LABEL=[nitro:] FAT IMAGE +FAT_LABEL=[img:] FAT IMAGE (%s) GBA_GAMECART=GBA GAMECART (%s) NDS_GAMECARD=NDS GAMECARD (%s)