mirror of https://github.com/PrimeDecomp/prime.git
Link nearly all of CARD
This commit is contained in:
parent
28a4b75d39
commit
e3de3f9e5d
|
@ -102,6 +102,8 @@ typedef struct CARDID {
|
||||||
u16 checkSumInv;
|
u16 checkSumInv;
|
||||||
} CARDID;
|
} CARDID;
|
||||||
|
|
||||||
|
void __CARDDefaultApiCallback(s32 chan, s32 result);
|
||||||
|
|
||||||
#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock)
|
#define CARDIsValidBlockNo(card, iBlock) (CARD_NUM_SYSTEM_BLOCK <= (iBlock) && (iBlock) < (card)->cBlock)
|
||||||
#define __CARDGetDirCheck(dir) ((CARDDirCheck*) &(dir)[CARD_MAX_FILE])
|
#define __CARDGetDirCheck(dir) ((CARDDirCheck*) &(dir)[CARD_MAX_FILE])
|
||||||
|
|
||||||
|
@ -110,9 +112,18 @@ u16* __CARDGetFatBlock(CARDControl* card);
|
||||||
s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback);
|
s32 __CARDUpdateFatBlock(s32 chan, u16* fat, CARDCallback callback);
|
||||||
void __CARDCheckSum(void* ptr, int length, u16* checkSum, u16* checkSumInv);
|
void __CARDCheckSum(void* ptr, int length, u16* checkSum, u16* checkSumInv);
|
||||||
u16 __CARDGetFontEncode();
|
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 CARDControl __CARDBlock[2];
|
||||||
extern DVDDiskID __CARDDiskNone;
|
extern DVDDiskID __CARDDiskNone;
|
||||||
|
extern u16 __CARDVendorID;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
|
|
|
@ -27,5 +27,6 @@ typedef struct OSSramEx {
|
||||||
u8 _padding1[2];
|
u8 _padding1[2];
|
||||||
} OSSramEx;
|
} OSSramEx;
|
||||||
|
|
||||||
|
OSSram* __OSLockSram();
|
||||||
OSSramEx* __OSLockSramEx();
|
OSSramEx* __OSLockSramEx();
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -22,6 +22,8 @@ void VISetWindowFullscreen(bool fullscreen);
|
||||||
bool VIGetWindowFullscreen();
|
bool VIGetWindowFullscreen();
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
vu16 __VIRegs[59] : 0xCC002000;
|
||||||
|
|
||||||
#ifdef __cplusplus
|
#ifdef __cplusplus
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
18
obj_files.mk
18
obj_files.mk
|
@ -821,16 +821,16 @@ CARD_FILES :=\
|
||||||
$(BUILD_DIR)/src/Dolphin/card/CARDBlock.ep.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDBlock.ep.o\
|
||||||
$(BUILD_DIR)/src/Dolphin/card/CARDDir.ep.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDDir.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDCheck.o\
|
$(BUILD_DIR)/asm/Dolphin/card/CARDCheck.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDMount.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDMount.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDFormat.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDFormat.ep.o\
|
||||||
$(BUILD_DIR)/src/Dolphin/card/CARDOpen.ep.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDOpen.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDCreate.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDCreate.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDRead.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDRead.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDWrite.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDWrite.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDDelete.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDDelete.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDStat.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDStat.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDRename.o\
|
$(BUILD_DIR)/src/Dolphin/card/CARDRename.ep.o\
|
||||||
$(BUILD_DIR)/asm/Dolphin/card/CARDNet.o
|
$(BUILD_DIR)/src/Dolphin/card/CARDNet.ep.o
|
||||||
|
|
||||||
SI_FILES :=\
|
SI_FILES :=\
|
||||||
$(BUILD_DIR)/asm/Dolphin/si/SIBios.o\
|
$(BUILD_DIR)/asm/Dolphin/si/SIBios.o\
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,121 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
#include <dolphin/OSRtcPriv.h>
|
||||||
|
#include <dolphin/vi.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); }
|
|
@ -0,0 +1,353 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
#include <dolphin/OSRtcPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,34 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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);
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,70 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,142 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,114 @@
|
||||||
|
#include <dolphin/card.h>
|
||||||
|
#include <dolphin/dsp.h>
|
||||||
|
#include <dolphin/dvd.h>
|
||||||
|
#include <dolphin/os.h>
|
||||||
|
|
||||||
|
#include <dolphin/CARDPriv.h>
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
Loading…
Reference in New Issue