mirror of
https://github.com/suloku/gcmm.git
synced 2026-09-13 13:55:28 -05:00
F-zero and Phantasy Star Online Ep I&II and Phantasy Star Online III savegames are patched uppon restoring so they will work on target card.
Lot's of thanks to Ralf at gscentral.org forums http://board.gscentral.org/retro-hacking/53093.htm#post188949
This commit is contained in:
@@ -188,6 +188,7 @@ static s32 __card_updatedir(s32 chn,cardcallback callback);
|
||||
static s32 __card_writepage(s32 chn,cardcallback callback);
|
||||
s32 __card_sectorerase(s32 chn,u32 sector,cardcallback callback);
|
||||
static s32 __card_onreset(s32 final);
|
||||
s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2);
|
||||
|
||||
static sys_resetinfo card_resetinfo = {
|
||||
{},
|
||||
@@ -3199,3 +3200,31 @@ s32 CARD_SetGamecode(const char *gamecode)
|
||||
|
||||
return CARD_ERROR_READY;
|
||||
}
|
||||
|
||||
//The following code is made by Ralf at GSCentral forums (gscentral.org)
|
||||
//http://board.gscentral.org/retro-hacking/53093.htm#post188949
|
||||
|
||||
/***********************************************************/
|
||||
/* CARD_GetSerialNo */
|
||||
/* */
|
||||
/* serial1 & serial2: Encrypted memory card serial numbers */
|
||||
/* chn: Memory card port */
|
||||
/* ret: Error code */
|
||||
/***********************************************************/
|
||||
//note the full serial number is an u64 (serial1+serial2)
|
||||
s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2)
|
||||
{
|
||||
s32 ret;
|
||||
card_block *card = NULL;
|
||||
struct card_header *header;
|
||||
|
||||
if(chn<EXI_CHANNEL_0 || chn>=EXI_CHANNEL_2) return CARD_ERROR_FATAL_ERROR;
|
||||
if((ret=__card_getcntrlblock(chn,&card))<0) return ret;
|
||||
|
||||
header = card->workarea;
|
||||
|
||||
*serial1 = header->serial[0]^header->serial[2]^header->serial[4]^header->serial[6];
|
||||
*serial2 = header->serial[1]^header->serial[3]^header->serial[5]^header->serial[7];
|
||||
|
||||
return __card_putcntrlblock(card,ret);
|
||||
}
|
||||
|
||||
@@ -620,6 +620,13 @@ s32 __card_getstatusex(s32 chn,s32 fileno,struct card_direntry *entry);
|
||||
*/
|
||||
s32 __card_setstatusex(s32 chn,s32 fileno,struct card_direntry *entry);
|
||||
|
||||
/* CARD_GetSerialNo */
|
||||
/* */
|
||||
/* serial1 & serial2: Encrypted memory card serial numbers */
|
||||
/* chn: Memory card port */
|
||||
/* ret: Error code */
|
||||
s32 CARD_GetSerialNo(s32 chn,u32 *serial1,u32 *serial2);
|
||||
|
||||
// Raw read and write functions
|
||||
s32 __card_read(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
|
||||
s32 __card_write(s32 chn,u32 address,u32 block_len,void *buffer,cardcallback callback);
|
||||
|
||||
109
source/mcard.c
109
source/mcard.c
@@ -58,6 +58,11 @@ s32 memsize, sectsize;
|
||||
|
||||
GCI gci;
|
||||
|
||||
//The following code is made by Ralf at GSCentral forums (gscentral.org)
|
||||
//http://board.gscentral.org/retro-hacking/53093.htm#post188949
|
||||
s32 FZEROGX_MakeSaveGameValid(s32 chn);
|
||||
s32 PSO_MakeSaveGameValid(s32 chn);
|
||||
|
||||
/*---------------------------------------------------------------------------------
|
||||
This function is called if a card is physically removed
|
||||
---------------------------------------------------------------------------------*/
|
||||
@@ -589,6 +594,10 @@ tryagain:
|
||||
return 0;
|
||||
}
|
||||
|
||||
//Thanks to Ralf, validate F-zero and PSO savegames
|
||||
FZEROGX_MakeSaveGameValid(slot);
|
||||
PSO_MakeSaveGameValid(slot);
|
||||
|
||||
/*** Now write the file data, in sector sized chunks ***/
|
||||
offset = 0;
|
||||
while (offset < filelen)
|
||||
@@ -813,3 +822,103 @@ void MC_FormatMode(s32 slot)
|
||||
WaitPrompt("Format operation cancelled");
|
||||
return;
|
||||
}
|
||||
|
||||
//The following code is made by Ralf at GSCentral forums (gscentral.org)
|
||||
//http://board.gscentral.org/retro-hacking/53093.htm#post188949
|
||||
|
||||
// u8 FileBuffer[MAXFILEBUFFER]: .gci file buffer
|
||||
// MCDATAOFFSET: .gci header size (0x40 bytes)
|
||||
|
||||
/*************************************************************/
|
||||
/* FZEROGX_MakeSaveGameValid */
|
||||
/* (use just before writing a F-Zero GX system .gci file) */
|
||||
/* */
|
||||
/* chn: Destination memory card port */
|
||||
/* ret: Error code */
|
||||
/*************************************************************/
|
||||
|
||||
s32 FZEROGX_MakeSaveGameValid(s32 chn)
|
||||
{
|
||||
s32 ret;
|
||||
u32 i,j;
|
||||
u32 serial1,serial2;
|
||||
u16 chksum = 0xFFFF;
|
||||
|
||||
if(stricmp(&FileBuffer[0x08],"f_zero.dat")!=0) return CARD_ERROR_READY; // check for F-Zero GX system file
|
||||
if((ret=CARD_GetSerialNo(chn,&serial1,&serial2))<0) return ret; // get encrypted destination memory card serial numbers
|
||||
|
||||
*(u16*)&FileBuffer[0x2066+MCDATAOFFSET] = serial1 >> 16; // set new serial numbers
|
||||
*(u16*)&FileBuffer[0x7580+MCDATAOFFSET] = serial2 >> 16;
|
||||
*(u16*)&FileBuffer[0x2060+MCDATAOFFSET] = serial1 & 0xFFFF;
|
||||
*(u16*)&FileBuffer[0x2200+MCDATAOFFSET] = serial2 & 0xFFFF;
|
||||
|
||||
for(i=0x02+MCDATAOFFSET;i<0x8000+MCDATAOFFSET;i++) { // calc 16-bit checksum
|
||||
chksum ^= (FileBuffer[i]&0xFF);
|
||||
|
||||
for(j=8;j>0;j--) {
|
||||
if (chksum&1) chksum = (chksum>>1)^0x8408;
|
||||
else chksum >>= 1;
|
||||
}
|
||||
}
|
||||
|
||||
*(u16*)&FileBuffer[0x00+MCDATAOFFSET] = ~chksum; // set new checksum
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/***********************************************************/
|
||||
/* PSO_MakeSaveGameValid */
|
||||
/* (use just before writing a PSO system .gci file) */
|
||||
/* */
|
||||
/* chn: Destination memory card port */
|
||||
/* ret: Error code */
|
||||
/***********************************************************/
|
||||
|
||||
s32 PSO_MakeSaveGameValid(s32 chn)
|
||||
{
|
||||
s32 ret;
|
||||
u32 i,j;
|
||||
u32 chksum;
|
||||
u32 crc32LUT[256];
|
||||
u32 serial1,serial2;
|
||||
u32 pso3offset;
|
||||
|
||||
if(stricmp(&FileBuffer[0x08],"PSO_SYSTEM")==0) { // check for PSO1&2 system file
|
||||
pso3offset = 0x00;
|
||||
goto exit;
|
||||
}
|
||||
|
||||
if(stricmp(&FileBuffer[0x08],"PSO3_SYSTEM")==0) { // check for PSO3 system file
|
||||
pso3offset = 0x10; // PSO3 data block size adjustment
|
||||
goto exit;
|
||||
}
|
||||
|
||||
return CARD_ERROR_READY; // nothing to do
|
||||
exit:
|
||||
if((ret=CARD_GetSerialNo(chn,&serial1,&serial2))<0) return ret; // get encrypted destination memory card serial numbers
|
||||
|
||||
*(u32*)&FileBuffer[0x2158+MCDATAOFFSET] = serial1; // set new serial numbers
|
||||
*(u32*)&FileBuffer[0x215C+MCDATAOFFSET] = serial2;
|
||||
|
||||
for(i=0;i<256;i++) { // generate crc32 LUT
|
||||
chksum = i;
|
||||
|
||||
for(j=8;j>0;j--) {
|
||||
if (chksum&1) chksum = (chksum>>1)^0xEDB88320;
|
||||
else chksum >>= 1;
|
||||
}
|
||||
|
||||
crc32LUT[i] = chksum;
|
||||
}
|
||||
|
||||
chksum = 0xDEBB20E3; // PSO initial crc32 value
|
||||
|
||||
for (i=0x204C+MCDATAOFFSET;i<0x2164+pso3offset+MCDATAOFFSET;i++) { // calc 32-bit checksum
|
||||
chksum = ((chksum>>8)&0xFFFFFF)^crc32LUT[(chksum^FileBuffer[i])&0xFF];
|
||||
}
|
||||
|
||||
*(u32*)&FileBuffer[0x2048+MCDATAOFFSET] = chksum^0xFFFFFFFF; // set new checksum
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user