Imported dolphin/card
This commit is contained in:
parent
61676fc982
commit
b44fb658a1
18 changed files with 3315 additions and 78 deletions
|
|
@ -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))
|
||||
|
|
|
|||
|
|
@ -39,6 +39,7 @@ struct OSResetFunctionInfo {
|
|||
OSResetFunctionInfo* prev;
|
||||
};
|
||||
|
||||
void OSRegisterResetFunction(OSResetFunctionInfo *info);
|
||||
u32 OSGetResetCode(void);
|
||||
|
||||
#ifdef __cplusplus
|
||||
|
|
|
|||
615
src/dolphin/card/CARDBios.c
Normal file
615
src/dolphin/card/CARDBios.c
Normal file
|
|
@ -0,0 +1,615 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/exi.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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;
|
||||
}
|
||||
170
src/dolphin/card/CARDBlock.c
Normal file
170
src/dolphin/card/CARDBlock.c
Normal file
|
|
@ -0,0 +1,170 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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);
|
||||
}
|
||||
343
src/dolphin/card/CARDCheck.c
Normal file
343
src/dolphin/card/CARDCheck.c
Normal file
|
|
@ -0,0 +1,343 @@
|
|||
#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 "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;
|
||||
}
|
||||
126
src/dolphin/card/CARDCreate.c
Normal file
126
src/dolphin/card/CARDCreate.c
Normal file
|
|
@ -0,0 +1,126 @@
|
|||
#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);
|
||||
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);
|
||||
}
|
||||
111
src/dolphin/card/CARDDelete.c
Normal file
111
src/dolphin/card/CARDDelete.c
Normal file
|
|
@ -0,0 +1,111 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "string.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;
|
||||
}
|
||||
|
||||
s32 CARDDelete(s32 chan, const char *fileName)
|
||||
{
|
||||
s32 result = CARDDeleteAsync(chan, fileName, __CARDSyncCallback);
|
||||
|
||||
if (result < 0)
|
||||
return result;
|
||||
return __CARDSync(chan);
|
||||
}
|
||||
101
src/dolphin/card/CARDDir.c
Normal file
101
src/dolphin/card/CARDDir.c
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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);
|
||||
}
|
||||
141
src/dolphin/card/CARDFormat.c
Normal file
141
src/dolphin/card/CARDFormat.c
Normal file
|
|
@ -0,0 +1,141 @@
|
|||
#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/hw_regs.h>
|
||||
#include <dolphin/vi.h>
|
||||
|
||||
#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);
|
||||
}
|
||||
396
src/dolphin/card/CARDMount.c
Normal file
396
src/dolphin/card/CARDMount.c
Normal file
|
|
@ -0,0 +1,396 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/exi.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);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
34
src/dolphin/card/CARDNet.c
Normal file
34
src/dolphin/card/CARDNet.c
Normal file
|
|
@ -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);
|
||||
}
|
||||
134
src/dolphin/card/CARDOpen.c
Normal file
134
src/dolphin/card/CARDOpen.c
Normal file
|
|
@ -0,0 +1,134 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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;
|
||||
}
|
||||
108
src/dolphin/card/CARDRdwr.c
Normal file
108
src/dolphin/card/CARDRdwr.c
Normal file
|
|
@ -0,0 +1,108 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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);
|
||||
}
|
||||
149
src/dolphin/card/CARDRead.c
Normal file
149
src/dolphin/card/CARDRead.c
Normal file
|
|
@ -0,0 +1,149 @@
|
|||
#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 = __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);
|
||||
}
|
||||
70
src/dolphin/card/CARDRename.c
Normal file
70
src/dolphin/card/CARDRename.c
Normal file
|
|
@ -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;
|
||||
}
|
||||
158
src/dolphin/card/CARDStat.c
Normal file
158
src/dolphin/card/CARDStat.c
Normal file
|
|
@ -0,0 +1,158 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "string.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 = __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);
|
||||
}
|
||||
406
src/dolphin/card/CARDUnlock.c
Normal file
406
src/dolphin/card/CARDUnlock.c
Normal file
|
|
@ -0,0 +1,406 @@
|
|||
#include <dolphin/card.h>
|
||||
#include <dolphin/dsp.h>
|
||||
#include <dolphin/dvd.h>
|
||||
#include <dolphin/exi.h>
|
||||
#include <dolphin/os.h>
|
||||
|
||||
#include "string.h"
|
||||
|
||||
#include <dolphin/CARDPriv.h>
|
||||
|
||||
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);
|
||||
}
|
||||
128
src/dolphin/card/CARDWrite.c
Normal file
128
src/dolphin/card/CARDWrite.c
Normal file
|
|
@ -0,0 +1,128 @@
|
|||
#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;
|
||||
}
|
||||
|
||||
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);
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue