From b44fb658a15a844374a9816864cbd9bfdc985574 Mon Sep 17 00:00:00 2001 From: dbalatoni13 Date: Tue, 12 Nov 2024 03:38:42 +0100 Subject: [PATCH] Imported dolphin/card --- include/dolphin/CARDPriv.h | 202 ++++++----- include/dolphin/os/OSReset.h | 1 + src/dolphin/card/CARDBios.c | 615 ++++++++++++++++++++++++++++++++++ src/dolphin/card/CARDBlock.c | 170 ++++++++++ src/dolphin/card/CARDCheck.c | 343 +++++++++++++++++++ src/dolphin/card/CARDCreate.c | 126 +++++++ src/dolphin/card/CARDDelete.c | 111 ++++++ src/dolphin/card/CARDDir.c | 101 ++++++ src/dolphin/card/CARDFormat.c | 141 ++++++++ src/dolphin/card/CARDMount.c | 396 ++++++++++++++++++++++ src/dolphin/card/CARDNet.c | 34 ++ src/dolphin/card/CARDOpen.c | 134 ++++++++ src/dolphin/card/CARDRdwr.c | 108 ++++++ src/dolphin/card/CARDRead.c | 149 ++++++++ src/dolphin/card/CARDRename.c | 70 ++++ src/dolphin/card/CARDStat.c | 158 +++++++++ src/dolphin/card/CARDUnlock.c | 406 ++++++++++++++++++++++ src/dolphin/card/CARDWrite.c | 128 +++++++ 18 files changed, 3315 insertions(+), 78 deletions(-) create mode 100644 src/dolphin/card/CARDBios.c create mode 100644 src/dolphin/card/CARDBlock.c create mode 100644 src/dolphin/card/CARDCheck.c create mode 100644 src/dolphin/card/CARDCreate.c create mode 100644 src/dolphin/card/CARDDelete.c create mode 100644 src/dolphin/card/CARDDir.c create mode 100644 src/dolphin/card/CARDFormat.c create mode 100644 src/dolphin/card/CARDMount.c create mode 100644 src/dolphin/card/CARDNet.c create mode 100644 src/dolphin/card/CARDOpen.c create mode 100644 src/dolphin/card/CARDRdwr.c create mode 100644 src/dolphin/card/CARDRead.c create mode 100644 src/dolphin/card/CARDRename.c create mode 100644 src/dolphin/card/CARDStat.c create mode 100644 src/dolphin/card/CARDUnlock.c create mode 100644 src/dolphin/card/CARDWrite.c diff --git a/include/dolphin/CARDPriv.h b/include/dolphin/CARDPriv.h index ca28f6e1..8e531702 100644 --- a/include/dolphin/CARDPriv.h +++ b/include/dolphin/CARDPriv.h @@ -21,103 +21,149 @@ extern "C" { #define CARD_MAX_MOUNT_STEP (CARD_NUM_SYSTEM_BLOCK + 2) typedef struct CARDDir { - u8 gameName[4]; - u8 company[2]; - u8 _padding0; - u8 bannerFormat; - u8 fileName[CARD_FILENAME_MAX]; - u32 time; // seconds since 01/01/2000 midnight + u8 gameName[4]; + u8 company[2]; + u8 _padding0; + u8 bannerFormat; + u8 fileName[CARD_FILENAME_MAX]; + u32 time; // seconds since 01/01/2000 midnight - u32 iconAddr; // 0xffffffff if not used - u16 iconFormat; - u16 iconSpeed; + u32 iconAddr; // 0xffffffff if not used + u16 iconFormat; + u16 iconSpeed; - u8 permission; - u8 copyTimes; - u16 startBlock; - u16 length; - u8 _padding1[2]; + u8 permission; + u8 copyTimes; + u16 startBlock; + u16 length; + u8 _padding1[2]; - u32 commentAddr; // 0xffffffff if not used + u32 commentAddr; // 0xffffffff if not used } CARDDir; typedef struct CARDDirCheck { - u8 padding0[64 - 2 * 4]; - u16 padding1; - s16 checkCode; - u16 checkSum; - u16 checkSumInv; + u8 padding0[64 - 2 * 4]; + u16 padding1; + s16 checkCode; + u16 checkSum; + u16 checkSumInv; } CARDDirCheck; typedef struct CARDControl { - BOOL attached; - s32 result; - u16 size; - u16 pageSize; - s32 sectorSize; - u16 cBlock; - u16 vendorID; - s32 latency; - u8 id[12]; - int mountStep; - int formatStep; - u32 scramble; - DSPTaskInfo task; - void* workArea; - CARDDir* currentDir; - u16* currentFat; - OSThreadQueue threadQueue; - u8 cmd[9]; - s32 cmdlen; - vu32 mode; - int retry; - int repeat; - u32 addr; - void* buffer; - s32 xferred; - u16 freeNo; - u16 startBlock; - CARDFileInfo* fileInfo; - CARDCallback extCallback; - CARDCallback txCallback; - CARDCallback exiCallback; - CARDCallback apiCallback; - CARDCallback xferCallback; - CARDCallback eraseCallback; - CARDCallback unlockCallback; - OSAlarm alarm; - u32 cid; - const DVDDiskID* diskID; + BOOL attached; + s32 result; + u16 size; + u16 pageSize; + s32 sectorSize; + u16 cBlock; + u16 vendorID; + s32 latency; + u8 id[12]; + int mountStep; + int formatStep; + u32 scramble; + DSPTaskInfo task; + void *workArea; + CARDDir *currentDir; + u16 *currentFat; + OSThreadQueue threadQueue; + u8 cmd[9]; + s32 cmdlen; + vu32 mode; + int retry; + int repeat; + u32 addr; + void *buffer; + s32 xferred; + u16 freeNo; + u16 startBlock; + CARDFileInfo *fileInfo; + CARDCallback extCallback; + CARDCallback txCallback; + CARDCallback exiCallback; + CARDCallback apiCallback; + CARDCallback xferCallback; + CARDCallback eraseCallback; + CARDCallback unlockCallback; + OSAlarm alarm; + u32 cid; + const DVDDiskID *diskID; } CARDControl; typedef struct CARDID { - u8 serial[32]; // flashID[12] + timebase[8] + counterBias[4] + language[4] + XXX[4] - u16 deviceID; - u16 size; - u16 encode; // character set -- 0: S-JIS, 1: ANSI + u8 serial[32]; // flashID[12] + timebase[8] + counterBias[4] + language[4] + XXX[4] + u16 deviceID; + u16 size; + u16 encode; // character set -- 0: S-JIS, 1: ANSI - u8 padding[512 - 32 - 5 * 2]; + u8 padding[512 - 32 - 5 * 2]; - u16 checkSum; - u16 checkSumInv; + u16 checkSum; + u16 checkSumInv; } CARDID; void __CARDDefaultApiCallback(s32 chan, s32 result); +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback); +s32 __CARDPutControlBlock(struct CARDControl *card, s32 result); +void __CARDSyncCallback(s32 chan, s32 result); +u16 *__CARDGetFatBlock(CARDControl *card); -#define CARDIsValidBlockNo(card, iBlock) \ - (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) -#define __CARDGetDirCheck(dir) ((CARDDirCheck*)&(dir)[CARD_MAX_FILE]) +/* CARDBios */ +void __CARDExtHandler(s32 chan, OSContext *context); +void __CARDExiHandler(s32 chan, OSContext *context); +void __CARDTxHandler(s32 chan, OSContext *context); +void __CARDUnlockedHandler(s32 chan, OSContext *context); +s32 __CARDEnableInterrupt(s32 chan, BOOL enable); +s32 __CARDReadStatus(s32 chan, u8 *status); +s32 __CARDReadVendorID(s32 chan, u16 *vendorId); +s32 __CARDClearStatus(s32 chan); +s32 __CARDStart(s32 chan, CARDCallback txCallback, CARDCallback exiCallback); +s32 __CARDReadSegment(s32 chan, CARDCallback callback); +s32 __CARDWritePage(s32 chan, CARDCallback callback); +u16 __CARDGetFontEncode(void); +void __CARDSetDiskID(const DVDDiskID *id); +s32 __CARDGetControlBlock(s32 chan, struct CARDControl **pcard); +s32 __CARDSync(s32 chan); -CARDDir* __CARDGetDirBlock(CARDControl* card); -u16* __CARDGetFatBlock(CARDControl* card); -s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback); -void __CARDCheckSum(void* ptr, int length, u16* checkSum, u16* checkSumInv); -u16 __CARDGetFontEncode(); -void __CARDExiHandler(s32 chan, OSContext* context); -void __CARDExtHandler(s32 chan, OSContext* context); -void __CARDUnlockedHandler(s32 chan, OSContext* context); -s32 __CARDAccess(CARDControl* card, CARDDir* ent); -BOOL __CARDIsWritable(CARDDir* ent); +/* CARDBlock */ +s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback); +s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback); +s32 __CARDUpdateFatBlock(s32 chan, u16 *fat, CARDCallback callback); + +/* CARDCheck */ +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv); +s32 __CARDVerify(CARDControl *card); + +/* CARDDir */ +CARDDir *__CARDGetDirBlock(CARDControl *card); +s32 __CARDUpdateDir(s32 chan, CARDCallback callback); + +/* CARDFormat */ +s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback); + +/* CARDMount */ +void __CARDMountCallback(s32 chan, s32 result); + +/* CARDOpen */ +BOOL __CARDCompareFileName(CARDDir *ent, const char *fileName); +s32 __CARDAccess(CARDControl *card, CARDDir *ent); +BOOL __CARDIsPublic(CARDDir *ent); +s32 __CARDIsReadable(CARDControl *card, CARDDir *ent); +s32 __CARDGetFileNo(CARDControl *card, const char *fileName, s32 *pfileNo); +BOOL __CARDIsOpened(CARDControl *card, s32 fileNo); + +/* CARDRdwr */ +s32 __CARDRead(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback); +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback); + +/* CARDRead */ +s32 __CARDSeek(CARDFileInfo *fileInfo, s32 length, s32 offset, CARDControl **pcard); + +/* CARDUnlock */ +s32 __CARDUnlock(s32 chan, u8 flashID[12]); + +#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) +#define __CARDGetDirCheck(dir) ((CARDDirCheck *)&(dir)[CARD_MAX_FILE]) #define TRUNC(n, a) (((u32)(n)) & ~((a)-1)) #define OFFSET(n, a) (((u32)(n)) & ((a)-1)) diff --git a/include/dolphin/os/OSReset.h b/include/dolphin/os/OSReset.h index d420a6f8..ae0e77e3 100644 --- a/include/dolphin/os/OSReset.h +++ b/include/dolphin/os/OSReset.h @@ -39,6 +39,7 @@ struct OSResetFunctionInfo { OSResetFunctionInfo* prev; }; +void OSRegisterResetFunction(OSResetFunctionInfo *info); u32 OSGetResetCode(void); #ifdef __cplusplus diff --git a/src/dolphin/card/CARDBios.c b/src/dolphin/card/CARDBios.c new file mode 100644 index 00000000..ff2d55ff --- /dev/null +++ b/src/dolphin/card/CARDBios.c @@ -0,0 +1,615 @@ +#include +#include +#include +#include +#include + +#include + +CARDControl __CARDBlock[2]; +DVDDiskID __CARDDiskNone; + +static u16 __CARDEncode; + +s32 __CARDReadStatus(s32 chan, u8 *status); +s32 __CARDClearStatus(s32 chan); +void __CARDSetDiskID(const DVDDiskID *id); +static s32 Retry(s32 chan); + +static BOOL OnReset(BOOL f); +static OSResetFunctionInfo ResetFunctionInfo = { OnReset, 127 }; + +void __CARDDefaultApiCallback(s32 chan, s32 result) { } + +void __CARDSyncCallback(s32 chan, s32 result) +{ + OSWakeupThread(&__CARDBlock[chan].threadQueue); +} + +void __CARDExtHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (card->attached) { + card->attached = FALSE; + EXISetExiCallback(chan, 0); + OSCancelAlarm(&card->alarm); + callback = card->exiCallback; + + if (callback) { + card->exiCallback = 0; + callback(chan, CARD_RESULT_NOCARD); + } + + if (card->result != CARD_RESULT_BUSY) { + card->result = CARD_RESULT_NOCARD; + } + + callback = card->extCallback; + if (callback && CARD_MAX_MOUNT_STEP <= card->mountStep) { + card->extCallback = 0; + callback(chan, CARD_RESULT_NOCARD); + } + } +} + +void __CARDExiHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + u8 status; + s32 result; + + card = &__CARDBlock[chan]; + + OSCancelAlarm(&card->alarm); + + if (!card->attached) { + return; + } + + if (!EXILock(chan, 0, 0)) { + result = CARD_RESULT_FATAL_ERROR; + goto fatal; + } + + if ((result = __CARDReadStatus(chan, &status)) < 0 || (result = __CARDClearStatus(chan)) < 0) { + goto error; + } + + if ((result = (status & 0x18) ? CARD_RESULT_IOERROR : CARD_RESULT_READY) == CARD_RESULT_IOERROR && --card->retry > 0) { + result = Retry(chan); + if (result >= 0) { + return; + } + goto fatal; + } + +error: + EXIUnlock(chan); + +fatal: + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, result); + } +} + +void __CARDTxHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + BOOL err; + + card = &__CARDBlock[chan]; + err = !EXIDeselect(chan); + EXIUnlock(chan); + callback = card->txCallback; + if (callback) { + card->txCallback = 0; + callback(chan, (!err && EXIProbe(chan)) ? CARD_RESULT_READY : CARD_RESULT_NOCARD); + } +} + +void __CARDUnlockedHandler(s32 chan, OSContext *context) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->unlockCallback; + if (callback) { + card->unlockCallback = 0; + callback(chan, EXIProbe(chan) ? CARD_RESULT_UNLOCKED : CARD_RESULT_NOCARD); + } +} + +s32 __CARDEnableInterrupt(s32 chan, BOOL enable) +{ + BOOL err; + u32 cmd; + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = enable ? 0x81010000 : 0x81000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, 1, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDReadStatus(s32 chan, u8 *status) +{ + BOOL err; + u32 cmd; + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x83000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 2, 1, NULL); + err |= !EXISync(chan); + err |= !EXIImm(chan, status, 1, 0, NULL); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +s32 __CARDClearStatus(s32 chan) +{ + BOOL err; + u32 cmd; + + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + cmd = 0x89000000; + err = FALSE; + err |= !EXIImm(chan, &cmd, 1, 1, 0); + err |= !EXISync(chan); + err |= !EXIDeselect(chan); + + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +static void TimeoutHandler(OSAlarm *alarm, OSContext *context) +{ + s32 chan; + CARDControl *card; + CARDCallback callback; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if (alarm == &card->alarm) { + break; + } + } + + if (!card->attached) { + return; + } + + EXISetExiCallback(chan, NULL); + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, CARD_RESULT_IOERROR); + } +} + +static void SetupTimeoutAlarm(CARDControl *card) +{ + OSCancelAlarm(&card->alarm); + switch (card->cmd[0]) { + case 0xF2: + OSSetAlarm(&card->alarm, OSMillisecondsToTicks(100), TimeoutHandler); + break; + case 0xF3: + break; + case 0xF4: + case 0xF1: + OSSetAlarm(&card->alarm, OSSecondsToTicks((OSTime)2) * (card->sectorSize / 0x2000), TimeoutHandler); + break; + } +} + +static s32 Retry(s32 chan) +{ + CARDControl *card; + card = &__CARDBlock[chan]; + + if (!EXISelect(chan, 0, 4)) { + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + SetupTimeoutAlarm(card); + + if (!EXIImmEx(chan, card->cmd, card->cmdlen, 1)) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + if (card->cmd[0] == 0x52 && !EXIImmEx(chan, (u8 *)card->workArea + sizeof(CARDID), card->latency, 1)) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + if (card->mode == 0xffffffff) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_READY; + } + + if (!EXIDma(chan, card->buffer, (s32)((card->cmd[0] == 0x52) ? 512 : 128), card->mode, __CARDTxHandler)) { + EXIDeselect(chan); + EXIUnlock(chan); + return CARD_RESULT_NOCARD; + } + + return CARD_RESULT_READY; +} + +static void UnlockedCallback(s32 chan, s32 result) +{ + CARDCallback callback; + CARDControl *card; + + card = &__CARDBlock[chan]; + if (result >= 0) { + card->unlockCallback = UnlockedCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + result = CARD_RESULT_READY; + } + else { + card->unlockCallback = 0; + result = Retry(chan); + } + } + + if (result < 0) { + switch (card->cmd[0]) { + case 0x52: + callback = card->txCallback; + if (callback) { + card->txCallback = 0; + callback(chan, result); + } + + break; + case 0xF2: + case 0xF4: + case 0xF1: + callback = card->exiCallback; + if (callback) { + card->exiCallback = 0; + callback(chan, result); + } + break; + } + } +} + +static s32 __CARDStart(s32 chan, CARDCallback txCallback, CARDCallback exiCallback) +{ + BOOL enabled; + CARDControl *card; + s32 result; + + enabled = OSDisableInterrupts(); + + card = &__CARDBlock[chan]; + if (!card->attached) { + result = CARD_RESULT_NOCARD; + } + else { + + if (txCallback) { + card->txCallback = txCallback; + } + if (exiCallback) { + card->exiCallback = exiCallback; + } + card->unlockCallback = UnlockedCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + result = CARD_RESULT_BUSY; + } + else { + card->unlockCallback = 0; + + if (!EXISelect(chan, 0, 4)) { + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } + else { + SetupTimeoutAlarm(card); + result = CARD_RESULT_READY; + } + } + } + + OSRestoreInterrupts(enabled); + return result; +} + +#define AD1(x) ((u8)(((x) >> 17) & 0x7f)) +#define AD1EX(x) ((u8)(AD1(x) | 0x80)); +#define AD2(x) ((u8)(((x) >> 9) & 0xff)) +#define AD3(x) ((u8)(((x) >> 7) & 0x03)) +#define BA(x) ((u8)((x)&0x7f)) + +s32 __CARDReadSegment(s32 chan, CARDCallback callback) +{ + CARDControl *card; + s32 result; + + card = &__CARDBlock[chan]; + card->cmd[0] = 0x52; + card->cmd[1] = AD1(card->addr); + card->cmd[2] = AD2(card->addr); + card->cmd[3] = AD3(card->addr); + card->cmd[4] = BA(card->addr); + card->cmdlen = 5; + card->mode = 0; + card->retry = 0; + + result = __CARDStart(chan, callback, 0); + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } + else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, 1) + || !EXIImmEx(chan, (u8 *)card->workArea + sizeof(CARDID), card->latency, + 1) + || // XXX use DMA if possible + !EXIDma(chan, card->buffer, 512, card->mode, __CARDTxHandler)) { + card->txCallback = 0; + EXIDeselect(chan); + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } + else { + result = CARD_RESULT_READY; + } + } + return result; +} + +s32 __CARDWritePage(s32 chan, CARDCallback callback) +{ + CARDControl *card; + s32 result; + + card = &__CARDBlock[chan]; + card->cmd[0] = 0xF2; + card->cmd[1] = AD1(card->addr); + card->cmd[2] = AD2(card->addr); + card->cmd[3] = AD3(card->addr); + card->cmd[4] = BA(card->addr); + card->cmdlen = 5; + card->mode = 1; + card->retry = 3; + + result = __CARDStart(chan, 0, callback); + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } + else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, 1) || !EXIDma(chan, card->buffer, 128, card->mode, __CARDTxHandler)) { + card->exiCallback = 0; + EXIDeselect(chan); + EXIUnlock(chan); + result = CARD_RESULT_NOCARD; + } + else { + result = CARD_RESULT_READY; + } + } + return result; +} + +s32 __CARDEraseSector(s32 chan, u32 addr, CARDCallback callback) +{ + CARDControl *card; + s32 result; + + card = &__CARDBlock[chan]; + card->cmd[0] = 0xF1; + card->cmd[1] = AD1(addr); + card->cmd[2] = AD2(addr); + card->cmdlen = 3; + card->mode = -1; + card->retry = 3; + + result = __CARDStart(chan, 0, callback); + + if (result == CARD_RESULT_BUSY) { + result = CARD_RESULT_READY; + } + else if (result >= 0) { + if (!EXIImmEx(chan, card->cmd, card->cmdlen, 1)) { + card->exiCallback = NULL; + result = CARD_RESULT_NOCARD; + } + else { + result = CARD_RESULT_READY; + } + + EXIDeselect(chan); + EXIUnlock(chan); + } + return result; +} + +void CARDInit(void) +{ + int chan; + + if (__CARDBlock[0].diskID && __CARDBlock[1].diskID) { + return; + } + + DSPInit(); + OSInitAlarm(); + + for (chan = 0; chan < 2; ++chan) { + CARDControl *card = &__CARDBlock[chan]; + + card->result = CARD_RESULT_NOCARD; + OSInitThreadQueue(&card->threadQueue); + OSCreateAlarm(&card->alarm); + } + __CARDSetDiskID((DVDDiskID *)OSPhysicalToCached(0x0)); + + OSRegisterResetFunction(&ResetFunctionInfo); +} + +u16 __CARDGetFontEncode() +{ + return __CARDEncode; +} + +void __CARDSetDiskID(const DVDDiskID *id) +{ + __CARDBlock[0].diskID = id ? id : &__CARDDiskNone; + __CARDBlock[1].diskID = id ? id : &__CARDDiskNone; +} + +s32 __CARDGetControlBlock(s32 chan, CARDControl **pcard) +{ + BOOL enabled; + s32 result; + CARDControl *card; + + card = &__CARDBlock[chan]; + if (chan < 0 || chan >= 2 || card->diskID == NULL) { + return CARD_RESULT_FATAL_ERROR; + } + + enabled = OSDisableInterrupts(); + if (!card->attached) { + result = CARD_RESULT_NOCARD; + } + else if (card->result == CARD_RESULT_BUSY) { + result = CARD_RESULT_BUSY; + } + else { + card->result = CARD_RESULT_BUSY; + result = CARD_RESULT_READY; + card->apiCallback = 0; + *pcard = card; + } + OSRestoreInterrupts(enabled); + return result; +} + +s32 __CARDPutControlBlock(CARDControl *card, s32 result) +{ + BOOL enabled; + + enabled = OSDisableInterrupts(); + if (card->attached) { + card->result = result; + } + else if (card->result == CARD_RESULT_BUSY) { + card->result = result; + } + OSRestoreInterrupts(enabled); + return result; +} + +s32 CARDGetResultCode(s32 chan) +{ + CARDControl *card; + if (chan < 0 || chan >= 2) { + return CARD_RESULT_FATAL_ERROR; + } + card = &__CARDBlock[chan]; + return card->result; +} + +s32 CARDFreeBlocks(s32 chan, s32 *byteNotUsed, s32 *filesNotUsed) +{ + CARDControl *card; + s32 result; + u16 *fat; + CARDDir *dir; + CARDDir *ent; + u16 fileNo; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + fat = __CARDGetFatBlock(card); + dir = __CARDGetDirBlock(card); + if (fat == 0 || dir == 0) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + if (byteNotUsed) { + *byteNotUsed = (s32)(card->sectorSize * fat[CARD_FAT_FREEBLOCKS]); + } + + if (filesNotUsed) { + *filesNotUsed = 0; + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->fileName[0] == 0xff) { + ++*filesNotUsed; + } + } + } + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +s32 CARDGetSectorSize(s32 chan, u32 *size) +{ + struct CARDControl *card; + long result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + *size = card->sectorSize; + return __CARDPutControlBlock(card, 0); +} + +s32 __CARDSync(s32 chan) +{ + CARDControl *block; + s32 result; + s32 enabled; + + block = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + while ((result = CARDGetResultCode(chan)) == -1) { + OSSleepThread(&block->threadQueue); + } + OSRestoreInterrupts(enabled); + return result; +} + +static BOOL OnReset(BOOL f) +{ + if (!f) { + if (CARDUnmount(0) == CARD_RESULT_BUSY || CARDUnmount(1) == CARD_RESULT_BUSY) { + return FALSE; + } + } + + return TRUE; +} diff --git a/src/dolphin/card/CARDBlock.c b/src/dolphin/card/CARDBlock.c new file mode 100644 index 00000000..c6543c7f --- /dev/null +++ b/src/dolphin/card/CARDBlock.c @@ -0,0 +1,170 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +u16 *__CARDGetFatBlock(CARDControl *card) +{ + return card->currentFat; +} + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u16 *fat; + u16 *fatBack; + + card = &__CARDBlock[chan]; + + if (result >= 0) { + fat = (u16 *)((u8 *)card->workArea + 0x6000); + fatBack = (u16 *)((u8 *)card->workArea + 0x8000); + + if (card->currentFat == fat) { + card->currentFat = fatBack; + memcpy(fatBack, fat, 0x2000); + } + else { + card->currentFat = fat; + memcpy(fat, fatBack, 0x2000); + } + } + + if (card->apiCallback == NULL) { + __CARDPutControlBlock(card, result); + } + + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u32 temp[2]; /* this compiler sucks */ + u16 *fat; + u32 addr; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fat = __CARDGetFatBlock(card); + addr = ((u32)fat - (u32)card->workArea) / CARD_SYSTEM_BLOCK_SIZE * card->sectorSize; + result = __CARDWrite(chan, addr, CARD_SYSTEM_BLOCK_SIZE, fat, WriteCallback); + if (result < 0) { + goto error; + } + + return; + +error: + if (card->apiCallback == NULL) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = NULL; + callback(chan, result); + } +} + +s32 __CARDAllocBlock(s32 chan, u32 cBlock, CARDCallback callback) +{ + CARDControl *card; + u16 *fat; + u16 iBlock; + u16 startBlock; + u16 prevBlock; + u16 count; + + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + fat = __CARDGetFatBlock(card); + if (fat[3] < cBlock) { + return CARD_RESULT_INSSPACE; + } + + fat[3] -= cBlock; + startBlock = 0xFFFF; + iBlock = fat[4]; + count = 0; + while (0 < cBlock) { + if (card->cBlock - 5 < ++count) { + return CARD_RESULT_BROKEN; + } + + iBlock++; + if (!CARDIsValidBlockNo(card, iBlock)) { + iBlock = 5; + } + + if (fat[iBlock] == 0x0000u) { + if (startBlock == 0xFFFF) { + startBlock = iBlock; + } + else { + fat[prevBlock] = iBlock; + } + prevBlock = iBlock; + fat[iBlock] = 0xFFFF; + --cBlock; + } + } + fat[4] = iBlock; + card->startBlock = startBlock; + + return __CARDUpdateFatBlock(chan, fat, callback); +} + +s32 __CARDFreeBlock(s32 chan, u16 nBlock, CARDCallback callback) +{ + CARDControl *card; + u16 *fat; + u16 nextBlock; + + card = card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + fat = __CARDGetFatBlock(card); + while (nBlock != 0xFFFF) { + if (!CARDIsValidBlockNo(card, nBlock)) { + return CARD_RESULT_BROKEN; + } + + nextBlock = fat[nBlock]; + fat[nBlock] = 0; + nBlock = nextBlock; + ++fat[3]; + } + + return __CARDUpdateFatBlock(chan, fat, callback); +} + +s32 __CARDUpdateFatBlock(s32 chan, u16 *fat, CARDCallback callback) +{ + CARDControl *card; + + card = &__CARDBlock[chan]; + ++fat[2]; + __CARDCheckSum(fat + 2, 0x1FFC, fat, fat + 1); + DCStoreRange(fat, 0x2000); + card->eraseCallback = callback; + + return __CARDEraseSector(chan, (((u32)fat - (u32)card->workArea) / 8192u) * card->sectorSize, EraseCallback); +} diff --git a/src/dolphin/card/CARDCheck.c b/src/dolphin/card/CARDCheck.c new file mode 100644 index 00000000..988e16b3 --- /dev/null +++ b/src/dolphin/card/CARDCheck.c @@ -0,0 +1,343 @@ +#include +#include +#include +#include + +#include +#include + +#include "string.h" + +void __CARDCheckSum(void *ptr, int length, u16 *checksum, u16 *checksumInv) +{ + u16 *p; + int i; + + length /= sizeof(u16); + *checksum = *checksumInv = 0; + for (i = 0, p = ptr; i < length; i++, p++) { + *checksum += *p; + *checksumInv += ~*p; + } + if (*checksum == 0xffff) { + *checksum = 0; + } + if (*checksumInv == 0xffff) { + *checksumInv = 0; + } +} + +static s32 VerifyID(CARDControl *card) +{ + CARDID *id; + u16 checksum; + u16 checksumInv; + OSSramEx *sramEx; + OSTime rand; + int i; + + id = card->workArea; + + if (id->deviceID != 0 || id->size != card->size) + return CARD_RESULT_BROKEN; + + __CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &checksum, &checksumInv); + if (id->checkSum != checksum || id->checkSumInv != checksumInv) + return CARD_RESULT_BROKEN; + + if (id->encode != OSGetFontEncode()) + return CARD_RESULT_ENCODING; + + rand = *(OSTime *)&id->serial[12]; + sramEx = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + rand = (rand * 1103515245 + 12345) >> 16; + if (id->serial[i] != (u8)(sramEx->flashID[card - __CARDBlock][i] + rand)) { + __OSUnlockSramEx(FALSE); + return CARD_RESULT_BROKEN; + } + rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF; + } + + __OSUnlockSramEx(FALSE); + + return CARD_RESULT_READY; +} + +static s32 VerifyDir(CARDControl *card, int *outCurrent) +{ + CARDDir *dir[2]; + CARDDirCheck *check[2]; + u16 checkSum; + u16 checkSumInv; + int i; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + dir[i] = (CARDDir *)((u8 *)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE); + check[i] = __CARDGetDirCheck(dir[i]); + __CARDCheckSum(dir[i], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (check[i]->checkSum != checkSum || check[i]->checkSumInv != checkSumInv) { + ++errors; + current = i; + card->currentDir = 0; + } + } + + if (0 == errors) { + if (card->currentDir == 0) { + if ((check[0]->checkCode - check[1]->checkCode) < 0) { + current = 0; + } + else { + current = 1; + } + card->currentDir = dir[current]; + memcpy(dir[current], dir[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } + else { + current = (card->currentDir == dir[0]) ? 0 : 1; + } + } + if (outCurrent) { + *outCurrent = current; + } + return errors; +} + +static s32 VerifyFAT(CARDControl *card, int *outCurrent) +{ + u16 *fat[2]; + u16 *fatp; + u16 nBlock; + u16 cFree; + int i; + u16 checkSum; + u16 checkSumInv; + int errors; + int current; + + current = errors = 0; + for (i = 0; i < 2; i++) { + fatp = fat[i] = (u16 *)((u8 *)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE); + + __CARDCheckSum(&fatp[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &checkSum, &checkSumInv); + if (fatp[CARD_FAT_CHECKSUM] != checkSum || fatp[CARD_FAT_CHECKSUMINV] != checkSumInv) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + + cFree = 0; + for (nBlock = CARD_NUM_SYSTEM_BLOCK; nBlock < card->cBlock; nBlock++) { + if (fatp[nBlock] == CARD_FAT_AVAIL) { + cFree++; + } + } + if (cFree != fatp[CARD_FAT_FREEBLOCKS]) { + ++errors; + current = i; + card->currentFat = 0; + continue; + } + } + + if (0 == errors) { + if (card->currentFat == 0) { + if (((s16)fat[0][CARD_FAT_CHECKCODE] - (s16)fat[1][CARD_FAT_CHECKCODE]) < 0) { + current = 0; + } + else { + current = 1; + } + card->currentFat = fat[current]; + memcpy(fat[current], fat[current ^ 1], CARD_SYSTEM_BLOCK_SIZE); + } + else { + current = (card->currentFat == fat[0]) ? 0 : 1; + } + } + if (outCurrent) { + *outCurrent = current; + } + return errors; +} + +s32 __CARDVerify(CARDControl *card) +{ + s32 result; + int errors; + + result = VerifyID(card); + if (result < 0) { + return result; + } + + errors = VerifyDir(card, NULL); + errors += VerifyFAT(card, NULL); + switch (errors) { + case 0: + return CARD_RESULT_READY; + case 1: + return CARD_RESULT_BROKEN; + default: + return CARD_RESULT_BROKEN; + } +} + +s32 CARDCheckExAsync(s32 chan, s32 *xferBytes, CARDCallback callback) +{ + CARDControl *card; + CARDDir *dir[2]; + u16 *fat[2]; + u16 *map; + s32 result; + int errors; + int currentFat; + int currentDir; + s32 fileNo; + u16 iBlock; + u16 cBlock; + u16 cFree; + BOOL updateFat = FALSE; + BOOL updateDir = FALSE; + BOOL updateOrphan = FALSE; + + if (xferBytes) { + *xferBytes = 0; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + result = VerifyID(card); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + errors = VerifyDir(card, ¤tDir); + errors += VerifyFAT(card, ¤tFat); + if (1 < errors) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + + dir[0] = (CARDDir *)((u8 *)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE); + dir[1] = (CARDDir *)((u8 *)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE); + fat[0] = (u16 *)((u8 *)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE); + fat[1] = (u16 *)((u8 *)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE); + + switch (errors) { + case 0: + break; + case 1: + if (!card->currentDir) { + card->currentDir = dir[currentDir]; + memcpy(dir[currentDir], dir[currentDir ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateDir = TRUE; + } + else { + card->currentFat = fat[currentFat]; + memcpy(fat[currentFat], fat[currentFat ^ 1], CARD_SYSTEM_BLOCK_SIZE); + updateFat = TRUE; + } + break; + } + + map = fat[currentFat ^ 1]; + memset(map, 0, CARD_SYSTEM_BLOCK_SIZE); + + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + CARDDir *ent; + + ent = &card->currentDir[fileNo]; + if (ent->gameName[0] == 0xff) { + continue; + } + + for (iBlock = ent->startBlock, cBlock = 0; iBlock != 0xFFFF && cBlock < ent->length; iBlock = card->currentFat[iBlock], ++cBlock) { + if (!CARDIsValidBlockNo(card, iBlock) || 1 < ++map[iBlock]) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cBlock != ent->length || iBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + cFree = 0; + for (iBlock = CARD_NUM_SYSTEM_BLOCK; iBlock < card->cBlock; iBlock++) { + u16 nextBlock; + + nextBlock = card->currentFat[iBlock]; + if (map[iBlock] == 0) { + if (nextBlock != CARD_FAT_AVAIL) { + card->currentFat[iBlock] = CARD_FAT_AVAIL; + updateOrphan = TRUE; + } + cFree++; + } + else if (!CARDIsValidBlockNo(card, nextBlock) && nextBlock != 0xFFFF) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + if (cFree != card->currentFat[CARD_FAT_FREEBLOCKS]) { + card->currentFat[CARD_FAT_FREEBLOCKS] = cFree; + updateOrphan = TRUE; + } + if (updateOrphan) { + __CARDCheckSum(&card->currentFat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &card->currentFat[CARD_FAT_CHECKSUM], + &card->currentFat[CARD_FAT_CHECKSUMINV]); + } + + memcpy(fat[currentFat ^ 1], fat[currentFat], CARD_SYSTEM_BLOCK_SIZE); + + if (updateDir) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateDir(chan, callback); + } + + if (updateFat | updateOrphan) { + if (xferBytes) { + *xferBytes = CARD_SYSTEM_BLOCK_SIZE; + } + return __CARDUpdateFatBlock(chan, card->currentFat, callback); + } + + __CARDPutControlBlock(card, CARD_RESULT_READY); + if (callback) { + BOOL enabled = OSDisableInterrupts(); + callback(chan, CARD_RESULT_READY); + OSRestoreInterrupts(enabled); + } + return CARD_RESULT_READY; +} + +s32 CARDCheckAsync(s32 chan, CARDCallback callback) +{ + s32 xferBytes; + + return CARDCheckExAsync(chan, &xferBytes, callback); +} + +s32 CARDCheck(s32 chan) +{ + s32 xferBytes; + + s32 result = CARDCheckExAsync(chan, &xferBytes, __CARDSyncCallback); + if (result >= 0) { + if (&xferBytes == NULL) { + return result; + } + + return __CARDSync(chan); + } + + return result; +} diff --git a/src/dolphin/card/CARDCreate.c b/src/dolphin/card/CARDCreate.c new file mode 100644 index 00000000..ac91d727 --- /dev/null +++ b/src/dolphin/card/CARDCreate.c @@ -0,0 +1,126 @@ +#include +#include +#include +#include + +#include + +static void CreateCallbackFat(s32 chan, s32 result) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = 0; + if (result < 0) { + goto error; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[card->freeNo]; + memcpy(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)); + memcpy(ent->company, card->diskID->company, sizeof(ent->company)); + ent->permission = CARD_ATTR_PUBLIC; + ent->copyTimes = 0; + ent->startBlock = card->startBlock; + + ent->bannerFormat = 0; + ent->iconAddr = 0xffffffff; + ent->iconFormat = 0; + ent->iconSpeed = 0; + ent->commentAddr = 0xffffffff; + + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + + card->fileInfo->offset = 0; + card->fileInfo->iBlock = ent->startBlock; + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + goto error; + } + return; + +error: + __CARDPutControlBlock(card, result); + if (callback) { + callback(chan, result); + } +} + +s32 CARDCreateAsync(s32 chan, const char *fileName, u32 size, CARDFileInfo *fileInfo, CARDCallback callback) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + u16 fileNo; + u16 freeNo; + u16 *fat; + + if (strlen(fileName) > (u32)CARD_FILENAME_MAX) { + return CARD_RESULT_NAMETOOLONG; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + if (size <= 0 || (size % card->sectorSize) != 0) { + return CARD_RESULT_FATAL_ERROR; + } + + freeNo = (u16)-1; + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->gameName[0] == 0xff) { + if (freeNo == (u16)-1) { + freeNo = fileNo; + } + } + else if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) == 0 + && memcmp(ent->company, card->diskID->company, sizeof(ent->company)) == 0 && __CARDCompareFileName(ent, fileName)) { + return __CARDPutControlBlock(card, CARD_RESULT_EXIST); + } + } + if (freeNo == (u16)-1) { + return __CARDPutControlBlock(card, CARD_RESULT_NOENT); + } + + fat = __CARDGetFatBlock(card); + if (card->sectorSize * fat[CARD_FAT_FREEBLOCKS] < size) { + return __CARDPutControlBlock(card, CARD_RESULT_INSSPACE); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + card->freeNo = freeNo; + ent = &dir[freeNo]; + ent->length = (u16)(size / card->sectorSize); + strcat(ent->fileName, fileName, CARD_FILENAME_MAX); + + card->fileInfo = fileInfo; + fileInfo->chan = chan; + fileInfo->fileNo = freeNo; + + result = __CARDAllocBlock(chan, size / card->sectorSize, CreateCallbackFat); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDCreate(s32 chan, const char *fileName, u32 size, CARDFileInfo *fileInfo) +{ + s32 result = CARDCreateAsync(chan, fileName, size, fileInfo, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDDelete.c b/src/dolphin/card/CARDDelete.c new file mode 100644 index 00000000..8b531738 --- /dev/null +++ b/src/dolphin/card/CARDDelete.c @@ -0,0 +1,111 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +static void DeleteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + callback = card->apiCallback; + card->apiCallback = 0; + + if (result < 0) { + goto error; + } + + result = __CARDFreeBlock(chan, card->startBlock, callback); + if (result < 0) { + goto error; + } + return; + +error: + __CARDPutControlBlock(card, result); + if (callback) { + callback(chan, result); + } +} + +s32 CARDFastDeleteAsync(s32 chan, s32 fileNo, CARDCallback callback) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo) { + return CARD_RESULT_FATAL_ERROR; + } + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + if (__CARDIsOpened(card, fileNo)) { + return __CARDPutControlBlock(card, CARD_RESULT_BUSY); + } + card->startBlock = ent->startBlock; + memset(ent, 0xff, sizeof(CARDDir)); + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDUpdateDir(chan, DeleteCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDDeleteAsync(s32 chan, const char *fileName, CARDCallback callback) +{ + CARDControl *card; + s32 fileNo; + s32 result; + CARDDir *dir; + CARDDir *ent; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + result = __CARDGetFileNo(card, fileName, &fileNo); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + if (__CARDIsOpened(card, fileNo)) { + return __CARDPutControlBlock(card, CARD_RESULT_BUSY); + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + card->startBlock = ent->startBlock; + memset(ent, 0xff, sizeof(CARDDir)); + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + result = __CARDUpdateDir(chan, DeleteCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDDelete(s32 chan, const char *fileName) +{ + s32 result = CARDDeleteAsync(chan, fileName, __CARDSyncCallback); + + if (result < 0) + return result; + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDDir.c b/src/dolphin/card/CARDDir.c new file mode 100644 index 00000000..97844a6e --- /dev/null +++ b/src/dolphin/card/CARDDir.c @@ -0,0 +1,101 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +CARDDir *__CARDGetDirBlock(CARDControl *card) +{ + return card->currentDir; +} + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (0 <= result) { + CARDDir *dir0 = (CARDDir *)((u8 *)card->workArea + 0x2000); + CARDDir *dir1 = (CARDDir *)((u8 *)card->workArea + 0x4000); + + if (card->currentDir == dir0) { + card->currentDir = dir1; + memcpy(dir1, dir0, 0x2000); + } + else { + card->currentDir = dir0; + memcpy(dir0, dir1, 0x2000); + } + } + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + CARDDir *dir; + u32 tmp[2]; + u32 addr; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + dir = __CARDGetDirBlock(card); + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + result = __CARDWrite(chan, addr, 0x2000, dir, WriteCallback); + if (result < 0) { + goto error; + } + + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->eraseCallback; + if (callback) { + card->eraseCallback = 0; + callback(chan, result); + } +} + +s32 __CARDUpdateDir(s32 chan, CARDCallback callback) +{ + CARDControl *card; + CARDDirCheck *check; + u32 tmp[2]; + u32 addr; + CARDDir *dir; + + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + dir = __CARDGetDirBlock(card); + check = __CARDGetDirCheck(dir); + ++check->checkCode; + __CARDCheckSum(dir, 0x2000 - sizeof(u32), &check->checkSum, &check->checkSumInv); + DCStoreRange(dir, 0x2000); + + card->eraseCallback = callback; + addr = ((u32)dir - (u32)card->workArea) / 0x2000 * card->sectorSize; + return __CARDEraseSector(chan, addr, EraseCallback); +} diff --git a/src/dolphin/card/CARDFormat.c b/src/dolphin/card/CARDFormat.c new file mode 100644 index 00000000..b2c91930 --- /dev/null +++ b/src/dolphin/card/CARDFormat.c @@ -0,0 +1,141 @@ +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "string.h" + +static void FormatCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + ++card->formatStep; + if (card->formatStep < CARD_NUM_SYSTEM_BLOCK) { + result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback); + if (0 <= result) { + return; + } + } + else if (card->formatStep < 2 * CARD_NUM_SYSTEM_BLOCK) { + int step = card->formatStep - CARD_NUM_SYSTEM_BLOCK; + result = __CARDWrite( + chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE, (u8 *)card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), FormatCallback); + if (result >= 0) { + return; + } + } + else { + card->currentDir = (CARDDir *)((u8 *)card->workArea + (1 + 0) * CARD_SYSTEM_BLOCK_SIZE); + memcpy(card->currentDir, (u8 *)card->workArea + (1 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE); + card->currentFat = (u16 *)((u8 *)card->workArea + (3 + 0) * CARD_SYSTEM_BLOCK_SIZE); + memcpy(card->currentFat, (u8 *)card->workArea + (3 + 1) * CARD_SYSTEM_BLOCK_SIZE, CARD_SYSTEM_BLOCK_SIZE); + } + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 __CARDFormatRegionAsync(s32 chan, u16 encode, CARDCallback callback) +{ + CARDControl *card; + CARDID *id; + CARDDir *dir; + u16 *fat; + s16 i; + s32 result; + OSSram *sram; + OSSramEx *sramEx; + u16 viDTVStatus; + OSTime time; + OSTime rand; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + id = (CARDID *)card->workArea; + memset(id, 0xff, CARD_SYSTEM_BLOCK_SIZE); + viDTVStatus = __VIRegs[55]; + + id->encode = encode; + + sram = __OSLockSram(); + *(u32 *)&id->serial[20] = sram->counterBias; + *(u32 *)&id->serial[24] = sram->language; + __OSUnlockSram(FALSE); + + rand = time = OSGetTime(); + + sramEx = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + rand = (rand * 1103515245 + 12345) >> 16; + id->serial[i] = (u8)(sramEx->flashID[chan][i] + rand); + rand = ((rand * 1103515245 + 12345) >> 16) & 0x7FFF; + } + __OSUnlockSramEx(FALSE); + + *(u32 *)&id->serial[28] = viDTVStatus; + *(OSTime *)&id->serial[12] = time; + + id->deviceID = 0; + id->size = card->size; + __CARDCheckSum(id, sizeof(CARDID) - sizeof(u32), &id->checkSum, &id->checkSumInv); + + for (i = 0; i < 2; i++) { + CARDDirCheck *check; + + dir = (CARDDir *)((u8 *)card->workArea + (1 + i) * CARD_SYSTEM_BLOCK_SIZE); + memset(dir, 0xff, CARD_SYSTEM_BLOCK_SIZE); + check = __CARDGetDirCheck(dir); + check->checkCode = i; + __CARDCheckSum(dir, CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &check->checkSum, &check->checkSumInv); + } + for (i = 0; i < 2; i++) { + fat = (u16 *)((u8 *)card->workArea + (3 + i) * CARD_SYSTEM_BLOCK_SIZE); + memset(fat, 0x00, CARD_SYSTEM_BLOCK_SIZE); + fat[CARD_FAT_CHECKCODE] = (u16)i; + fat[CARD_FAT_FREEBLOCKS] = (u16)(card->cBlock - CARD_NUM_SYSTEM_BLOCK); + fat[CARD_FAT_LASTSLOT] = CARD_NUM_SYSTEM_BLOCK - 1; + __CARDCheckSum(&fat[CARD_FAT_CHECKCODE], CARD_SYSTEM_BLOCK_SIZE - sizeof(u32), &fat[CARD_FAT_CHECKSUM], &fat[CARD_FAT_CHECKSUMINV]); + } + + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + DCStoreRange(card->workArea, CARD_WORKAREA_SIZE); + + card->formatStep = 0; + result = __CARDEraseSector(chan, (u32)card->sectorSize * card->formatStep, FormatCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDFormatAsync(s32 chan, CARDCallback callback) +{ + return __CARDFormatRegionAsync(chan, __CARDGetFontEncode(), callback); +} + +s32 CARDFormat(s32 chan) +{ + s32 result = __CARDFormatRegionAsync(chan, OSGetFontEncode(), __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDMount.c b/src/dolphin/card/CARDMount.c new file mode 100644 index 00000000..f8e75c49 --- /dev/null +++ b/src/dolphin/card/CARDMount.c @@ -0,0 +1,396 @@ +#include +#include +#include +#include +#include + +#include +#include + +u8 GameChoice : (OS_BASE_CACHED | 0x000030E3); + +static u32 SectorSizeTable[8] = { + 8 * 1024, + 16 * 1024, + 32 * 1024, + 64 * 1024, + 128 * 1024, + 256 * 1024, + 0, + 0, +}; + +static u32 LatencyTable[8] = { + 4, + 8, + 16, + 32, + 64, + 128, + 256, + 512, +}; + +void __CARDMountCallback(s32 chan, s32 result); +static void DoUnmount(s32 chan, s32 result); + +static BOOL IsCard(u32 id) +{ + u32 size; + s32 sectorSize; + if (id & (0xFFFF0000) && (id != 0x80000004 || __CARDVendorID == 0xFFFF)) { + return FALSE; + } + + if ((id & 3) != 0) { + return FALSE; + } + + size = id & 0xfc; + switch (size) { + case 4: + case 8: + case 16: + case 32: + case 64: + case 128: + break; + default: + return FALSE; + break; + } + + sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + if (sectorSize == 0) { + return FALSE; + } + + if ((size * 1024 * 1024 / 8) / sectorSize < 8) { + return FALSE; + } + + return TRUE; +} + +s32 CARDProbeEx(s32 chan, s32 *memSize, s32 *sectorSize) +{ + u32 id; + CARDControl *card; + BOOL enabled; + s32 result; + int probe; + + if (chan < 0 || 2 <= chan) { + return CARD_RESULT_FATAL_ERROR; + } + + if (GameChoice & 0x80) { + return CARD_RESULT_NOCARD; + } + + card = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + + probe = EXIProbeEx(chan); + if (probe == -1) { + result = CARD_RESULT_NOCARD; + } + else if (probe == 0) { + result = CARD_RESULT_BUSY; + } + else if (card->attached) { + if (card->mountStep < 1) { + result = CARD_RESULT_BUSY; + } + else { + if (memSize) { + *memSize = card->size; + } + if (sectorSize) { + *sectorSize = card->sectorSize; + } + result = CARD_RESULT_READY; + } + } + else if ((EXIGetState(chan) & 8)) { + result = CARD_RESULT_WRONGDEVICE; + } + else if (!EXIGetID(chan, 0, &id)) { + result = CARD_RESULT_BUSY; + } + else if (IsCard(id)) { + if (memSize) { + *memSize = (s32)(id & 0xfc); + } + if (sectorSize) { + *sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + } + result = CARD_RESULT_READY; + } + else { + result = CARD_RESULT_WRONGDEVICE; + } + + OSRestoreInterrupts(enabled); + return result; +} + +static s32 DoMount(s32 chan) +{ + CARDControl *card; + u32 id; + u8 status; + s32 result; + OSSramEx *sram; + int i; + u8 checkSum; + int step; + + card = &__CARDBlock[chan]; + + if (card->mountStep == 0) { + if (EXIGetID(chan, 0, &id) == 0) { + result = CARD_RESULT_NOCARD; + } + else if (IsCard(id)) { + result = CARD_RESULT_READY; + } + else { + result = CARD_RESULT_WRONGDEVICE; + } + if (result < 0) { + goto error; + } + + card->cid = id; + + card->size = (u16)(id & 0xFC); + card->sectorSize = SectorSizeTable[(id & 0x00003800) >> 11]; + card->cBlock = (u16)((card->size * 1024 * 1024 / 8) / card->sectorSize); + card->latency = LatencyTable[(id & 0x00000700) >> 8]; + + result = __CARDClearStatus(chan); + if (result < 0) { + goto error; + } + result = __CARDReadStatus(chan, &status); + if (result < 0) { + goto error; + } + + if (!EXIProbe(chan)) { + result = CARD_RESULT_NOCARD; + goto error; + } + + if (!(status & 0x40)) { + result = __CARDUnlock(chan, card->id); + if (result < 0) { + goto error; + } + + checkSum = 0; + sram = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + sram->flashID[chan][i] = card->id[i]; + checkSum += card->id[i]; + } + sram->flashIDCheckSum[chan] = (u8)~checkSum; + __OSUnlockSramEx(TRUE); + + return result; + } + else { + card->mountStep = 1; + + checkSum = 0; + sram = __OSLockSramEx(); + for (i = 0; i < 12; i++) { + checkSum += sram->flashID[chan][i]; + } + __OSUnlockSramEx(FALSE); + if (sram->flashIDCheckSum[chan] != (u8)~checkSum) { + result = CARD_RESULT_IOERROR; + goto error; + } + } + } + + if (card->mountStep == 1) { + if (card->cid == 0x80000004) { + u16 vendorID; + + sram = __OSLockSramEx(); + vendorID = *(u16 *)sram->flashID[chan]; + __OSUnlockSramEx(FALSE); + + if (__CARDVendorID == 0xffff || vendorID != __CARDVendorID) { + result = CARD_RESULT_WRONGDEVICE; + goto error; + } + } + + card->mountStep = 2; + + result = __CARDEnableInterrupt(chan, TRUE); + if (result < 0) { + goto error; + } + + EXISetExiCallback(chan, __CARDExiHandler); + EXIUnlock(chan); + DCInvalidateRange(card->workArea, CARD_WORKAREA_SIZE); + } + + step = card->mountStep - 2; + result = __CARDRead( + chan, (u32)card->sectorSize * step, CARD_SYSTEM_BLOCK_SIZE, (u8 *)card->workArea + (CARD_SYSTEM_BLOCK_SIZE * step), __CARDMountCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; + +error: + EXIUnlock(chan); + DoUnmount(chan, result); + return result; +} + +void __CARDMountCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + + switch (result) { + case CARD_RESULT_READY: + if (++card->mountStep < CARD_MAX_MOUNT_STEP) { + result = DoMount(chan); + if (0 <= result) { + return; + } + } + else { + result = __CARDVerify(card); + } + break; + case CARD_RESULT_UNLOCKED: + card->unlockCallback = __CARDMountCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + return; + } + card->unlockCallback = 0; + + result = DoMount(chan); + if (0 <= result) { + return; + } + break; + case CARD_RESULT_IOERROR: + case CARD_RESULT_NOCARD: + DoUnmount(chan, result); + break; + } + + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDMountAsync(s32 chan, void *workArea, CARDCallback detachCallback, CARDCallback attachCallback) +{ + CARDControl *card; + BOOL enabled; + + if (chan < 0 || 2 <= chan) { + return CARD_RESULT_FATAL_ERROR; + } + if (GameChoice & 0x80) { + return CARD_RESULT_NOCARD; + } + card = &__CARDBlock[chan]; + + enabled = OSDisableInterrupts(); + if (card->result == CARD_RESULT_BUSY) { + OSRestoreInterrupts(enabled); + return CARD_RESULT_BUSY; + } + + if (!card->attached && (EXIGetState(chan) & 0x08)) { + OSRestoreInterrupts(enabled); + return CARD_RESULT_WRONGDEVICE; + } + + card->result = CARD_RESULT_BUSY; + card->workArea = workArea; + card->extCallback = detachCallback; + card->apiCallback = attachCallback ? attachCallback : __CARDDefaultApiCallback; + card->exiCallback = 0; + + if (!card->attached && !EXIAttach(chan, __CARDExtHandler)) { + card->result = CARD_RESULT_NOCARD; + OSRestoreInterrupts(enabled); + return CARD_RESULT_NOCARD; + } + + card->mountStep = 0; + card->attached = TRUE; + EXISetExiCallback(chan, 0); + OSCancelAlarm(&card->alarm); + + card->currentDir = 0; + card->currentFat = 0; + + OSRestoreInterrupts(enabled); + + card->unlockCallback = __CARDMountCallback; + if (!EXILock(chan, 0, __CARDUnlockedHandler)) { + return CARD_RESULT_READY; + } + card->unlockCallback = 0; + + return DoMount(chan); +} + +s32 CARDMount(s32 chan, void *workArea, CARDCallback attachCb) +{ + s32 result = CARDMountAsync(chan, workArea, attachCb, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} + +static void DoUnmount(s32 chan, s32 result) +{ + CARDControl *card; + BOOL enabled; + + card = &__CARDBlock[chan]; + enabled = OSDisableInterrupts(); + if (card->attached) { + EXISetExiCallback(chan, 0); + EXIDetach(chan); + OSCancelAlarm(&card->alarm); + card->attached = FALSE; + card->result = result; + card->mountStep = 0; + } + OSRestoreInterrupts(enabled); +} + +s32 CARDUnmount(s32 chan) +{ + CARDControl *card; + s32 result; + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + DoUnmount(chan, CARD_RESULT_NOCARD); + return CARD_RESULT_READY; +} diff --git a/src/dolphin/card/CARDNet.c b/src/dolphin/card/CARDNet.c new file mode 100644 index 00000000..24ab484f --- /dev/null +++ b/src/dolphin/card/CARDNet.c @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +#include + +u16 __CARDVendorID = 0xffff; + +s32 CARDGetSerialNo(s32 chan, u64 *serialNo) +{ + CARDControl *card; + CARDID *id; + int i; + u64 code; + s32 result; + + if (!(0 <= chan && chan < 2)) { + return CARD_RESULT_FATAL_ERROR; + } + + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + id = (CARDID *)card->workArea; + for (code = 0, i = 0; i < sizeof(id->serial) / sizeof(u64); ++i) { + code ^= *(u64 *)&id->serial[sizeof(u64) * i]; + } + *serialNo = code; + + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} diff --git a/src/dolphin/card/CARDOpen.c b/src/dolphin/card/CARDOpen.c new file mode 100644 index 00000000..929982a0 --- /dev/null +++ b/src/dolphin/card/CARDOpen.c @@ -0,0 +1,134 @@ +#include +#include +#include +#include + +#include + +BOOL __CARDCompareFileName(CARDDir *ent, const char *fileName) +{ + char *entName; + char c1; + char c2; + int n; + + entName = (char *)ent->fileName; + n = CARD_FILENAME_MAX; + while (0 <= --n) { + if ((c1 = *entName++) != (c2 = *fileName++)) { + return FALSE; + } + else if (c2 == '\0') { + return TRUE; + } + } + + if (*fileName == '\0') { + return TRUE; + } + + return FALSE; +} + +s32 __CARDAccess(CARDControl *card, CARDDir *ent) +{ + if (ent->gameName[0] == 0xFF) { + return CARD_RESULT_NOFILE; + } + + if (card->diskID == &__CARDDiskNone + || (memcmp(ent->gameName, card->diskID->gameName, 4) == 0 && memcmp(ent->company, card->diskID->company, 2) == 0)) { + return CARD_RESULT_READY; + } + + return CARD_RESULT_NOPERM; +} + +BOOL __CARDIsPublic(CARDDir *ent) +{ + if (ent->gameName[0] == 0xFF) { + return CARD_RESULT_NOFILE; + } + + if ((ent->permission & CARD_ATTR_PUBLIC) != 0) { + return CARD_RESULT_READY; + } + + return CARD_RESULT_NOPERM; +} + +s32 __CARDGetFileNo(CARDControl *card, const char *fileName, s32 *pfileNo) +{ + CARDDir *dir; + CARDDir *ent; + s32 fileNo; + s32 result; + + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + continue; + } + if (__CARDCompareFileName(ent, fileName)) { + *pfileNo = fileNo; + return CARD_RESULT_READY; + } + } + + return CARD_RESULT_NOFILE; +} + +s32 CARDOpen(s32 chan, const char *fileName, CARDFileInfo *fileInfo) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + s32 fileNo; + + fileInfo->chan = -1; + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + result = __CARDGetFileNo(card, fileName, &fileNo); + if (0 <= result) { + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + if (!CARDIsValidBlockNo(card, ent->startBlock)) { + result = CARD_RESULT_BROKEN; + } + else { + fileInfo->chan = chan; + fileInfo->fileNo = fileNo; + fileInfo->offset = 0; + fileInfo->iBlock = ent->startBlock; + } + } + return __CARDPutControlBlock(card, result); +} + +s32 CARDClose(CARDFileInfo *fileInfo) +{ + CARDControl *card; + s32 result; + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) { + return result; + } + + fileInfo->chan = -1; + return __CARDPutControlBlock(card, CARD_RESULT_READY); +} + +BOOL __CARDIsOpened(CARDControl *card, s32 fileNo) +{ + return FALSE; +} diff --git a/src/dolphin/card/CARDRdwr.c b/src/dolphin/card/CARDRdwr.c new file mode 100644 index 00000000..3a235891 --- /dev/null +++ b/src/dolphin/card/CARDRdwr.c @@ -0,0 +1,108 @@ +#include +#include +#include +#include + +#include + +static void BlockReadCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + card->xferred += CARD_SEG_SIZE; + + card->addr += CARD_SEG_SIZE; + (u8 *)card->buffer += CARD_SEG_SIZE; + if (--card->repeat <= 0) { + goto error; + } + + result = __CARDReadSegment(chan, BlockReadCallback); + if (result < 0) { + goto error; + } + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->xferCallback; + if (callback) { + card->xferCallback = 0; + callback(chan, result); + } +} + +s32 __CARDRead(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback) +{ + CARDControl *card; + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + card->xferCallback = callback; + card->repeat = (int)(length / CARD_SEG_SIZE); + card->addr = addr; + card->buffer = dst; + + return __CARDReadSegment(chan, BlockReadCallback); +} + +static void BlockWriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + card->xferred += CARD_PAGE_SIZE; + + card->addr += CARD_PAGE_SIZE; + (u8 *)card->buffer += CARD_PAGE_SIZE; + if (--card->repeat <= 0) { + goto error; + } + + result = __CARDWritePage(chan, BlockWriteCallback); + if (result < 0) { + goto error; + } + return; + +error: + if (card->apiCallback == 0) { + __CARDPutControlBlock(card, result); + } + callback = card->xferCallback; + if (callback) { + card->xferCallback = 0; + callback(chan, result); + } +} + +s32 __CARDWrite(s32 chan, u32 addr, s32 length, void *dst, CARDCallback callback) +{ + CARDControl *card; + card = &__CARDBlock[chan]; + if (!card->attached) { + return CARD_RESULT_NOCARD; + } + + card->xferCallback = callback; + card->repeat = (int)(length / CARD_PAGE_SIZE); + card->addr = addr; + card->buffer = dst; + + return __CARDWritePage(chan, BlockWriteCallback); +} diff --git a/src/dolphin/card/CARDRead.c b/src/dolphin/card/CARDRead.c new file mode 100644 index 00000000..4de1d769 --- /dev/null +++ b/src/dolphin/card/CARDRead.c @@ -0,0 +1,149 @@ +#include +#include +#include +#include + +#include + +s32 __CARDSeek(CARDFileInfo *fileInfo, s32 length, s32 offset, CARDControl **pcard) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + u16 *fat; + + result = __CARDGetControlBlock(fileInfo->chan, &card); + if (result < 0) { + return result; + } + + if (!CARDIsValidBlockNo(card, fileInfo->iBlock) || card->cBlock * card->sectorSize <= fileInfo->offset) { + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + if (ent->length * card->sectorSize <= offset || ent->length * card->sectorSize < offset + length) { + return __CARDPutControlBlock(card, CARD_RESULT_LIMIT); + } + + card->fileInfo = fileInfo; + fileInfo->length = length; + if (offset < fileInfo->offset) { + fileInfo->offset = 0; + fileInfo->iBlock = ent->startBlock; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + fat = __CARDGetFatBlock(card); + while (fileInfo->offset < TRUNC(offset, card->sectorSize)) { + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + return __CARDPutControlBlock(card, CARD_RESULT_BROKEN); + } + } + + fileInfo->offset = offset; + + *pcard = card; + return CARD_RESULT_READY; +} + +static void ReadCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u16 *fat; + CARDFileInfo *fileInfo; + s32 length; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + length = (s32)TRUNC(fileInfo->offset + card->sectorSize, card->sectorSize) - fileInfo->offset; + fileInfo->length -= length; + if (fileInfo->length <= 0) { + goto error; + } + + fat = __CARDGetFatBlock(card); + fileInfo->offset += length; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + result = CARD_RESULT_BROKEN; + goto error; + } + + result = __CARDRead(chan, card->sectorSize * (u32)fileInfo->iBlock, (fileInfo->length < card->sectorSize) ? fileInfo->length : card->sectorSize, + card->buffer, ReadCallback); + if (result < 0) { + goto error; + } + + return; + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDReadAsync(CARDFileInfo *fileInfo, void *buf, s32 length, s32 offset, CARDCallback callback) +{ + CARDControl *card; + s32 result; + CARDDir *dir; + CARDDir *ent; + + if (OFFSET(offset, CARD_SEG_SIZE) != 0 || OFFSET(length, CARD_SEG_SIZE) != 0) { + return CARD_RESULT_FATAL_ERROR; + } + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + result = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) { + result = __CARDIsPublic(ent); + } + + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + DCInvalidateRange(buf, (u32)length); + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + + offset = (s32)OFFSET(fileInfo->offset, card->sectorSize); + length = (length < card->sectorSize - offset) ? length : card->sectorSize - offset; + result = __CARDRead(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock + offset, length, buf, ReadCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDRead(CARDFileInfo *fileInfo, void *buf, s32 length, s32 offset) +{ + s32 result = CARDReadAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +} diff --git a/src/dolphin/card/CARDRename.c b/src/dolphin/card/CARDRename.c new file mode 100644 index 00000000..83d1c8a5 --- /dev/null +++ b/src/dolphin/card/CARDRename.c @@ -0,0 +1,70 @@ +#include +#include +#include +#include + +#include + +s32 CARDRenameAsync(s32 chan, const char* old, const char* new, CARDCallback callback) { + CARDControl* card; + CARDDir* dir; + CARDDir* ent; + s32 result; + int fileNo; + int newNo; + int oldNo; + + if (*old == 0xff || *new == 0xff || *old == 0x00 || *new == 0x00) { + return CARD_RESULT_FATAL_ERROR; + } + if (CARD_FILENAME_MAX < (u32)strlen(old) || CARD_FILENAME_MAX < (u32)strlen(new)) { + return CARD_RESULT_NAMETOOLONG; + } + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + newNo = oldNo = -1; + dir = __CARDGetDirBlock(card); + for (fileNo = 0; fileNo < CARD_MAX_FILE; fileNo++) { + ent = &dir[fileNo]; + if (ent->gameName[0] == 0xff) { + continue; + } + + if (memcmp(ent->gameName, card->diskID->gameName, sizeof(ent->gameName)) != 0 || + memcmp(ent->company, card->diskID->company, sizeof(ent->company)) != 0) { + continue; + } + + if (__CARDCompareFileName(ent, old)) { + oldNo = fileNo; + } + if (__CARDCompareFileName(ent, new)) { + newNo = fileNo; + } + } + + if (oldNo == -1) { + return __CARDPutControlBlock(card, CARD_RESULT_NOFILE); + } + if (newNo != -1) { + return __CARDPutControlBlock(card, CARD_RESULT_EXIST); + } + + ent = &dir[oldNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + strncpy((char*)ent->fileName, new, CARD_FILENAME_MAX); + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} diff --git a/src/dolphin/card/CARDStat.c b/src/dolphin/card/CARDStat.c new file mode 100644 index 00000000..e4fbc265 --- /dev/null +++ b/src/dolphin/card/CARDStat.c @@ -0,0 +1,158 @@ +#include +#include +#include +#include + +#include "string.h" + +#include + +static void UpdateIconOffsets(CARDDir *ent, CARDStat *stat) +{ + u32 offset; + BOOL iconTlut; + int i; + + offset = ent->iconAddr; + if (offset == 0xffffffff) { + stat->bannerFormat = 0; + stat->iconFormat = 0; + stat->iconSpeed = 0; + offset = 0; + } + + iconTlut = FALSE; + switch (CARDGetBannerFormat(ent)) { + case CARD_STAT_BANNER_C8: + stat->offsetBanner = offset; + offset += CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT; + stat->offsetBannerTlut = offset; + offset += 2 * 256; + break; + case CARD_STAT_BANNER_RGB5A3: + stat->offsetBanner = offset; + offset += 2 * CARD_BANNER_WIDTH * CARD_BANNER_HEIGHT; + stat->offsetBannerTlut = 0xffffffff; + break; + default: + stat->offsetBanner = 0xffffffff; + stat->offsetBannerTlut = 0xffffffff; + break; + } + for (i = 0; i < CARD_ICON_MAX; ++i) { + switch (CARDGetIconFormat(ent, i)) { + case CARD_STAT_ICON_C8: + stat->offsetIcon[i] = offset; + offset += CARD_ICON_WIDTH * CARD_ICON_HEIGHT; + iconTlut = TRUE; + break; + case CARD_STAT_ICON_RGB5A3: + stat->offsetIcon[i] = offset; + offset += 2 * CARD_ICON_WIDTH * CARD_ICON_HEIGHT; + break; + default: + stat->offsetIcon[i] = 0xffffffff; + break; + } + } + if (iconTlut) { + stat->offsetIconTlut = offset; + offset += 2 * 256; + } + else { + stat->offsetIconTlut = 0xffffffff; + } + stat->offsetData = offset; +} + +s32 CARDGetStatus(s32 chan, s32 fileNo, CARDStat *stat) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo) { + return CARD_RESULT_FATAL_ERROR; + } + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result == CARD_RESULT_NOPERM) { + result = __CARDIsPublic(ent); + } + + if (result >= 0) { + memcpy(stat->gameName, ent->gameName, sizeof(stat->gameName)); + memcpy(stat->company, ent->company, sizeof(stat->company)); + stat->length = (u32)ent->length * card->sectorSize; + memcpy(stat->fileName, ent->fileName, CARD_FILENAME_MAX); + stat->time = ent->time; + + stat->bannerFormat = ent->bannerFormat; + stat->iconAddr = ent->iconAddr; + stat->iconFormat = ent->iconFormat; + stat->iconSpeed = ent->iconSpeed; + stat->commentAddr = ent->commentAddr; + + UpdateIconOffsets(ent, stat); + } + return __CARDPutControlBlock(card, result); +} + +s32 CARDSetStatusAsync(s32 chan, s32 fileNo, CARDStat *stat, CARDCallback callback) +{ + CARDControl *card; + CARDDir *dir; + CARDDir *ent; + s32 result; + + if (fileNo < 0 || CARD_MAX_FILE <= fileNo || (stat->iconAddr != 0xffffffff && CARD_READ_SIZE <= stat->iconAddr) + || (stat->commentAddr != 0xffffffff && CARD_SYSTEM_BLOCK_SIZE - CARD_COMMENT_SIZE < stat->commentAddr % CARD_SYSTEM_BLOCK_SIZE)) { + return CARD_RESULT_FATAL_ERROR; + } + result = __CARDGetControlBlock(chan, &card); + if (result < 0) { + return result; + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + ent->bannerFormat = stat->bannerFormat; + ent->iconAddr = stat->iconAddr; + ent->iconFormat = stat->iconFormat; + ent->iconSpeed = stat->iconSpeed; + ent->commentAddr = stat->commentAddr; + UpdateIconOffsets(ent, stat); + + if (ent->iconAddr == 0xffffffff) { + CARDSetIconSpeed(ent, 0, CARD_STAT_SPEED_FAST); + } + + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + result = __CARDUpdateDir(chan, callback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDSetStatus(s32 chan, s32 fileNo, CARDStat *stat) +{ + s32 result = CARDSetStatusAsync(chan, fileNo, stat, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(chan); +} diff --git a/src/dolphin/card/CARDUnlock.c b/src/dolphin/card/CARDUnlock.c new file mode 100644 index 00000000..55989b97 --- /dev/null +++ b/src/dolphin/card/CARDUnlock.c @@ -0,0 +1,406 @@ +#include +#include +#include +#include +#include + +#include "string.h" + +#include + +static void InitCallback(void *task); +static void DoneCallback(void *task); + +static u8 CardData[] ATTRIBUTE_ALIGN(32) = { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x02, 0xFF, 0x00, 0x21, 0x13, 0x06, 0x12, 0x03, 0x12, 0x04, 0x13, 0x05, 0x00, + 0x92, 0x00, 0xFF, 0x00, 0x88, 0xFF, 0xFF, 0x00, 0x89, 0xFF, 0xFF, 0x00, 0x8A, 0xFF, 0xFF, 0x00, 0x8B, 0xFF, 0xFF, 0x8F, 0x00, 0x02, 0xBF, 0x00, + 0x88, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, 0x00, 0x16, 0xFB, 0x00, 0x01, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x03, 0x80, 0xFF, 0x00, 0x02, + 0x94, 0x00, 0x27, 0x02, 0xBF, 0x00, 0x8E, 0x1F, 0xDF, 0x24, 0xFF, 0x02, 0x40, 0x0F, 0xFF, 0x00, 0x98, 0x04, 0x00, 0x00, 0x9A, 0x00, 0x10, 0x00, + 0x99, 0x00, 0x00, 0x8E, 0x00, 0x02, 0xBF, 0x00, 0x94, 0x02, 0xBF, 0x86, 0x44, 0x02, 0xBF, 0x00, 0x88, 0x16, 0xFC, 0xDC, 0xD1, 0x16, 0xFD, 0x00, + 0x03, 0x16, 0xFB, 0x00, 0x01, 0x8F, 0x00, 0x02, 0xBF, 0x00, 0x8E, 0x03, 0x80, 0xCD, 0xD1, 0x02, 0x94, 0x00, 0x48, 0x27, 0xFF, 0x03, 0x80, 0x00, + 0x01, 0x02, 0x95, 0x00, 0x5A, 0x03, 0x80, 0x00, 0x02, 0x02, 0x95, 0x80, 0x00, 0x02, 0x9F, 0x00, 0x48, 0x00, 0x21, 0x8E, 0x00, 0x02, 0xBF, 0x00, + 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x25, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC5, 0xFF, 0xFF, 0x03, + 0x40, 0x0F, 0xFF, 0x1C, 0x9F, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC7, 0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x00, 0xC6, 0xFF, 0xFF, 0x02, 0xBF, 0x00, + 0x8E, 0x00, 0xC0, 0xFF, 0xFF, 0x02, 0xBF, 0x00, 0x8E, 0x20, 0xFF, 0x03, 0x40, 0x0F, 0xFF, 0x1F, 0x5F, 0x02, 0xBF, 0x00, 0x8E, 0x21, 0xFF, 0x02, + 0xBF, 0x00, 0x8E, 0x23, 0xFF, 0x12, 0x05, 0x12, 0x06, 0x02, 0x9F, 0x80, 0xB5, 0x00, 0x21, 0x27, 0xFC, 0x03, 0xC0, 0x80, 0x00, 0x02, 0x9D, 0x00, + 0x88, 0x02, 0xDF, 0x27, 0xFE, 0x03, 0xC0, 0x80, 0x00, 0x02, 0x9C, 0x00, 0x8E, 0x02, 0xDF, 0x2E, 0xCE, 0x2C, 0xCF, 0x00, 0xF8, 0xFF, 0xCD, 0x00, + 0xF9, 0xFF, 0xC9, 0x00, 0xFA, 0xFF, 0xCB, 0x26, 0xC9, 0x02, 0xC0, 0x00, 0x04, 0x02, 0x9D, 0x00, 0x9C, 0x02, 0xDF, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 }; + +typedef struct DecodeParameters { + u8 *inputAddr; + u32 inputLength; + u32 aramAddr; + u8 *outputAddr; +} DecodeParameters; + +static unsigned long int next = 1; + +static int CARDRand(void) +{ + next = next * 1103515245 + 12345; + return (int)((unsigned int)(next / 65536) % 32768); +} + +static void CARDSrand(unsigned int seed) +{ + next = seed; +} + +static u32 GetInitVal(void) +{ + u32 tmp; + u32 tick; + + tick = OSGetTick(); + CARDSrand(tick); + tmp = 0x7fec8000; + tmp |= CARDRand(); + tmp &= 0xfffff000; + return tmp; +} + +static u32 exnor_1st(u32 data, u32 rshift) +{ + u32 wk; + u32 w; + u32 i; + + w = data; + for (i = 0; i < rshift; i++) { + wk = ~(w ^ (w >> 7) ^ (w >> 15) ^ (w >> 23)); + w = (w >> 1) | ((wk << 30) & 0x40000000); + } + return w; +} + +static u32 exnor(u32 data, u32 lshift) +{ + u32 wk; + u32 w; + u32 i; + + w = data; + for (i = 0; i < lshift; i++) { + // 1bit Left Shift + wk = ~(w ^ (w << 7) ^ (w << 15) ^ (w << 23)); + w = (w << 1) | ((wk >> 30) & 0x00000002); + // printf("i=%d, w=%8x\n", i, w); + } + return w; +} + +static u32 bitrev(u32 data) +{ + u32 wk; + u32 i; + u32 k = 0; + u32 j = 1; + + wk = 0; + for (i = 0; i < 32; i++) { + if (i > 15) { + if (i == 31) { + wk |= (((data & (0x01 << 31)) >> 31) & 0x01); + } + else { + wk |= ((data & (0x01 << i)) >> j); + j += 2; + } + } + else { + wk |= ((data & (0x01 << i)) << (31 - i - k)); + k++; + } + } + return wk; +} + +#define SEC_AD1(x) ((u8)(((x) >> 29) & 0x03)) +#define SEC_AD2(x) ((u8)(((x) >> 21) & 0xff)) +#define SEC_AD3(x) ((u8)(((x) >> 19) & 0x03)) +#define SEC_BA(x) ((u8)(((x) >> 12) & 0x7f)) + +static s32 ReadArrayUnlock(s32 chan, u32 data, void *rbuf, s32 rlen, s32 mode) +{ + CARDControl *card; + BOOL err; + u8 cmd[5]; + + card = &__CARDBlock[chan]; + if (!EXISelect(chan, 0, 4)) { + return CARD_RESULT_NOCARD; + } + + data &= 0xfffff000; + memset(cmd, 0, 5); + cmd[0] = 0x52; + if (mode == 0) { + cmd[1] = SEC_AD1(data); + cmd[2] = SEC_AD2(data); + cmd[3] = SEC_AD3(data); + cmd[4] = SEC_BA(data); + } + else { + cmd[1] = (u8)((data & 0xff000000) >> 24); + cmd[2] = (u8)((data & 0x00ff0000) >> 16); + } + + err = FALSE; + err |= !EXIImmEx(chan, cmd, 5, 1); + err |= !EXIImmEx(chan, (u8 *)card->workArea + (u32)sizeof(CARDID), card->latency, 1); + err |= !EXIImmEx(chan, rbuf, rlen, 0); + err |= !EXIDeselect(chan); + + return err ? CARD_RESULT_NOCARD : CARD_RESULT_READY; +} + +// Calculate Dummy Read Length, 4-32Bytes +static s32 DummyLen(void) +{ + u32 tick; + u32 wk; + s32 tmp; + u32 max; + + wk = 1; + max = 0; + tick = OSGetTick(); + CARDSrand(tick); + + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + while ((tmp < 4) && (max < 10)) { + tick = OSGetTick(); + tmp = (s32)(tick << wk); + wk++; + if (wk > 16) { + wk = 1; + } + CARDSrand((u32)tmp); + tmp = CARDRand(); + tmp &= 0x0000001f; + tmp += 1; + max++; + } + if (tmp < 4) { + tmp = 4; + } + + return tmp; +} + +s32 __CARDUnlock(s32 chan, u8 flashID[12]) +{ + u32 init_val; + u32 data; + + s32 dummy; + s32 rlen; + u32 rshift; + + u8 fsts; + u32 wk, wk1; + u32 Ans1 = 0; + u32 Ans2 = 0; + u32 *dp; + u8 rbuf[64]; + u32 para1A = 0; + u32 para1B = 0; + u32 para2A = 0; + u32 para2B = 0; + + CARDControl *card; + DSPTaskInfo *task; + DecodeParameters *param; + u8 *input; + u8 *output; + + card = &__CARDBlock[chan]; + task = &card->task; + param = (DecodeParameters *)card->workArea; + input = (u8 *)((u8 *)param + sizeof(DecodeParameters)); + input = (u8 *)OSRoundUp32B(input); + output = input + 32; + + fsts = 0; + init_val = GetInitVal(); + + dummy = DummyLen(); + rlen = dummy; + if (ReadArrayUnlock(chan, init_val, rbuf, rlen, 0) < 0) { + return CARD_RESULT_NOCARD; + } + + rshift = (u32)(dummy * 8 + 1); + wk = exnor_1st(init_val, rshift); + wk1 = ~(wk ^ (wk >> 7) ^ (wk >> 15) ^ (wk >> 23)); + card->scramble = (wk | ((wk1 << 31) & 0x80000000)); + card->scramble = bitrev(card->scramble); + dummy = DummyLen(); + rlen = 20 + dummy; + data = 0; + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) { + return CARD_RESULT_NOCARD; + } + dp = (u32 *)rbuf; + para1A = *dp++; + para1B = *dp++; + Ans1 = *dp++; + para2A = *dp++; + para2B = *dp++; + para1A = (para1A ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + para1B = (para1B ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + Ans1 ^= card->scramble; + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + para2A = (para2A ^ card->scramble); + rshift = 32; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + para2B = (para2B ^ card->scramble); + rshift = (u32)(dummy * 8); + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + rshift = 32 + 1; + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + *(u32 *)&input[0] = para2A; + *(u32 *)&input[4] = para2B; + + param->inputAddr = input; + param->inputLength = 8; + param->outputAddr = output; + param->aramAddr = 0; + + DCFlushRange(input, 8); + DCInvalidateRange(output, 4); + DCFlushRange(param, sizeof(DecodeParameters)); + + task->priority = 255; + task->iram_mmem_addr = (u16 *)OSPhysicalToCached(CardData); + task->iram_length = 0x160; + task->iram_addr = 0; + task->dsp_init_vector = 0x10; + task->init_cb = InitCallback; + task->res_cb = NULL; + task->done_cb = DoneCallback; + task->req_cb = NULL; + DSPAddTask(task); + + dp = (u32 *)flashID; + *dp++ = para1A; + *dp++ = para1B; + *dp = Ans1; + + return CARD_RESULT_READY; +} + +static void InitCallback(void *_task) +{ + s32 chan; + CARDControl *card; + DSPTaskInfo *task; + DecodeParameters *param; + + task = _task; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo *)&card->task == task) { + break; + } + } + param = (DecodeParameters *)card->workArea; + + DSPSendMailToDSP(0xff000000); + while (DSPCheckMailToDSP()) + ; + + DSPSendMailToDSP((u32)param); + while (DSPCheckMailToDSP()) + ; +} + +static void DoneCallback(void *_task) +{ + u8 rbuf[64]; + u32 data; + s32 dummy; + s32 rlen; + u32 rshift; + + u8 unk; + u32 wk, wk1; + u32 Ans2; + + s32 chan; + CARDControl *card; + s32 result; + DSPTaskInfo *task; + DecodeParameters *param; + + u8 *input; + u8 *output; + task = _task; + for (chan = 0; chan < 2; ++chan) { + card = &__CARDBlock[chan]; + if ((DSPTaskInfo *)&card->task == task) { + break; + } + } + + param = (DecodeParameters *)card->workArea; + input = (u8 *)((u8 *)param + sizeof(DecodeParameters)); + input = (u8 *)OSRoundUp32B(input); + output = input + 32; + + Ans2 = *(u32 *)output; + dummy = DummyLen(); + rlen = dummy; + data = ((Ans2 ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + + rshift = (u32)((dummy + 4 + card->latency) * 8 + 1); + wk = exnor(card->scramble, rshift); + wk1 = ~(wk ^ (wk << 7) ^ (wk << 15) ^ (wk << 23)); + card->scramble = (wk | ((wk1 >> 31) & 0x00000001)); + + dummy = DummyLen(); + rlen = dummy; + data = (((Ans2 << 16) ^ card->scramble) & 0xffff0000); + if (ReadArrayUnlock(chan, data, rbuf, rlen, 1) < 0) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + result = __CARDReadStatus(chan, &unk); + if (!EXIProbe(chan)) { + EXIUnlock(chan); + __CARDMountCallback(chan, CARD_RESULT_NOCARD); + return; + } + if (result == CARD_RESULT_READY && !(unk & 0x40)) { + EXIUnlock(chan); + result = CARD_RESULT_IOERROR; + } + __CARDMountCallback(chan, result); +} diff --git a/src/dolphin/card/CARDWrite.c b/src/dolphin/card/CARDWrite.c new file mode 100644 index 00000000..ca8aacfb --- /dev/null +++ b/src/dolphin/card/CARDWrite.c @@ -0,0 +1,128 @@ +#include +#include +#include +#include + +#include + +static void EraseCallback(s32 chan, s32 result); + +static void WriteCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + u16 *fat; + CARDDir *dir; + CARDDir *ent; + CARDFileInfo *fileInfo; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fileInfo = card->fileInfo; + if (fileInfo->length < 0) { + result = CARD_RESULT_CANCELED; + goto error; + } + + fileInfo->length -= card->sectorSize; + if (fileInfo->length <= 0) { + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + ent->time = (u32)OSTicksToSeconds(OSGetTime()); + callback = card->apiCallback; + card->apiCallback = 0; + result = __CARDUpdateDir(chan, callback); + } + else { + fat = __CARDGetFatBlock(card); + fileInfo->offset += card->sectorSize; + fileInfo->iBlock = fat[fileInfo->iBlock]; + if (!CARDIsValidBlockNo(card, fileInfo->iBlock)) { + result = CARD_RESULT_BROKEN; + goto error; + } + result = __CARDEraseSector(chan, card->sectorSize * (u32)fileInfo->iBlock, EraseCallback); + } + + if (result < 0) { + goto error; + } + return; + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +static void EraseCallback(s32 chan, s32 result) +{ + CARDControl *card; + CARDCallback callback; + CARDFileInfo *fileInfo; + + card = &__CARDBlock[chan]; + if (result < 0) { + goto error; + } + + fileInfo = card->fileInfo; + result = __CARDWrite(chan, card->sectorSize * (u32)fileInfo->iBlock, card->sectorSize, card->buffer, WriteCallback); + if (result < 0) { + goto error; + } + return; + +error: + callback = card->apiCallback; + card->apiCallback = 0; + __CARDPutControlBlock(card, result); + callback(chan, result); +} + +s32 CARDWriteAsync(CARDFileInfo *fileInfo, const void *buf, s32 length, s32 offset, CARDCallback callback) +{ + CARDControl *card; + s32 result; + CARDDir *dir; + CARDDir *ent; + + result = __CARDSeek(fileInfo, length, offset, &card); + if (result < 0) { + return result; + } + + if (OFFSET(offset, card->sectorSize) != 0 || OFFSET(length, card->sectorSize) != 0) { + return __CARDPutControlBlock(card, CARD_RESULT_FATAL_ERROR); + } + + dir = __CARDGetDirBlock(card); + ent = &dir[fileInfo->fileNo]; + result = __CARDAccess(card, ent); + if (result < 0) { + return __CARDPutControlBlock(card, result); + } + + DCStoreRange((void *)buf, (u32)length); + card->apiCallback = callback ? callback : __CARDDefaultApiCallback; + card->buffer = (void *)buf; + result = __CARDEraseSector(fileInfo->chan, card->sectorSize * (u32)fileInfo->iBlock, EraseCallback); + if (result < 0) { + __CARDPutControlBlock(card, result); + } + return result; +} + +s32 CARDWrite(CARDFileInfo *fileInfo, const void *buf, s32 length, s32 offset) +{ + s32 result = CARDWriteAsync(fileInfo, buf, length, offset, __CARDSyncCallback); + if (result < 0) { + return result; + } + + return __CARDSync(fileInfo->chan); +}