2022-11-27 06:38:23 +09:00
|
|
|
#include "gcn.h"
|
|
|
|
#include "card.h"
|
2023-05-16 03:27:33 +09:00
|
|
|
#include "drawText.h"
|
2022-11-27 06:38:23 +09:00
|
|
|
|
|
|
|
#if VERSION == 1
|
|
|
|
#define FILENAME "GCT_GMSE01"
|
|
|
|
#elif VERSION == 2
|
|
|
|
#define FILENAME "GCT_GMSJ01"
|
|
|
|
#elif VERSION == 3
|
|
|
|
#define FILENAME "GCT_GMSP01"
|
|
|
|
#elif VERSION == 4
|
|
|
|
#define FILENAME "GCT_GMSJ0A"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
// Memory space reserved for Gecko codes to store their state
|
|
|
|
// data, based on the current usage
|
|
|
|
// See: https://github.com/BitPatty/gctGenerator/blob/375ba5eb73e50894d4e765fdfddbe004e3b4949d/Readme.md#reserved-memory
|
|
|
|
// Range: 0x817F0000 - 0x817F1000
|
|
|
|
#define ADDR_GECKO_HEAP_START 0x817F0000
|
2023-02-10 23:20:40 +09:00
|
|
|
#define ADDR_GECKO_HEAP_SIZE 0x00001000
|
2022-11-27 06:38:23 +09:00
|
|
|
#define ADDR_GECKO_HEAP_END (ADDR_GECKO_HEAP_START + ADDR_GECKO_HEAP_SIZE)
|
2023-02-10 23:20:40 +09:00
|
|
|
// GCTDST = 0x817F1000; // in ldscripts/sms.ld
|
|
|
|
|
|
|
|
extern struct GCTBuffer {
|
|
|
|
// =0: initialized
|
|
|
|
// >0: Loading(1), Done(2)
|
|
|
|
// <0: error
|
|
|
|
int status;
|
|
|
|
// return address to the original Gecko handler
|
|
|
|
void *returnAddr;
|
|
|
|
// actual Gecko code
|
|
|
|
u32 code[0];
|
|
|
|
} GCTDST;
|
|
|
|
|
|
|
|
#define GCT_LOAD_LOADING 1
|
|
|
|
#define GCT_LOAD_DONE 2
|
2022-11-27 06:38:23 +09:00
|
|
|
|
|
|
|
void loadCodes(TCardManager *cm, CARDFileInfo *fileInfo)
|
|
|
|
{
|
2023-02-10 23:20:40 +09:00
|
|
|
GCTDST.status = GCT_LOAD_LOADING;
|
|
|
|
// load card
|
|
|
|
int rc = loadCard(cm, fileInfo, FILENAME, GCTDST.code);
|
|
|
|
GCTDST.status = rc == 0 ? GCT_LOAD_DONE : rc; // DONE or Error code
|
2022-11-27 06:38:23 +09:00
|
|
|
}
|
|
|
|
|
2023-02-10 23:20:40 +09:00
|
|
|
int onReadOptionBlock(TCardManager *this, CARDFileInfo *fileInfo)
|
|
|
|
{
|
|
|
|
if (GCTDST.status <= 0) // Initialized(=0) or Error(<0)
|
|
|
|
loadCodes(this, fileInfo);
|
|
|
|
return open_(this, fileInfo);
|
|
|
|
}
|
2023-05-16 03:27:33 +09:00
|
|
|
|
|
|
|
// TODO better hook address?
|
|
|
|
// e.g. hook after fader.draw() (but also avoid conflict with controller display)
|
|
|
|
void JUTRect_set(void *r3, u32 r4, u32 r5, u32 r6, u32 r7);
|
|
|
|
void willDrawFader(void *r3, u32 r4, u32 r5, u32 r6, u32 r7) {
|
|
|
|
JUTRect_set(r3, r4, r5, r6, r7);
|
|
|
|
|
|
|
|
// do not show GCI status until boot finished
|
|
|
|
if (gpApplication.directorType < 4) return;
|
|
|
|
DrawTextOpt opt = {
|
|
|
|
.x = 16,
|
|
|
|
.y = 440,
|
|
|
|
.fontSize = 32,
|
|
|
|
.colorTop = 0xff3333bb,
|
|
|
|
.colorBot = 0xff3333bb
|
|
|
|
};
|
|
|
|
switch (GCTDST.status) {
|
|
|
|
case LOAD_ERR_MOUNT:
|
|
|
|
drawText(&opt, "Fail to mount memory card");
|
|
|
|
break;
|
|
|
|
case LOAD_ERR_OPEN:
|
|
|
|
drawText(&opt, "Fail to open GCI file: "FILENAME);
|
|
|
|
break;
|
|
|
|
case LOAD_ERR_SIZE:
|
|
|
|
drawText(&opt, "GCI file too large: "FILENAME);
|
|
|
|
break;
|
|
|
|
case LOAD_ERR_FILE_NOT_EXIST:
|
|
|
|
drawText(&opt, "GCI file not exists: "FILENAME);
|
|
|
|
break;
|
|
|
|
case LOAD_ERR_READ:
|
|
|
|
drawText(&opt, "Fail to read GCI file");
|
|
|
|
break;
|
|
|
|
case LOAD_STAT_INIT:
|
|
|
|
drawText(&opt, "Preparing to load GCI file...");
|
|
|
|
break;
|
|
|
|
case LOAD_STAT_LOADING:
|
|
|
|
drawText(&opt, "Loading GCI file...");
|
|
|
|
break;
|
|
|
|
case LOAD_STAT_DONE:
|
|
|
|
break;
|
|
|
|
default:
|
|
|
|
drawText(&opt, "Unknown GCI Error: %d", GCTDST.status);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|