diff options
author | mrb0nk500 <b0nk@b0nk.xyz> | 2023-02-01 18:45:02 -0400 |
---|---|---|
committer | mrb0nk500 <b0nk@b0nk.xyz> | 2023-02-01 18:50:25 -0400 |
commit | 9fa0a7f1da1b70bee995f53c6c96c43189018772 (patch) | |
tree | 114548896790eaff23cdca84a025281de86bbb51 /src/Dolphin/dvd/dvd.c | |
parent | 2ba3289286bbfcf9fcc13fd135d976058d8b6c2e (diff) |
global: Import Dolphin SDK
This version comes from the Metroid Prime decompilation project.
https://github.com/PrimeDecomp/prime
Diffstat (limited to 'src/Dolphin/dvd/dvd.c')
-rw-r--r-- | src/Dolphin/dvd/dvd.c | 1389 |
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); +} |