Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
f4641ca
Add MemCardPro GameID support (using Swiss implementation)
jllottes Jul 8, 2025
d39bf64
Added "Off"/"Full ID"/"Short ID" options.
jllottes Jul 9, 2025
b3bbe92
Update README.md
Arrghus8 Jul 9, 2025
0e03757
Added "Off"/"Full ID"/"Short ID" options.
jllottes Jul 9, 2025
c8f1816
Replace spaces with tabs. Add Swiss copyright information to `MemCard…
jllottes Jul 10, 2025
fd79549
Replace spaces with tabs. Add Swiss copyright information to `MemCard…
jllottes Jul 10, 2025
2751853
Replace spaces with tabs. Add Swiss copyright information to `MemCard…
jllottes Jul 10, 2025
10539bb
Replace spaces with tabs. Add Swiss copyright information to `MemCard…
jllottes Jul 10, 2025
badf8c8
Send GameID information within `BootDevolution`, `BootNintendont`, an…
jllottes Jul 10, 2025
2aeb648
Send GameID information within `BootDevolution`, `BootNintendont`, an…
jllottes Jul 10, 2025
394fdea
Cleaning up, send GameID with (c)MIOS, fix `BootDIOSMIOS` GameID
jllottes Jul 10, 2025
2b4a0b8
Cleaning up, send GameID with (c)MIOS, fix `BootDIOSMIOS` GameID
jllottes Jul 10, 2025
2f8efe8
Cleaning up, send GameID with (c)MIOS, fix `BootDIOSMIOS` GameID
jllottes Jul 10, 2025
a82bc3c
Move "MemCardPro GameID" setting above "GameCube Mode" setting.
jllottes Jul 10, 2025
d6f41b6
Move "MemCardPro GameID" setting above "GameCube Mode" setting.
jllottes Jul 10, 2025
830f876
Move "MemCardPro GameID" setting above "GameCube Mode" setting.
jllottes Jul 10, 2025
468bf0c
Change setting name "MemCardPro GameID" -> "MemCard PRO Game ID"
jllottes Jul 10, 2025
17eca89
Change setting name "MemCard PRO Game ID" -> "MemCard PRO GameID"
jllottes Jul 10, 2025
7076bdc
Change setting name "MemCard PRO GameID" -> "MemCard PRO"
jllottes Jul 10, 2025
b1dfe4c
Move "MemCard PRO" setting below "GameCube Mode" in `LoaderSettings.cpp`
jllottes Jul 11, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
142 changes: 142 additions & 0 deletions source/GameCube/MemCardPro.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
/*
* Copyright (c) 2022, Extrems <extrems@extremscorner.org>
*
* This file is part of Swiss.
*
* Swiss is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Swiss is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* with Swiss. If not, see <https://www.gnu.org/licenses/>.
*/

/*
* Lightly modified from Swiss, mcp.c
*/

#include <stdbool.h>
#include <string.h>
#include <ogc/card.h>
#include <ogc/exi.h>
#include "usbloader/disc.h"
#include "MemCardPro.h"

static const char digits[] = "0123456789ABCDEF";

s32 MCP_ProbeEx(s32 chan)
{
return CARD_ProbeEx(chan, NULL, NULL);
}

s32 MCP_GetDeviceID(s32 chan, u32 *id)
{
bool err = false;
u8 cmd[2];

if (!EXI_Lock(chan, EXI_DEVICE_0, NULL)) return MCP_RESULT_BUSY;
if (!EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED16MHZ)) {
EXI_Unlock(chan);
return MCP_RESULT_NOCARD;
}

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 MCP_RESULT_NOCARD;
else if (*id >> 16 != 0x3842)
return MCP_RESULT_WRONGDEVICE;
else
return MCP_RESULT_READY;
}

s32 MCP_SetDiskID(s32 chan, const dvddiskid *diskID, bool shortID)
{
bool err = false;
u8 cmd[12];

if (!EXI_Lock(chan, EXI_DEVICE_0, NULL)) return MCP_RESULT_BUSY;
if (!EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED16MHZ)) {
EXI_Unlock(chan);
return MCP_RESULT_NOCARD;
}

memset(cmd, 0, sizeof(cmd));
cmd[0] = 0x8B;
cmd[1] = 0x11;

