From fcdeb2170419cd7d8757c23b20b1b4913b7c691e Mon Sep 17 00:00:00 2001 From: Phillip Stephens Date: Sat, 10 Sep 2022 21:54:54 -0700 Subject: [PATCH] Link nearly all of CARD Former-commit-id: e3de3f9e5d76c4a65e44d46e5205e2c57e7c5a50 --- include/dolphin/CARDPriv.h | 11 ++ include/dolphin/OSRtcPriv.h | 1 + include/dolphin/vi.h | 2 + obj_files.mk | 18 +- src/Dolphin/card/CARDCreate.c | 113 +++++++++++ src/Dolphin/card/CARDDelete.c | 97 ++++++++++ src/Dolphin/card/CARDFormat.c | 121 ++++++++++++ src/Dolphin/card/CARDMount.c | 353 ++++++++++++++++++++++++++++++++++ src/Dolphin/card/CARDNet.c | 34 ++++ src/Dolphin/card/CARDRead.c | 136 +++++++++++++ src/Dolphin/card/CARDRename.c | 70 +++++++ src/Dolphin/card/CARDStat.c | 142 ++++++++++++++ src/Dolphin/card/CARDWrite.c | 114 +++++++++++ 13 files changed, 1203 insertions(+), 9 deletions(-) create mode 100644 src/Dolphin/card/CARDCreate.c create mode 100644 src/Dolphin/card/CARDDelete.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/CARDRead.c create mode 100644 src/Dolphin/card/CARDRename.c create mode 100644 src/Dolphin/card/CARDStat.c create mode 100644 src/Dolphin/card/CARDWrite.c diff --git a/include/dolphin/CARDPriv.h b/include/dolphin/CARDPriv.h index a7702cb0..7a4c085e 100644 --- a/include/dolphin/CARDPriv.h +++ b/include/dolphin/CARDPriv.h @@ -102,6 +102,8 @@ typedef struct CARDID { u16 checkSumInv; } CARDID; +void __CARDDefaultApiCallback(s32 chan, s32 result); + #define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock) #define __CARDGetDirCheck(dir) ((CARDDirCheck*) &(dir)[CARD_MAX_FILE]) @@ -110,9 +112,18 @@ 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); + +#define TRUNC(n, a) (((u32) (n)) & ~((a) - 1)) +#define OFFSET(n, a) (((u32) (n)) & ((a) - 1)) extern CARDControl __CARDBlock[2]; extern DVDDiskID __CARDDiskNone; +extern u16 __CARDVendorID; #ifdef __cplusplus } diff --git a/include/dolphin/OSRtcPriv.h b/include/dolphin/OSRtcPriv.h index 71a80a6f..e07e98e4 100644 --- a/include/dolphin/OSRtcPriv.h +++ b/include/dolphin/OSRtcPriv.h @@ -27,5 +27,6 @@ typedef struct OSSramEx { u8 _padding1[2]; } OSSramEx; +OSSram* __OSLockSram(); OSSramEx* __OSLockSramEx(); #endif diff --git a/include/dolphin/vi.h b/include/dolphin/vi.h index e78e5090..db8269c2 100644 --- a/include/dolphin/vi.h +++ b/include/dolphin/vi.h @@ -22,6 +22,8 @@ void VISetWindowFullscreen(bool fullscreen); bool VIGetWindowFullscreen(); #endif +vu16 __VIRegs[59] : 0xCC002000; + #ifdef __cplusplus } #endif diff --git a/obj_files.mk b/obj_files.mk index fbf55506..06662f67 100644 --- a/obj_files.mk +++ b/obj_files.mk @@ -821,16 +821,16 @@ CARD_FILES :=\ $(BUILD_DIR)/src/Dolphin/card/CARDBlock.ep.o\ $(BUILD_DIR)/src/Dolphin/card/CARDDir.ep.o\ $(BUILD_DIR)/asm/Dolphin/card/CARDCheck.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDMount.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDFormat.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDMount.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDFormat.ep.o\ $(BUILD_DIR)/src/Dolphin/card/CARDOpen.ep.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDCreate.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDRead.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDWrite.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDDelete.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDStat.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDRename.o\ - $(BUILD_DIR)/asm/Dolphin/card/CARDNet.o + $(BUILD_DIR)/src/Dolphin/card/CARDCreate.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDRead.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDWrite.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDDelete.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDStat.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDRename.ep.o\ + $(BUILD_DIR)/src/Dolphin/card/CARDNet.ep.o SI_FILES :=\ $(BUILD_DIR)/asm/Dolphin/si/SIBios.o\ diff --git a/src/Dolphin/card/CARDCreate.c b/src/Dolphin/card/CARDCreate.c new file mode 100644 index 00000000..880f3638 --- /dev/null +++ b/src/Dolphin/card/CARDCreate.c @@ -0,0 +1,113 @@ +#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); + strncpy(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; +} diff --git a/src/Dolphin/card/CARDDelete.c b/src/Dolphin/card/CARDDelete.c new file mode 100644 index 00000000..f715751c --- /dev/null +++ b/src/Dolphin/card/CARDDelete.c @@ -0,0 +1,97 @@ +#include +#include +#include +#include + +#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; +} diff --git a/src/Dolphin/card/CARDFormat.c b/src/Dolphin/card/CARDFormat.c new file mode 100644 index 00000000..d9f0b10c --- /dev/null +++ b/src/Dolphin/card/CARDFormat.c @@ -0,0 +1,121 @@ +#include +#include +#include +#include + +#include +#include +#include + +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); } diff --git a/src/Dolphin/card/CARDMount.c b/src/Dolphin/card/CARDMount.c new file mode 100644 index 00000000..e1bd3b6c --- /dev/null +++ b/src/Dolphin/card/CARDMount.c @@ -0,0 +1,353 @@ +#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); +} + +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..b4330a4b --- /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/CARDRead.c b/src/Dolphin/card/CARDRead.c new file mode 100644 index 00000000..df16ef58 --- /dev/null +++ b/src/Dolphin/card/CARDRead.c @@ -0,0 +1,136 @@ +#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 = __CARDIsWritable(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; +} 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..c453a4e8 --- /dev/null +++ b/src/Dolphin/card/CARDStat.c @@ -0,0 +1,142 @@ +#include +#include +#include +#include + +#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 = __CARDIsWritable(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; +} diff --git a/src/Dolphin/card/CARDWrite.c b/src/Dolphin/card/CARDWrite.c new file mode 100644 index 00000000..7b5c7ff5 --- /dev/null +++ b/src/Dolphin/card/CARDWrite.c @@ -0,0 +1,114 @@ +#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; +}