#include <dolphin/DVDPriv.h>
#include <dolphin/dvd.h>
#include <dolphin/dvd_regs.h>
#include <dolphin/os.h>
#include <dolphin/os/OSBootInfo.h>
typedef void (*stateFunc)(DVDCommandBlock* block);
stateFunc LastState;
extern OSThreadQueue __DVDThreadQueue;
static DVDBB2 BB2 ATTRIBUTE_ALIGN(32);
static DVDDiskID CurrDiskID ATTRIBUTE_ALIGN(32);
static DVDCommandBlock* executing;
static DVDDiskID* IDShouldBe;
static OSBootInfo* bootInfo;
static BOOL autoInvalidation = TRUE;
static volatile BOOL PauseFlag = FALSE;
static volatile BOOL PausingFlag = FALSE;
static volatile BOOL AutoFinishing = FALSE;
static volatile BOOL FatalErrorFlag = FALSE;
static vu32 CurrCommand;
static vu32 Canceling = FALSE;
static DVDCBCallback CancelCallback;
static vu32 ResumeFromHere = 0;
static vu32 CancelLastError;
static vu32 LastError;
static vs32 NumInternalRetry = 0;
static volatile BOOL ResetRequired;
static volatile BOOL CancelAllSyncComplete = FALSE;
static volatile BOOL FirstTimeInBootrom = FALSE;
static DVDCommandBlock DummyCommandBlock;
static OSAlarm ResetAlarm;
static BOOL DVDInitialized = FALSE;
static void stateReadingFST();
static void stateTimeout();
static void stateGettingError();
static void stateGoToRetry();
static void stateCheckID();
static void stateCheckID3();
static void stateCheckID2a();
static void stateCheckID2();
static void stateCoverClosed();
static void stateCoverClosed_CMD();
static void stateCoverOpen();
static void stateMotorStopped();
static void stateReady();
static void stateBusy();
static void cbForStateReadingFST(u32 intType);
static void cbForStateError(u32 intType);
static void cbForStateGettingError(u32 intType);
static void cbForUnrecoveredError(u32 intType);
static void cbForUnrecoveredErrorRetry(u32 intType);
static void cbForStateGoToRetry(u32 intType);
static void cbForStateCheckID2a(u32 intType);
static void cbForStateCheckID1(u32 intType);
static void cbForStateCheckID2(u32 intType);
static void cbForStateCheckID3(u32 intType);
static void cbForStateCoverClosed(u32 intType);
static void cbForStateMotorStopped(u32 intType);
static void cbForStateBusy(u32 intType);
static void cbForCancelStreamSync(s32 result, DVDCommandBlock* block);
static void cbForCancelSync(s32 result, DVDCommandBlock* block);
static void cbForCancelAllSync(s32 result, DVDCommandBlock* block);
static void defaultOptionalCommandChecker(DVDCommandBlock* block, DVDLowCallback cb);
static DVDOptionalCommandChecker checkOptionalCommand = defaultOptionalCommandChecker;
extern void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context);
void __DVDPrintFatalMessage() {
}
int DVDCompareDiskID(DVDDiskID *lol, DVDDiskID *lol2) {
return 0;
}
static void defaultOptionalCommandChecker(DVDCommandBlock* block, DVDLowCallback cb) {}
void DVDInit() {
if (DVDInitialized) {
return;
}
DVDInitialized = TRUE;
__DVDFSInit();
__DVDClearWaitingQueue();
__DVDInitWA();
bootInfo = (OSBootInfo*)OSPhysicalToCached(0x0000);
IDShouldBe = &(bootInfo->DVDDiskID);
__OSSetInterruptHandler(21, __DVDInterruptHandler);
__OSUnmaskInterrupts(0x400);
OSInitThreadQueue(&__DVDThreadQueue);
__DIRegs[0] = 0x2a;
__DIRegs[1] = 0;
if (bootInfo->magic == 0xE5207C22) {
OSReport("app booted via JTAG\n");
OSReport("load fst\n");
__fstLoad();
} else if (bootInfo->magic != 0xD15EA5E) {
FirstTimeInBootrom = TRUE;
OSReport("bootrom\n");
} else {
OSReport("app booted from bootrom\n");
}
}
static void stateReadingFST() {
LastState = (stateFunc)stateReadingFST;
if (bootInfo->FSTMaxLength < BB2.FSTLength) {
OSPanic("dvd.c", 630, "DVDChangeDisk(): FST in the new disc is too big. ");
}
DVDLowRead(bootInfo->FSTLocation, OSRoundUp32B(BB2.FSTLength), BB2.FSTPosition,
cbForStateReadingFST);
}
static void cbForStateReadingFST(u32 intType) {
DVDCommandBlock* finished;
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
__DVDFSInit();
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)(0, finished);
}
stateReady();
} else {
stateGettingError();
}
}
inline static void stateError(u32 error) {
__DVDStoreErrorCode(error);
DVDLowStopMotor(cbForStateError);
}
static void cbForStateError(u32 intType) {
DVDCommandBlock* finished;
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
__DVDPrintFatalMessage();
FatalErrorFlag = TRUE;
finished = executing;
executing = &DummyCommandBlock;
if (finished->callback) {
(finished->callback)(-1, finished);
}
if (Canceling) {
Canceling = FALSE;
if (CancelCallback)
(CancelCallback)(0, finished);
}
stateReady();
return;
}
static void stateTimeout() {
__DVDStoreErrorCode(0x1234568);
DVDReset();
cbForStateError(0);
}
static void stateGettingError() { DVDLowRequestError(cbForStateGettingError); }
static u32 CategorizeError(u32 error) {
if (error == 0x20400) {
LastError = error;
return 1;
}
error &= 0xffffff;
if ((error == 0x62800) || (error == 0x23a00) || (error == 0xb5a01)) {
return 0;
}
++NumInternalRetry;
if (NumInternalRetry == 2) {
if (error == LastError) {
LastError = error;
return 1;
} else {
LastError = error;
return 2;
}
} else {
LastError = error;
if ((error == 0x31100) || (executing->command == 5)) {
return 2;
} else {
return 3;
}
}
}
inline static BOOL CheckCancel(u32 resume) {
DVDCommandBlock* finished;
if (Canceling) {
ResumeFromHere = resume;
Canceling = FALSE;
finished = executing;
executing = &DummyCommandBlock;
finished->state = 10;
if (finished->callback)
(*finished->callback)(-3, finished);
if (CancelCallback)
(CancelCallback)(0, finished);
stateReady();
return TRUE;
}
return FALSE;
}
static void cbForStateGettingError(u32 intType) {
u32 error;
u32 status;
u32 errorCategory;
u32 resume;
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 2) {
executing->state = -1;
stateError(0x1234567);
return;
}
error = __DIRegs[8];
status = error & 0xff000000;
errorCategory = CategorizeError(error);
if (errorCategory == 1) {
executing->state = -1;
stateError(error);
return;
}
if ((errorCategory == 2) || (errorCategory == 3)) {
resume = 0;
} else {
if (status == 0x01000000)
resume = 4;
else if (status == 0x02000000)
resume = 6;
else if (status == 0x03000000)
resume = 3;
else
resume = 5;
}
if (CheckCancel(resume))
return;
if (errorCategory == 2) {
__DVDStoreErrorCode(error);
stateGoToRetry();
return;
}
if (errorCategory == 3) {
if ((error & 0x00ffffff) == 0x00031100) {
DVDLowSeek(executing->offset, cbForUnrecoveredError);
} else {
LastState(executing);
}
return;
}
if (status == 0x01000000) {
executing->state = 5;
stateMotorStopped();
return;
} else if (status == 0x02000000) {
executing->state = 3;
stateCoverClosed();
return;
} else if (status == 0x03000000) {
executing->state = 4;
stateMotorStopped();
return;
} else {
executing->state = -1;
stateError(0x1234567);
return;
}
}
static void cbForUnrecoveredError(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
stateGoToRetry();
return;
}
DVDLowRequestError(cbForUnrecoveredErrorRetry);
}
static void cbForUnrecoveredErrorRetry(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
executing->state = -1;
if (intType & 2) {
__DVDStoreErrorCode(0x1234567);
DVDLowStopMotor(cbForStateError);
return;
}
__DVDStoreErrorCode(__DIRegs[8]);
DVDLowStopMotor(cbForStateError);
}
static void stateGoToRetry() { DVDLowStopMotor(cbForStateGoToRetry); }
static void cbForStateGoToRetry(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 2) {
executing->state = -1;
stateError(0x1234567);
return;
}
NumInternalRetry = 0;
if ((CurrCommand == 4) || (CurrCommand == 5) || (CurrCommand == 13) || (CurrCommand == 15)) {
ResetRequired = TRUE;
}
if (!CheckCancel(2)) {
executing->state = 11;
stateMotorStopped();
}
}
static void stateCheckID() {
switch (CurrCommand) {
case 3:
if (DVDCompareDiskID(&CurrDiskID, executing->id)) {
memcpy(IDShouldBe, &CurrDiskID, sizeof(DVDDiskID));
executing->state = 1;
DCInvalidateRange(&BB2, sizeof(DVDBB2));
LastState = stateCheckID2a;
stateCheckID2a(executing);
return;
} else {
DVDLowStopMotor(cbForStateCheckID1);
}
break;
default:
if (memcmp(&CurrDiskID, IDShouldBe, sizeof(DVDDiskID))) {
DVDLowStopMotor(cbForStateCheckID1);
} else {
LastState = stateCheckID3;
stateCheckID3(executing);
}
break;
}
}
static void stateCheckID3() {
DVDLowAudioBufferConfig(IDShouldBe->streaming, 10, cbForStateCheckID3);
}
static void stateCheckID2a() {
DVDLowAudioBufferConfig(IDShouldBe->streaming, 10, cbForStateCheckID2a);
}
static void cbForStateCheckID2a(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
stateCheckID2(executing);
return;
}
DVDLowRequestError(cbForStateGettingError);
}
static void stateCheckID2() {
DVDLowRead(&BB2, OSRoundUp32B(sizeof(BB2)), 0x420, cbForStateCheckID2);
}
static void cbForStateCheckID1(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 2) {
executing->state = -1;
stateError(0x1234567);
return;
}
NumInternalRetry = 0;
if (!CheckCancel(1)) {
executing->state = 6;
stateMotorStopped();
}
}
static void cbForStateCheckID2(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
stateReadingFST();
} else {
stateGettingError();
}
}
static void cbForStateCheckID3(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
if (!CheckCancel(0)) {
executing->state = 1;
stateBusy(executing);
}
} else {
stateGettingError();
}
}
static void AlarmHandler(OSAlarm* alarm, OSContext* context) {
DVDReset();
DCInvalidateRange(&CurrDiskID, sizeof(DVDDiskID));
LastState = stateCoverClosed_CMD;
stateCoverClosed_CMD(executing);
}
static void stateCoverClosed() {
DVDCommandBlock* finished;
switch (CurrCommand) {
case 5:
case 4:
case 13:
case 15:
__DVDClearWaitingQueue();
finished = executing;
executing = &DummyCommandBlock;
if (finished->callback) {
(finished->callback)(-4, finished);
}
stateReady();
break;
default:
DVDReset();
OSCreateAlarm(&ResetAlarm);
OSSetAlarm(&ResetAlarm, OSMillisecondsToTicks(1150), AlarmHandler);
break;
}
}
static void stateCoverClosed_CMD(DVDCommandBlock* block) {
DVDLowReadDiskID(&CurrDiskID, cbForStateCoverClosed);
}
static void cbForStateCoverClosed(u32 intType) {
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
stateCheckID();
} else {
stateGettingError();
}
}
static void stateMotorStopped(void) { DVDLowWaitCoverClose(cbForStateMotorStopped); }
static void cbForStateMotorStopped(u32 intType) {
__DIRegs[1] = 0;
executing->state = 3;
stateCoverClosed();
}
static void stateReady() {
DVDCommandBlock* finished;
if (!__DVDCheckWaitingQueue()) {
executing = (DVDCommandBlock*)NULL;
return;
}
if (PauseFlag) {
PausingFlag = TRUE;
executing = (DVDCommandBlock*)NULL;
return;
}
executing = __DVDPopWaitingQueue();
if (FatalErrorFlag) {
executing->state = -1;
finished = executing;
executing = &DummyCommandBlock;
if (finished->callback) {
(finished->callback)(-1, finished);
}
stateReady();
return;
}
CurrCommand = executing->command;
if (ResumeFromHere) {
switch (ResumeFromHere) {
case 1:
executing->state = 1;
stateCoverClosed();
break;
case 2:
executing->state = 11;
stateMotorStopped();
break;
case 3:
executing->state = 4;
stateMotorStopped();
break;
case 4:
executing->state = 5;
stateMotorStopped();
break;
case 7:
case 6:
executing->state = 3;
stateCoverClosed();
break;
case 5:
executing->state = -1;
stateError(CancelLastError);
break;
}
ResumeFromHere = 0;
} else {
executing->state = 1;
stateBusy(executing);
}
}
#define MIN(a, b) (((a) > (b)) ? (b) : (a))
static void stateBusy(DVDCommandBlock* block) {
DVDCommandBlock* finished;
LastState = stateBusy;
switch (block->command) {
case 5:
__DIRegs[1] = __DIRegs[1];
block->currTransferSize = sizeof(DVDDiskID);
DVDLowReadDiskID(block->addr, cbForStateBusy);
break;
case 1:
case 4:
if (!block->length) {
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
finished->callback(0, finished);
}
stateReady();
} else {
__DIRegs[1] = __DIRegs[1];
block->currTransferSize = MIN(block->length - block->transferredSize, 0x80000);
DVDLowRead((void*)((u8*)block->addr + block->transferredSize), block->currTransferSize,
block->offset + block->transferredSize, cbForStateBusy);
}
break;
case 2:
__DIRegs[1] = __DIRegs[1];
DVDLowSeek(block->offset, cbForStateBusy);
break;
case 3:
DVDLowStopMotor(cbForStateBusy);
break;
case 15:
DVDLowStopMotor(cbForStateBusy);
break;
case 6:
__DIRegs[1] = __DIRegs[1];
if (AutoFinishing) {
executing->currTransferSize = 0;
DVDLowRequestAudioStatus(0, cbForStateBusy);
} else {
executing->currTransferSize = 1;
DVDLowAudioStream(0, block->length, block->offset, cbForStateBusy);
}
break;
case 7:
__DIRegs[1] = __DIRegs[1];
DVDLowAudioStream(0x10000, 0, 0, cbForStateBusy);
break;
case 8:
__DIRegs[1] = __DIRegs[1];
AutoFinishing = TRUE;
DVDLowAudioStream(0, 0, 0, cbForStateBusy);
break;
case 9:
__DIRegs[1] = __DIRegs[1];
DVDLowRequestAudioStatus(0, cbForStateBusy);
break;
case 10:
__DIRegs[1] = __DIRegs[1];
DVDLowRequestAudioStatus(0x10000, cbForStateBusy);
break;
case 11:
__DIRegs[1] = __DIRegs[1];
DVDLowRequestAudioStatus(0x20000, cbForStateBusy);
break;
case 12:
__DIRegs[1] = __DIRegs[1];
DVDLowRequestAudioStatus(0x30000, cbForStateBusy);
break;
case 13:
__DIRegs[1] = __DIRegs[1];
DVDLowAudioBufferConfig(block->offset, block->length, cbForStateBusy);
break;
case 14:
__DIRegs[1] = __DIRegs[1];
block->currTransferSize = sizeof(DVDDriveInfo);
DVDLowInquiry(block->addr, cbForStateBusy);
break;
default:
checkOptionalCommand(block, cbForStateBusy);
break;
}
}
static u32 ImmCommand[] = {0xffffffff, 0xffffffff, 0xffffffff};
static char string_DVDChangeDiskAsyncMsg[] =
"DVDChangeDiskAsync(): You can't specify NULL to company name. \n";
static u32 DmaCommand[] = {0xffffffff};
inline static BOOL IsImmCommandWithResult(u32 command) {
u32 i;
if (command == 9 || command == 10 || command == 11 || command == 12) {
return TRUE;
}
for (i = 0; i < sizeof(ImmCommand) / sizeof(ImmCommand[0]); i++) {
if (command == ImmCommand[i])
return TRUE;
}
return FALSE;
}
inline static BOOL IsDmaCommand(u32 command) {
u32 i;
if (command == 1 || command == 4 || command == 5 || command == 14)
return TRUE;
for (i = 0; i < sizeof(DmaCommand) / sizeof(DmaCommand[0]); i++) {
if (command == DmaCommand[i])
return TRUE;
}
return FALSE;
}
static void cbForStateBusy(u32 intType) {
DVDCommandBlock* finished;
if (intType == 16) {
executing->state = -1;
stateTimeout();
return;
}
if ((CurrCommand == 3) || (CurrCommand == 15)) {
if (intType & 2) {
executing->state = -1;
stateError(0x1234567);
return;
}
NumInternalRetry = 0;
if (CurrCommand == 15) {
ResetRequired = TRUE;
}
if (CheckCancel(7)) {
return;
}
executing->state = 7;
stateMotorStopped();
return;
}
if (IsDmaCommand(CurrCommand)) {
executing->transferredSize += executing->currTransferSize - __DIRegs[6];
}
if (intType & 8) {
Canceling = FALSE;
finished = executing;
executing = &DummyCommandBlock;
finished->state = 10;
if (finished->callback)
(*finished->callback)(-3, finished);
if (CancelCallback)
(CancelCallback)(0, finished);
stateReady();
return;
}
if (intType & 1) {
NumInternalRetry = 0;
if (CheckCancel(0))
return;
if (IsDmaCommand(CurrCommand)) {
if (executing->transferredSize != executing->length) {
stateBusy(executing);
return;
}
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)((s32)finished->transferredSize, finished);
}
stateReady();
} else if (IsImmCommandWithResult(CurrCommand)) {
s32 result;
if ((CurrCommand == 11) || (CurrCommand == 10)) {
result = (s32)(__DIRegs[8] << 2);
} else {
result = (s32)__DIRegs[8];
}
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)(result, finished);
}
stateReady();
} else if (CurrCommand == 6) {
if (executing->currTransferSize == 0) {
if (__DIRegs[8] & 1) {
finished = executing;
executing = &DummyCommandBlock;
finished->state = 9;
if (finished->callback) {
(finished->callback)(-2, finished);
}
stateReady();
} else {
AutoFinishing = FALSE;
executing->currTransferSize = 1;
DVDLowAudioStream(0, executing->length, executing->offset, cbForStateBusy);
}
} else {
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)(0, finished);
}
stateReady();
}
} else {
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)(0, finished);
}
stateReady();
}
} else {
if (CurrCommand == 14) {
executing->state = -1;
stateError(0x01234567);
return;
}
if ((CurrCommand == 1 || CurrCommand == 4 || CurrCommand == 5 || CurrCommand == 14) &&
(executing->transferredSize == executing->length)) {
if (CheckCancel(0)) {
return;
}
finished = executing;
executing = &DummyCommandBlock;
finished->state = 0;
if (finished->callback) {
(finished->callback)((s32)finished->transferredSize, finished);
}
stateReady();
return;
}
stateGettingError();
}
}
static BOOL issueCommand(s32 prio, DVDCommandBlock* block) {
BOOL level;
BOOL result;
if (autoInvalidation &&
(block->command == 1 || block->command == 4 || block->command == 5 || block->command == 14)) {
DCInvalidateRange(block->addr, block->length);
}
level = OSDisableInterrupts();
block->state = 2;
result = __DVDPushWaitingQueue(prio, block);
if ((executing == (DVDCommandBlock*)NULL) && (PauseFlag == FALSE)) {
stateReady();
}
OSRestoreInterrupts(level);
return result;
}
BOOL DVDReadAbsAsyncPrio(DVDCommandBlock* block, void* addr, s32 length, s32 offset,
DVDCBCallback callback, s32 prio) {
BOOL idle;
block->command = 1;
block->addr = addr;
block->length = length;
block->offset = offset;
block->transferredSize = 0;
block->callback = callback;
idle = issueCommand(prio, block);
return idle;
}
BOOL DVDReadAbsAsyncForBS(DVDCommandBlock* block, void* addr, s32 length, s32 offset,
DVDCBCallback callback) {
BOOL idle;
block->command = 4;
block->addr = addr;
block->length = length;
block->offset = offset;
block->transferredSize = 0;
block->callback = callback;
idle = issueCommand(2, block);
return idle;
}
BOOL DVDReadDiskID(DVDCommandBlock* block, DVDDiskID* diskID, DVDCBCallback callback) {
BOOL idle;
block->command = 5;
block->addr = diskID;
block->length = sizeof(DVDDiskID);
;
block->offset = 0;
block->transferredSize = 0;
block->callback = callback;
idle = issueCommand(2, block);
return idle;
}
BOOL DVDPrepareStreamAbsAsync(DVDCommandBlock* block, u32 length, u32 offset,
DVDCBCallback callback) {
BOOL idle;
block->command = 6;
block->length = length;
block->offset = offset;
block->callback = callback;
idle = issueCommand(1, block);
return idle;
}
BOOL DVDCancelStreamAsync(DVDCommandBlock* block, DVDCBCallback callback) {
BOOL idle;
block->command = 7;
block->callback = callback;
idle = issueCommand(1, block);
return idle;
}
s32 DVDCancelStream(DVDCommandBlock* block) {
BOOL result;
s32 state;
BOOL enabled;
s32 retVal;
result = DVDCancelStreamAsync(block, cbForCancelStreamSync);
if (result == FALSE) {
return -1;
}
enabled = OSDisableInterrupts();
while (TRUE) {
state = ((volatile DVDCommandBlock*)block)->state;
if (state == 0 || state == -1 || state == 10) {
retVal = (s32)block->transferredSize;
break;
}
OSSleepThread(&__DVDThreadQueue);
}
OSRestoreInterrupts(enabled);
return retVal;
}
static void cbForCancelStreamSync(s32 result, DVDCommandBlock* block) {
block->transferredSize = (u32)result;
OSWakeupThread(&__DVDThreadQueue);
}
BOOL DVDStopStreamAtEndAsync(DVDCommandBlock* block, DVDCBCallback callback) {
BOOL idle;
block->command = 8;
block->callback = callback;
idle = issueCommand(1, block);
return idle;
}
BOOL DVDGetStreamErrorStatusAsync(DVDCommandBlock* block, DVDCBCallback callback) {
BOOL idle;
block->command = 9;
block->callback = callback;
idle = issueCommand(1, block);
return idle;
}
BOOL DVDGetStreamPlayAddrAsync(DVDCommandBlock* block, DVDCBCallback callback) {
BOOL idle;
block->command = 10;
block->callback = callback;
idle = issueCommand(1, block);
return idle;
}
BOOL DVDInquiryAsync(DVDCommandBlock* block, DVDDriveInfo* info, DVDCBCallback callback) {
BOOL idle;
block->command = 14;
block->addr = (void*)info;
block->length = sizeof(DVDDriveInfo);
block->transferredSize = 0;
block->callback = callback;
idle = issueCommand(2, block);
return idle;
}
void DVDReset(void) {
DVDLowReset();
__DIRegs[0] = 0x2a;
__DIRegs[1] = __DIRegs[1];
ResetRequired = FALSE;
ResumeFromHere = 0;
}
s32 DVDGetCommandBlockStatus(const DVDCommandBlock* block) {
BOOL enabled;
s32 retVal;
enabled = OSDisableInterrupts();
if (block->state == 3) {
retVal = 1;
} else {
retVal = block->state;
}
OSRestoreInterrupts(enabled);
return retVal;
}
s32 DVDGetDriveStatus() {
BOOL enabled;
s32 retVal;
enabled = OSDisableInterrupts();
if (FatalErrorFlag) {
retVal = -1;
} else if (PausingFlag) {
retVal = 8;
} else {
if (executing == (DVDCommandBlock*)NULL) {
retVal = 0;
} else if (executing == &DummyCommandBlock) {
retVal = 0;
} else {
retVal = DVDGetCommandBlockStatus(executing);
}
}
OSRestoreInterrupts(enabled);
return retVal;
}
BOOL DVDSetAutoInvalidation(BOOL autoInval) {
BOOL prev;
prev = autoInvalidation;
autoInvalidation = autoInval;
return prev;
}
inline void DVDPause(void) {
BOOL level;
level = OSDisableInterrupts();
PauseFlag = TRUE;
if (executing == (DVDCommandBlock*)NULL) {
PausingFlag = TRUE;
}
OSRestoreInterrupts(level);
}
inline void DVDResume(void) {
BOOL level;
level = OSDisableInterrupts();
PauseFlag = FALSE;
if (PausingFlag) {
PausingFlag = FALSE;
stateReady();
}
OSRestoreInterrupts(level);
}
BOOL DVDCancelAsync(DVDCommandBlock* block, DVDCBCallback callback) {
BOOL enabled;
DVDLowCallback old;
enabled = OSDisableInterrupts();
switch (block->state) {
case -1:
case 0:
case 10:
if (callback)
(*callback)(0, block);
break;
case 1:
if (Canceling) {
OSRestoreInterrupts(enabled);
return FALSE;
}
Canceling = TRUE;
CancelCallback = callback;
if (block->command == 4 || block->command == 1) {
DVDLowBreak();
}
break;
case 2:
__DVDDequeueWaitingQueue(block);
block->state = 10;
if (block->callback)
(block->callback)(-3, block);
if (callback)
(*callback)(0, block);
break;
case 3:
switch (block->command) {
case 5:
case 4:
case 13:
case 15:
if (callback)
(*callback)(0, block);
break;
default:
if (Canceling) {
OSRestoreInterrupts(enabled);
return FALSE;
}
Canceling = TRUE;
CancelCallback = callback;
break;
}
break;
case 4:
case 5:
case 6:
case 7:
case 11:
old = DVDLowClearCallback();
if (old != cbForStateMotorStopped) {
OSRestoreInterrupts(enabled);
return FALSE;
}
if (block->state == 4)
ResumeFromHere = 3;
if (block->state == 5)
ResumeFromHere = 4;
if (block->state == 6)
ResumeFromHere = 1;
if (block->state == 11)
ResumeFromHere = 2;
if (block->state == 7)
ResumeFromHere = 7;
block->state = 10;
if (block->callback) {
(block->callback)(-3, block);
}
if (callback) {
(callback)(0, block);
}
stateReady();
break;
}
OSRestoreInterrupts(enabled);
return TRUE;
}
s32 DVDCancel(DVDCommandBlock* block) {
BOOL result;
s32 state;
u32 command;
BOOL enabled;
result = DVDCancelAsync(block, cbForCancelSync);
if (result == FALSE) {
return -1;
}
enabled = OSDisableInterrupts();
for (;;) {
state = ((volatile DVDCommandBlock*)block)->state;
if ((state == 0) || (state == -1) || (state == 10)) {
break;
}
if (state == 3) {
command = ((volatile DVDCommandBlock*)block)->command;
if ((command == 4) || (command == 5) || (command == 13) || (command == 15)) {
break;
}
}
OSSleepThread(&__DVDThreadQueue);
}
OSRestoreInterrupts(enabled);
return 0;
}
static void cbForCancelSync(s32 result, DVDCommandBlock* block) {
OSWakeupThread(&__DVDThreadQueue);
}
inline BOOL DVDCancelAllAsync(DVDCBCallback callback) {
BOOL enabled;
DVDCommandBlock* p;
BOOL retVal;
enabled = OSDisableInterrupts();
DVDPause();
while ((p = __DVDPopWaitingQueue()) != 0) {
DVDCancelAsync(p, NULL);
}
if (executing)
retVal = DVDCancelAsync(executing, callback);
else {
retVal = TRUE;
if (callback)
(*callback)(0, NULL);
}
DVDResume();
OSRestoreInterrupts(enabled);
return retVal;
}
s32 DVDCancelAll(void) {
BOOL result;
BOOL enabled;
enabled = OSDisableInterrupts();
CancelAllSyncComplete = FALSE;
result = DVDCancelAllAsync(cbForCancelAllSync);
if (result == FALSE) {
OSRestoreInterrupts(enabled);
return -1;
}
for (;;) {
if (CancelAllSyncComplete)
break;
OSSleepThread(&__DVDThreadQueue);
}
OSRestoreInterrupts(enabled);
return 0;
}
static void cbForCancelAllSync(s32 result, DVDCommandBlock* block) {
CancelAllSyncComplete = TRUE;
OSWakeupThread(&__DVDThreadQueue);
}
DVDDiskID* DVDGetCurrentDiskID(void) { return (DVDDiskID*)OSPhysicalToCached(0); }
BOOL DVDCheckDisk(void) {
BOOL enabled;
s32 retVal;
s32 state;
u32 coverReg;
enabled = OSDisableInterrupts();
if (FatalErrorFlag) {
state = -1;
} else if (PausingFlag) {
state = 8;
} else {
if (executing == (DVDCommandBlock*)NULL) {
state = 0;
} else if (executing == &DummyCommandBlock) {
state = 0;
} else {
state = executing->state;
}
}
switch (state) {
case 1:
case 9:
case 10:
case 2:
retVal = TRUE;
break;
case -1:
case 11:
case 7:
case 3:
case 4:
case 5:
case 6:
retVal = FALSE;
break;
case 0:
case 8:
coverReg = __DIRegs[1];
if (((coverReg >> 2) & 1) || (coverReg & 1)) {
retVal = FALSE;
} else {
retVal = TRUE;
}
}
OSRestoreInterrupts(enabled);
return retVal;
}
void __DVDPrepareResetAsync(DVDCBCallback callback) {
BOOL enabled;
enabled = OSDisableInterrupts();
__DVDClearWaitingQueue();
if (Canceling) {
CancelCallback = callback;
} else {
if (executing) {
executing->callback = NULL;
}
DVDCancelAllAsync(callback);
}
OSRestoreInterrupts(enabled);
}