if (diskID) {
memcpy(&cmd[2], diskID->gamename, 4);
if (!shortID){
memcpy(&cmd[6], diskID->company, 2);
cmd[8] = digits[diskID->disknum / 16];
cmd[9] = digits[diskID->disknum % 16];
cmd[10] = digits[diskID->gamever / 16];
cmd[11] = digits[diskID->gamever % 16];
}
}

err |= !EXI_ImmEx(chan, cmd, sizeof(cmd), EXI_WRITE);
err |= !EXI_Deselect(chan);
EXI_Unlock(chan);

return err ? MCP_RESULT_NOCARD : MCP_RESULT_READY;
}

s32 MCP_SetDiskInfo(s32 chan, const char diskInfo[64])
{
bool err = false;
u8 cmd[2];

if (!EXI_Lock(chan, EXI_DEVICE_0, NULL)) return MCP_RESULT_BUSY;
if (!EXI_Select(chan, EXI_DEVICE_0, EXI_SPEED16MHZ)) {
EXI_Unlock(chan);
return MCP_RESULT_NOCARD;
}

cmd[0] = 0x8B;
cmd[1] = 0x13;

err |= !EXI_Imm(chan, cmd, 2, EXI_WRITE, NULL);
err |= !EXI_Sync(chan);
err |= !EXI_ImmEx(chan, (char *)diskInfo, 64, EXI_WRITE);
err |= !EXI_Deselect(chan);
EXI_Unlock(chan);

return err ? MCP_RESULT_NOCARD : MCP_RESULT_READY;
}

/*
* Lightly modified from Swiss, gameid.c
*/

void gameID_early_set(const discHdr *header, bool shortID)
{
for (s32 chan = 0; chan < 2; chan++) {
u32 id;
s32 ret;

while ((ret = MCP_ProbeEx(chan)) == MCP_RESULT_BUSY);
if (ret < 0) continue;
while ((ret = MCP_GetDeviceID(chan, &id)) == MCP_RESULT_BUSY);
if (ret < 0) continue;
while ((ret = MCP_SetDiskID(chan, (dvddiskid *)header, shortID)) == MCP_RESULT_BUSY);
if (ret < 0) continue;
while ((ret = MCP_SetDiskInfo(chan, header->title)) == MCP_RESULT_BUSY);
if (ret < 0) continue;
}
}
51 changes: 51 additions & 0 deletions source/GameCube/MemCardPro.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
/*
* Copyright (c) 2022, Extrems <extrems@extremscorner.org>
*
* This file is part of Swiss.
*
* Swiss is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* Swiss is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* with Swiss. If not, see <https://www.gnu.org/licenses/>.
*/

/*
* Lightly modified from Swiss, mcp.h
*/

#ifndef __MCP_H__
#define __MCP_H__

#include <gctypes.h>
#include <ogc/dvd.h>
#include "usbloader/disc.h"

#define MCP_RESULT_READY 0
#define MCP_RESULT_BUSY -1
#define MCP_RESULT_WRONGDEVICE -2
#define MCP_RESULT_NOCARD -3
#define MCP_RESULT_FATAL_ERROR -128

#ifdef __cplusplus
extern "C" {
#endif

s32 MCP_ProbeEx(s32 chan);
s32 MCP_GetDeviceID(s32 chan, u32 *id);
s32 MCP_SetDiskID(s32 chan, const dvddiskid *diskID, bool shortID);
s32 MCP_SetDiskInfo(s32 chan, const char diskInfo[64]);
void gameID_early_set(const discHdr *header, bool shortID);

#ifdef __cplusplus
}
#endif

