From a186ea2715cdb877b3cc5b3d4269a18e2ace8d48 Mon Sep 17 00:00:00 2001 From: Colin Edwards Date: Sun, 30 Jul 2023 12:52:12 -0500 Subject: [PATCH] Add MemCard Pro GC Support Uses code from the swiss implementation https://github.com/emukidid/swiss-gc/commit/3ee5c037e236060e38521f8f29187c1581df414a --- common/include/CommonConfig.h | 3 ++ loader/include/MemCardPro.h | 10 +++++ loader/include/menu.h | 2 + loader/source/MemCardPro.c | 71 +++++++++++++++++++++++++++++++++++ loader/source/main.c | 9 +++++ loader/source/menu.c | 8 ++++ 6 files changed, 103 insertions(+) create mode 100644 loader/include/MemCardPro.h create mode 100644 loader/source/MemCardPro.c diff --git a/common/include/CommonConfig.h b/common/include/CommonConfig.h index d85dce41b..43695060a 100644 --- a/common/include/CommonConfig.h +++ b/common/include/CommonConfig.h @@ -25,6 +25,9 @@ typedef struct NIN_CFG signed char VideoOffset; unsigned char NetworkProfile; unsigned int WiiUGamepadSlot; + unsigned int GameMakerCode; + unsigned int GameRevision; + unsigned int GameDiscNumber; } NIN_CFG; enum ninconfigbitpos diff --git a/loader/include/MemCardPro.h b/loader/include/MemCardPro.h new file mode 100644 index 000000000..6bd4dcf06 --- /dev/null +++ b/loader/include/MemCardPro.h @@ -0,0 +1,10 @@ +#ifndef __MEMCARDPRO_H__ +#define __MEMCARDPRO_H__ + +#include +#include "global.h" + +bool CheckForMemCardPro(s32 chan); +void SetMemCardProGameInfo(s32 chan, NIN_CFG* ncfg); + +#endif \ No newline at end of file diff --git a/loader/include/menu.h b/loader/include/menu.h index 9728cece8..a14fe5e6a 100644 --- a/loader/include/menu.h +++ b/loader/include/menu.h @@ -57,6 +57,8 @@ typedef struct GameInfo char ID[6]; // ID6 of the game. uint8_t Revision; // Disc revision. uint8_t Flags; // See GameInfoFlags. + char MakerCode[2]; + uint8_t DiscNumber; char *Name; // Game name. (If NameAlloc, strdup()'d.) char *Path; // File path. diff --git a/loader/source/MemCardPro.c b/loader/source/MemCardPro.c new file mode 100644 index 000000000..0b199b818 --- /dev/null +++ b/loader/source/MemCardPro.c @@ -0,0 +1,71 @@ +/* + Lightly modified from the implementation in swiss + https://github.com/emukidid/swiss-gc/commit/3ee5c037e236060e38521f8f29187c1581df414a +*/ + +#include "MemCardPro.h" + +#include +#include + +static const char digits[16] = "0123456789ABCDEF"; + +bool CheckForMemCardPro(s32 chan) +{ + if (CARD_ProbeEx(chan, NULL, NULL) < 0) { + return false; + } + + bool err = false; + u32 id; + u8 cmd[2]; + + if (!EXI_Lock(chan, EXI_DEVICE_0, NULL)) return false; + if (!EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED16MHZ)) { + EXI_Unlock(chan); + return false; + } + + cmd[0] = 0x8B; + cmd[1] = 0x00; + + err |= !EXI_Imm(chan, cmd, 2, EXI_WRITE, NULL); + err |= !EXI_Sync(chan); + err |= !EXI_Imm(chan, &id, 4, EXI_READ, NULL); + err |= !EXI_Sync(chan); + err |= !EXI_Deselect(chan); + EXI_Unlock(chan); + + if (err) + return false; + else if (id >> 16 != 0x3842) + return false; + else + return true; +} + +void SetMemCardProGameInfo(s32 chan, NIN_CFG* ncfg) +{ + u8 cmd[12]; + + if (!EXI_Lock(chan, EXI_DEVICE_0, NULL)) return; + if (!EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED16MHZ)) { + EXI_Unlock(chan); + return; + } + + memset(cmd, 0, sizeof(cmd)); + cmd[0] = 0x8B; + cmd[1] = 0x11; + + memcpy(&cmd[2], &ncfg->GameID, 4); + memcpy(&cmd[6], &ncfg->GameMakerCode, 2); + cmd[8] = digits[ncfg->GameDiscNumber / 16]; + cmd[9] = digits[ncfg->GameDiscNumber % 16]; + cmd[10] = digits[ncfg->GameRevision / 16]; + cmd[11] = digits[ncfg->GameRevision % 16]; + + EXI_ImmEx(chan, cmd, sizeof(cmd), EXI_WRITE); + EXI_Deselect(chan); + EXI_Unlock(chan); +} \ No newline at end of file diff --git a/loader/source/main.c b/loader/source/main.c index a0be6caab..230226ade 100644 --- a/loader/source/main.c +++ b/loader/source/main.c @@ -36,6 +36,7 @@ Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA. #include "FPad.h" #include "menu.h" #include "MemCard.h" +#include "MemCardPro.h" #include "Patches.h" #include "kernel_zip.h" #include "kernelboot_bin.h" @@ -1121,6 +1122,14 @@ int main(int argc, char **argv) sram->lang = ncfg->Language; __SYS_UnlockSram(1); // 1 -> write changes while(!__SYS_SyncSram()); + + // Send game ID to MemCard Pro GC + s32 chan; + for ( chan = 0; chan < 2; chan++) { + if (CheckForMemCardPro(chan)) { + SetMemCardProGameInfo(chan, ncfg); + } + } } //Check if game is Triforce game diff --git a/loader/source/menu.c b/loader/source/menu.c index 9ca452e47..59e5ccae3 100644 --- a/loader/source/menu.c +++ b/loader/source/menu.c @@ -222,6 +222,11 @@ static bool IsDiscImageValid(const char *filename, int discNumber, gameinfo *gi) // Save the revision number. gi->Revision = buf[0x07]; + // Save the maker code. + memcpy(gi->MakerCode, &buf[0x4], 2); + + gi->DiscNumber = discNumber; + // Check if this is a multi-game image. // Reference: https://gbatemp.net/threads/wit-wiimms-iso-tools-gamecube-disc-support.251630/#post-3088119 const bool is_multigame = IsMultiGameDisc((const char*)buf); @@ -1843,6 +1848,9 @@ static int SelectGame(void) strncpy(ncfg->GamePath, StartChar, sizeof(ncfg->GamePath)); ncfg->GamePath[sizeof(ncfg->GamePath)-1] = 0; memcpy(&(ncfg->GameID), gi[SelectedGame].ID, 4); + memcpy(&(ncfg->GameMakerCode), gi[SelectedGame].MakerCode, 2); + ncfg->GameRevision = gi[SelectedGame].Revision; + ncfg->GameDiscNumber = gi[SelectedGame].DiscNumber; DCFlushRange((void*)ncfg, sizeof(NIN_CFG)); } // Free allocated memory in the game list.