summaryrefslogtreecommitdiff
path: root/src/Dolphin/dvd/dvd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/Dolphin/dvd/dvd.c')
-rw-r--r--src/Dolphin/dvd/dvd.c1389
1 files changed, 1389 insertions, 0 deletions
diff --git a/src/Dolphin/dvd/dvd.c b/src/Dolphin/dvd/dvd.c
new file mode 100644
index 0000000..65c67f6
--- /dev/null
+++ b/src/Dolphin/dvd/dvd.c
@@ -0,0 +1,1389 @@
+#include <dolphin/DVDPriv.h>
+#include <dolphin/dvd.h>
+#include <dolphin/dvd_regs.h>
+#include <dolphin/os.h>
+#include <dolphin/os/OSBootInfo.h>
+
+const char* __DVDVersion = "<< Dolphin SDK - DVD\trelease build: Sep 5 2002 05:34:06 (0x2301) >>";
+
+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;
+
+/* States */
+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();
+
+/* Callbacks */
+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);
+
+static void defaultOptionalCommandChecker(DVDCommandBlock* block, DVDLowCallback cb) {}
+
+void DVDInit() {
+ if (DVDInitialized) {
+ return;
+ }
+
+ OSRegisterVersion(__DVDVersion);
+ 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("load fst\n");
+ __fstLoad();
+ } else if (bootInfo->magic != 0xD15EA5E) {
+ FirstTimeInBootrom = TRUE;
+ }
+}
+
+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};
+/* Somehow this got included even though the function is stripped? O.o */
+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);
+}