#endif
7 changes: 7 additions & 0 deletions source/settings/CGameSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -210,6 +210,7 @@ bool CGameSettings::Save()
fprintf(f, "WiirdDebugger:%d; ", GameList[i].WiirdDebugger);
fprintf(f, "wpadMotor:%d; ", GameList[i].wpadMotor);
fprintf(f, "wpadSpeaker:%d; ", GameList[i].wpadSpeaker);
fprintf(f, "MemCardProGameID:%d; ", GameList[i].MemCardProGameID);
fprintf(f, "GameCubeMode:%d; ", GameList[i].GameCubeMode);
fprintf(f, "DMLVideo:%d; ", GameList[i].DMLVideo);
fprintf(f, "DMLProgPatch:%d; ", GameList[i].DMLProgPatch);
Expand Down Expand Up @@ -397,6 +398,11 @@ bool CGameSettings::SetSetting(GameCFG & game, const char *name, const char *val
game.Locked = atoi(value);
return true;
}
else if(strcmp(name, "MemCardProGameID") == 0)
{
game.MemCardProGameID = atoi(value);
return true;
}
else if(strcmp(name, "GameCubeMode") == 0)
{
game.GameCubeMode = atoi(value);
Expand Down Expand Up @@ -735,6 +741,7 @@ void CGameSettings::SetDefault(GameCFG &game)
game.WiirdDebugger = INHERIT;
game.wpadMotor = INHERIT;
game.wpadSpeaker = INHERIT;
game.MemCardProGameID = INHERIT;
game.GameCubeMode = INHERIT;
game.DMLVideo = INHERIT;
game.DMLProgPatch = INHERIT;
Expand Down
2 changes: 2 additions & 0 deletions source/settings/CGameSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@ typedef struct _GameCFG
short WiirdDebugger;
short wpadMotor;
short wpadSpeaker;
short MemCardProGameID;
short GameCubeMode;
short DMLVideo;
short DMLProgPatch;
Expand Down Expand Up @@ -109,6 +110,7 @@ typedef struct _GameCFG
this->WiirdDebugger = game.WiirdDebugger;
this->wpadMotor = game.wpadMotor;
this->wpadSpeaker = game.wpadSpeaker;
this->MemCardProGameID = game.MemCardProGameID;
this->GameCubeMode = game.GameCubeMode;
this->DMLVideo = game.DMLVideo;
this->DMLProgPatch = game.DMLProgPatch;
Expand Down
7 changes: 7 additions & 0 deletions source/settings/CSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,7 @@ void CSettings::SetDefault()
BannerProjectionWidth = (Settings.widescreen ? (Settings.PAL50 ? 616 : 620.0f) : 608.0f);
BannerProjectionHeight = (Settings.PAL50 ? 448.0f : (NTSC ? 470.0f : 464.0f));
GCBannerScale = 1.5f;
MemCardProGameID = OFF;
GameCubeMode = GC_MODE_NINTENDONT;
GameCubeSource = AUTO;
MultiDiscPrompt = OFF;
Expand Down Expand Up @@ -484,6 +485,7 @@ bool CSettings::Save()
fprintf(file, "GCBannerScale = %g\n", GCBannerScale);
fprintf(file, "GameCubePath = %s\n", GameCubePath);
fprintf(file, "GameCubeSDPath = %s\n", GameCubeSDPath);
fprintf(file, "MemCardProGameID = %d\n", MemCardProGameID);
fprintf(file, "GameCubeMode = %d\n", GameCubeMode);
fprintf(file, "GameCubeSource = %d\n", GameCubeSource);
fprintf(file, "MultiDiscPrompt = %d\n", MultiDiscPrompt);
Expand Down Expand Up @@ -1041,6 +1043,11 @@ bool CSettings::SetSetting(char *name, char *value)
ParentalBlocks = strtoul(value, 0, 16);
return true;
}
else if (strcmp(name, "MemCardProGameID") == 0)
{
MemCardProGameID = atoi(value);
return true;
}
else if (strcmp(name, "GameCubeMode") == 0)
{
GameCubeMode = atoi(value);
Expand Down
1 change: 1 addition & 0 deletions source/settings/CSettings.h
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ class CSettings
float BannerProjectionWidth;
float BannerProjectionHeight;
float GCBannerScale;
short MemCardProGameID;
short GameCubeMode;
short GameCubeSource;
short MultiDiscPrompt;
Expand Down
9 changes: 9 additions & 0 deletions source/settings/SettingsEnums.h
Original file line number Diff line number Diff line change
Expand Up @@ -357,6 +357,15 @@ enum

};

enum
{
MEMCARDPRO_GAMEID_OFF,
MEMCARDPRO_GAMEID_ON_FULL,
MEMCARDPRO_GAMEID_ON_SHORT,
MEMCARDPRO_GAMEID_MAX_CHOICE

};

enum
{
DEVO_MC_OFF,
Expand Down
20 changes: 20 additions & 0 deletions source/settings/menus/GCGameLoadSM.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,13 @@ static const char * GCMode[] =
trNOOP( "Nintendont" )
};

static const char * MCPGameID[] =
{
trNOOP( "OFF"),
trNOOP( "Full ID" ),
trNOOP( "Short ID" )
};

static const char * DMLVideoText[] =
{
trNOOP( "Auto" ),
Expand Down Expand Up @@ -183,6 +190,7 @@ void GCGameLoadSM::SetOptionNames()
Options->SetName(Idx++, "%s", tr( "Favorite Level" ));
Options->SetName(Idx++, "%s", tr( "Game Language" ));
Options->SetName(Idx++, "%s", tr( "Parental Control" ));
Options->SetName(Idx++, "%s", tr( "MemCard PRO" ));
Options->SetName(Idx++, "%s", tr( "GameCube Mode" ));
if(currentGCmode == GC_MODE_MIOS &&IosLoader::GetMIOSInfo() > DEFAULT_MIOS)
{
Expand Down Expand Up @@ -269,6 +277,12 @@ void GCGameLoadSM::SetOptionValues()
//! Settings: Parental Control
Options->SetValue(Idx++, "%s", tr(ParentalText[GameConfig.parentalcontrol]));

//! Settings: MemCard PRO
if(GameConfig.MemCardProGameID == INHERIT)
Options->SetValue(Idx++, tr("Use global"));
else
Options->SetValue(Idx++, "%s", tr(MCPGameID[GameConfig.MemCardProGameID]));

//! Settings: GameCube Mode
if(GameConfig.GameCubeMode == INHERIT)
Options->SetValue(Idx++, tr("Use global"));
Expand Down Expand Up @@ -654,6 +668,12 @@ int GCGameLoadSM::GetMenuInternal()
if (++GameConfig.parentalcontrol >= 5) GameConfig.parentalcontrol = 0;
}

//! Settings: MemCard PRO
else if (ret == ++Idx)
{
if (++GameConfig.MemCardProGameID >= MEMCARDPRO_GAMEID_MAX_CHOICE) GameConfig.MemCardProGameID = INHERIT;
}

//! Settings: GameCube Mode
else if (ret == ++Idx)
{
Expand Down
17 changes: 17 additions & 0 deletions source/settings/menus/LoaderSettings.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -156,6 +156,13 @@ static const char * GCMode[] =
trNOOP( "Nintendont" )
};

static const char * MCPGameID[] =
{
trNOOP( "OFF"),
trNOOP( "Full ID" ),
trNOOP( "Short ID" )
};

static const char * GCSourceText[][3] =
{
{ trNOOP( "Main Path" ), "", "" },
Expand Down Expand Up @@ -322,6 +329,7 @@ void LoaderSettings::SetOptionNames()
Options->SetName(Idx++, "%s", tr( "=== GameCube Settings" ));
Options->SetName(Idx++, "%s", tr( "GameCube Source" ));
Options->SetName(Idx++, "%s", tr( "GameCube Mode" ));
Options->SetName(Idx++, "%s", tr( "MemCard PRO" ));
Options->SetName(Idx++, "%s", tr( "Progressive Patch" ));
Options->SetName(Idx++, "%s", tr( "--== DM(L) + Nintendont" ));
Options->SetName(Idx++, "%s", tr( "Video Mode" ));
Expand Down Expand Up @@ -500,6 +508,9 @@ void LoaderSettings::SetOptionValues()
//! Settings: GameCube Mode
Options->SetValue(Idx++, "%s", tr(GCMode[Settings.GameCubeMode]));

//! Settings: MemCard PRO
Options->SetValue(Idx++, "%s", tr(MCPGameID[Settings.MemCardProGameID]));

//! Settings: DML + NIN + Devo Progressive Patch
Options->SetValue(Idx++, "%s", tr(OnOffText[Settings.DMLProgPatch]));

Expand Down Expand Up @@ -921,6 +932,12 @@ int LoaderSettings::GetMenuInternal()
if (++Settings.GameCubeMode >= CG_MODE_MAX_CHOICE) Settings.GameCubeMode = 0;
}

//! Settings: MemCard PRO
else if (ret == ++Idx)
{
if (++Settings.MemCardProGameID >= MEMCARDPRO_GAMEID_MAX_CHOICE) Settings.MemCardProGameID = 0;
}

//! Settings: DML + NIN + Devo Progressive Patch
else if (ret == ++Idx)
{
Expand Down
Loading