summaryrefslogtreecommitdiff
path: root/src/dolphin
diff options
context:
space:
mode:
authorLagoLunatic <LagoLunatic@users.noreply.github.com>2025-03-16 21:52:11 -0400
committerLagoLunatic <LagoLunatic@users.noreply.github.com>2025-03-16 21:52:11 -0400
commit6acb5f801bae8bec14b7c0d854b0363daa792d1e (patch)
treec84a7e8ea6e596d014de7af359454b7e79344f11 /src/dolphin
parentc91ade372a9560eb511fc94369cbc229819f7ef6 (diff)
dolphin/dvd OK
Diffstat (limited to 'src/dolphin')
-rw-r--r--src/dolphin/dvd/dvd.c1731
-rw-r--r--src/dolphin/dvd/dvdFatal.c94
-rw-r--r--src/dolphin/dvd/dvderror.c74
-rw-r--r--src/dolphin/dvd/dvdfs.c664
-rw-r--r--src/dolphin/dvd/dvdidutils.c95
-rw-r--r--src/dolphin/dvd/dvdlow.c544
-rw-r--r--src/dolphin/dvd/dvdqueue.c164
-rw-r--r--src/dolphin/dvd/fstload.c82
8 files changed, 3448 insertions, 0 deletions
diff --git a/src/dolphin/dvd/dvd.c b/src/dolphin/dvd/dvd.c
new file mode 100644
index 00000000..61a5f255
--- /dev/null
+++ b/src/dolphin/dvd/dvd.c
@@ -0,0 +1,1731 @@
+#include "dolphin/dvd/dvd.h"
+#include "dolphin/dvd/dvderror.h"
+#include "dolphin/dvd/dvdfs.h"
+#include "dolphin/dvd/dvdlow.h"
+#include "dolphin/os/OS.h"
+
+const char* __DVDVersion = "<< Dolphin SDK - DVD\trelease build: Sep 5 2002 05:34:06 (0x2301) >>";
+
+static DVDBB2 BB2;
+static DVDDiskID CurrDiskID;
+static DVDCommandBlock DummyCommandBlock;
+static OSAlarm ResetAlarm;
+
+static DVDCommandBlock* executing;
+static DVDDiskID* IDShouldBe;
+static OSBootInfo* bootInfo;
+static volatile int PauseFlag;
+static volatile int PausingFlag;
+static int AutoFinishing;
+static BOOL FatalErrorFlag;
+static volatile u32 CurrCommand;
+static volatile u32 Canceling;
+static void (*CancelCallback)(s32, DVDCommandBlock*);
+static volatile u32 ResumeFromHere;
+static volatile u32 CancelLastError;
+static u32 LastError;
+static volatile s32 NumInternalRetry;
+static int ResetRequired;
+static int CancelAllSyncComplete;
+static volatile u32 ResetCount;
+static BOOL FirstTimeInBootrom;
+static u32 MotorState;
+static int DVDInitialized;
+void (*LastState)(DVDCommandBlock*);
+
+static int autoInvalidation = 1;
+
+static void defaultOptionalCommandChecker(DVDCommandBlock*, DVDCommandCheckerCallback);
+static DVDCommandChecker checkOptionalCommand = defaultOptionalCommandChecker;
+
+static void stateReadingFST();
+static void cbForStateReadingFST(unsigned long intType);
+static void stateError();
+static void stateGettingError();
+static unsigned long CategorizeError(unsigned long error);
+static void cbForStateGettingError(unsigned long intType);
+static void stateGoToRetry();
+static void cbForStateGoToRetry(unsigned long intType);
+static void stateCheckID();
+static void stateCheckID3();
+static void stateCheckID2a();
+static void cbForStateCheckID1(unsigned long intType);
+static void cbForStateCheckID2(unsigned long intType);
+static void cbForStateCheckID3(unsigned long intType);
+static void cbForStateCheckID2a(u32 intType);
+static void stateCheckID2();
+static void stateCoverClosed();
+static void stateCoverClosed_CMD(DVDCommandBlock* command);
+static void cbForStateCoverClosed(unsigned long intType);
+static void stateMotorStopped();
+static void cbForStateMotorStopped(unsigned long intType);
+static void stateReady();
+static void stateBusy(struct DVDCommandBlock * block);
+static void cbForStateBusy(unsigned long intType);
+static int issueCommand(long prio, struct DVDCommandBlock * block);
+static void cbForCancelStreamSync(long result, struct DVDCommandBlock * block);
+static void cbForStopStreamAtEndSync(long result, struct DVDCommandBlock *block);
+static void cbForGetStreamErrorStatusSync(long result, struct DVDCommandBlock *block);
+static void cbForGetStreamPlayAddrSync(long result, struct DVDCommandBlock *block);
+static void cbForGetStreamStartAddrSync(long result, struct DVDCommandBlock *block);
+static void cbForGetStreamLengthSync(long result, struct DVDCommandBlock *block);
+static void cbForChangeDiskSync();
+static void cbForInquirySync(long result, struct DVDCommandBlock *block);
+static void cbForCancelSync();
+static void cbForCancelAllSync();
+static void stateTimeout(void);
+static void cbForUnrecoveredError(u32 intType);
+static void cbForUnrecoveredErrorRetry(u32 intType);
+
+static void defaultOptionalCommandChecker(DVDCommandBlock*, DVDCommandCheckerCallback) {}
+
+void DVDInit() {
+ if (DVDInitialized == FALSE) {
+ OSRegisterVersion(__DVDVersion);
+ DVDInitialized = TRUE;
+ __DVDFSInit();
+ __DVDClearWaitingQueue();
+ __DVDInitWA();
+ bootInfo = (void*)OSPhysicalToCached(0);
+ IDShouldBe = &bootInfo->disk_info;
+ __OSSetInterruptHandler(0x15, __DVDInterruptHandler);
+ __OSUnmaskInterrupts(0x400U);
+ OSInitThreadQueue(&__DVDThreadQueue);
+ __DIRegs[0] = 0x2A;
+ __DIRegs[1] = 0;
+ if (bootInfo->boot_code == 0xE5207C22) {
+ // OSReport("app booted via JTAG\n");
+ OSReport("load fst\n");
+ __fstLoad();
+ } else if (bootInfo->boot_code == 0x0D15EA5E) {
+ // OSReport("app booted from bootrom\n");
+ } else {
+ FirstTimeInBootrom = 1;
+ // OSReport("bootrom\n");
+ }
+ }
+}
+
+static void stateReadingFST() {
+ LastState = stateReadingFST;
+ ASSERTLINE(652, ((u32)(bootInfo->FSTLocation) & (32 - 1)) == 0);
+ DVD_ASSERTMSGLINE(630, bootInfo->fst_max_length >= BB2.FSTLength, "DVDChangeDisk(): FST in the new disc is too big. ");
+ DVDLowRead(bootInfo->fst_location, (u32)(BB2.FSTLength + 0x1F) & 0xFFFFFFE0, BB2.FSTPosition, cbForStateReadingFST);
+}
+
+static u32 DmaCommand[1] = {0xFFFFFFFF};
+
+static void cbForStateReadingFST(u32 intType) {
+ DVDCommandBlock* finished;
+
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ ASSERTLINE(680, (intType & DVD_INTTYPE_CVR) == 0);
+
+ if (intType & DVD_INTTYPE_TC) {
+ ASSERTLINE(685, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+
+ __DVDFSInit();
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_END;
+
+ if (finished->callback) {
+ finished->callback(0, finished);
+ }
+
+ stateReady();
+ return;
+ }
+
+ ASSERTLINE(712, intType == DVD_INTTYPE_DE);
+ stateGettingError();
+}
+
+static void cbForStateError(u32 intType) {
+ DVDCommandBlock* finished;
+
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ 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();
+}
+
+static void stateError(u32 intType) {
+ __DVDStoreErrorCode(intType);
+ DVDLowStopMotor(&cbForStateError);
+}
+
+static void stateTimeout(void) {
+ __DVDStoreErrorCode(0x01234568);
+ DVDReset();
+ cbForStateError(0);
+}
+
+static void stateGettingError() {
+ DVDLowRequestError(cbForStateGettingError);
+}
+
+static unsigned long CategorizeError(unsigned long error) {
+ if (error == 0x20400) {
+ LastError = error;
+ return 1;
+ }
+
+ error &= 0x00FFFFFF;
+ if ((error == 0x62800) || (error == 0x23A00) || (error == 0xB5A01)) {
+ return 0;
+ }
+ NumInternalRetry += 1;
+ if (NumInternalRetry == 2) {
+ if (error == LastError) {
+ LastError = error;
+ return 1;
+ }
+ LastError = error;
+ return 2;
+ }
+
+ LastError = error;
+
+ if (error == 0x31100 || executing->command == DVD_COMMAND_READID) {
+ return 2;
+ }
+
+ return 3;
+}
+
+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 = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ if (intType & 2) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(0x1234567);
+ return;
+ }
+
+ ASSERTLINE(0x35D, intType == DVD_INTTYPE_TC);
+
+ error = __DIRegs[8];
+ status = error & 0xff000000;
+
+ errorCategory = CategorizeError(error);
+
+ if (errorCategory == 1) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ 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 = DVD_STATE_FATAL_ERROR;
+ stateError(0x1234567);
+ return;
+ }
+}
+
+static void cbForUnrecoveredError(u32 intType)
+{
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ if (intType & 1) {
+ stateGoToRetry();
+ return;
+ }
+
+ ASSERTLINE(0x3C3, intType == DVD_INTTYPE_DE);
+ DVDLowRequestError(cbForUnrecoveredErrorRetry);
+}
+
+static void cbForUnrecoveredErrorRetry(u32 intType)
+{
+ if (intType == 0x10) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+#ifdef DEBUG
+ DVDReset();
+#else
+ stateTimeout();
+#endif
+ } else {
+ executing->state = DVD_STATE_FATAL_ERROR;
+
+ if ((intType & 2) != 0) {
+#ifndef DEBUG
+ __DVDStoreErrorCode(0x01234567);
+#endif
+ DVDLowStopMotor(cbForStateError);
+ return;
+ }
+
+ stateError(__DIRegs[8]);
+ }
+}
+
+static void stateGoToRetry() {
+ DVDLowStopMotor(cbForStateGoToRetry);
+}
+
+static void cbForStateGoToRetry(u32 intType)
+{
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ if (intType & 2) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(0x1234567);
+ return;
+ }
+
+ ASSERTLINE(0x3F9, intType == DVD_INTTYPE_TC);
+ 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 DVD_COMMAND_CHANGE_DISK:
+ if (DVDCompareDiskID(&CurrDiskID, executing->disk_id)) {
+ memcpy(IDShouldBe, &CurrDiskID, sizeof(DVDDiskID));
+ executing->state = DVD_STATE_BUSY;
+ DCInvalidateRange(&BB2.bootFilePosition, 0x20);
+ LastState = stateCheckID2a;
+ stateCheckID2a(executing);
+ } else {
+ DVDLowStopMotor(cbForStateCheckID1);
+ }
+ break;
+ default:
+ if (memcmp(&CurrDiskID, IDShouldBe, sizeof(DVDDiskID)) != 0) {
+ DVDLowStopMotor(cbForStateCheckID1);
+ } else {
+ LastState = stateCheckID3;
+ stateCheckID3(executing);
+ }
+ break;
+ }
+}
+
+static void stateCheckID3() {
+ DVDLowAudioBufferConfig(IDShouldBe->is_streaming, 0xA, cbForStateCheckID3);
+}
+
+static void stateCheckID2a() {
+ DVDLowAudioBufferConfig(IDShouldBe->is_streaming, 0xA, cbForStateCheckID2a);
+}
+
+static void cbForStateCheckID2a(u32 intType) {
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ ASSERTLINE(1227, (intType & DVD_INTTYPE_CVR) == 0);
+
+ if (intType & DVD_INTTYPE_TC) {
+ ASSERTLINE(1232, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+ stateCheckID2(executing);
+ return;
+ }
+
+ ASSERTLINE(1243, intType == DVD_INTTYPE_DE);
+ stateGettingError();
+}
+
+static void stateCheckID2() {
+ DVDLowRead(&BB2, 0x20, 0x420, cbForStateCheckID2);
+}
+
+static void cbForStateCheckID1(unsigned long intType) {
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ if (intType & DVD_INTTYPE_DE) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(0x01234567);
+ return;
+ }
+
+ ASSERTLINE(0x483, intType == DVD_INTTYPE_TC);
+ NumInternalRetry = 0;
+
+ if (CheckCancel(1) == FALSE) {
+ executing->state = DVD_STATE_WRONG_DISK;
+ stateMotorStopped();
+ }
+}
+
+static void cbForStateCheckID2(unsigned long intType) {
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ ASSERTLINE(0x499, (intType & DVD_INTTYPE_CVR) == 0);
+ if (intType & DVD_INTTYPE_TC) {
+ ASSERTLINE(0x49E, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+ stateReadingFST();
+ return;
+ }
+ ASSERTLINE(0x4AF, intType == DVD_INTTYPE_DE);
+ stateGettingError();
+}
+
+static void cbForStateCheckID3(unsigned long intType) {
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ ASSERTLINE(0x4BF, (intType & DVD_INTTYPE_CVR) == 0);
+ if (intType & DVD_INTTYPE_TC) {
+ ASSERTLINE(0x4C4, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+ if (CheckCancel(0) == FALSE) {
+ executing->state = DVD_STATE_BUSY;
+ stateBusy(executing);
+ }
+ return;
+ }
+ ASSERTLINE(0x4D2, intType == DVD_INTTYPE_DE);
+ stateGettingError();
+}
+
+static void AlarmHandler(OSAlarm* alarm, OSContext* context) {
+ DVDReset();
+ DCInvalidateRange(&CurrDiskID, sizeof(DVDDiskID));
+ LastState = &stateCoverClosed_CMD;
+ stateCoverClosed_CMD(executing);
+}
+
+static void stateCoverClosed() {
+ struct DVDCommandBlock * finished;
+
+ switch(CurrCommand) {
+ case DVD_COMMAND_BSREAD:
+ case DVD_COMMAND_READID:
+ case DVD_COMMAND_AUDIO_BUFFER_CONFIG:
+ case DVD_COMMAND_BS_CHANGE_DISK:
+ __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* command) {
+ DVDLowReadDiskID(&CurrDiskID, cbForStateCoverClosed);
+}
+
+static void cbForStateCoverClosed(unsigned long intType) {
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ ASSERTLINE(0x524, (intType & DVD_INTTYPE_CVR) == 0);
+ if (intType & DVD_INTTYPE_TC) {
+ ASSERTLINE(0x529, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+ stateCheckID();
+ return;
+ }
+ ASSERTLINE(0x535, intType == DVD_INTTYPE_DE);
+ stateGettingError();
+}
+
+static void stateMotorStopped() {
+ DVDLowWaitCoverClose(cbForStateMotorStopped);
+}
+
+static void cbForStateMotorStopped(unsigned long intType) {
+ ASSERTLINE(0x552, intType == DVD_INTTYPE_CVR);
+ __DIRegs[1] = 0;
+ executing->state = DVD_STATE_COVER_CLOSED;
+ stateCoverClosed();
+}
+
+static void stateReady() {
+ if (__DVDCheckWaitingQueue() == 0) {
+ executing = NULL;
+ return;
+ }
+ if (PauseFlag != 0) {
+ PausingFlag = 1;
+ executing = NULL;
+ return;
+ }
+ executing = __DVDPopWaitingQueue();
+ if (FatalErrorFlag) {
+ DVDCommandBlock* finished;
+
+ executing->state = DVD_STATE_FATAL_ERROR;
+ finished = executing;
+ executing = &DummyCommandBlock;
+ if (finished->callback) {
+ (*finished->callback)(-1, finished);
+ }
+
+ stateReady();
+ return;
+ }
+
+ CurrCommand = executing->command;
+ if (ResumeFromHere != 0) {
+ DVDCommandBlock* finished;
+ switch (ResumeFromHere) {
+ case 1:
+ executing->state = DVD_STATE_BUSY;
+ switch (CurrCommand) {
+ case 4:
+ case 5:
+ case 0xD: // DVD_COMMAND_AUDIO_BUFFER_CONFIG
+ case 0xF: // DVD_COMMAND_AUDIO_BUFFER_CONFIG
+ __DVDClearWaitingQueue();
+ finished = executing;
+ executing = &DummyCommandBlock;
+ if (finished->callback) {
+ finished->callback(-4, finished);
+ }
+ stateReady();
+ break;
+ default:
+ DVDReset();
+ OSCreateAlarm(&ResetAlarm);
+ OSSetAlarm(&ResetAlarm, OSMillisecondsToTicks(1150), &AlarmHandler);
+ break;
+ }
+ break;
+ case 2:
+ executing->state = DVD_STATE_RETRY;
+ stateMotorStopped();
+ break;
+ case 3:
+ executing->state = DVD_STATE_NO_DISK;
+ stateMotorStopped();
+ break;
+ // case 7:
+ // executing->state = DVD_STATE_MOTOR_STOPPED;
+ // stateMotorStopped();
+ // break;
+ case 4:
+ executing->state = DVD_STATE_COVER_OPEN;
+ stateMotorStopped();
+ break;
+ case 6:
+ case 7:
+ executing->state = DVD_STATE_COVER_CLOSED;
+ stateCoverClosed();
+ break;
+ case 5:
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(CancelLastError);
+ break;
+ }
+ ResumeFromHere = 0;
+ return;
+ }
+ executing->state = DVD_STATE_BUSY;
+ stateBusy(executing);
+}
+
+static void stateBusy(struct DVDCommandBlock * block) {
+ DVDCommandBlock* finished;
+ LastState = stateBusy;
+ switch(block->command) {
+ case DVD_COMMAND_READID:
+ __DIRegs[1] = __DIRegs[1];
+ block->current_transfer_size = 0x20;
+ DVDLowReadDiskID(block->buffer, cbForStateBusy);
+ return;
+ case DVD_COMMAND_READ:
+ case DVD_COMMAND_BSREAD:
+ if (block->length == 0) {
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = 0;
+
+ if (finished->callback != 0) {
+ (*finished->callback)(0, finished);
+ }
+
+ stateReady();
+ } else {
+ __DIRegs[1] = __DIRegs[1];
+ block->current_transfer_size = (block->length - block->transferred_size > 0x80000) ? 0x80000 : (block->length - block->transferred_size);
+ DVDLowRead((char*)block->buffer + block->transferred_size, block->current_transfer_size, block->offset + block->transferred_size, cbForStateBusy);
+ }
+ return;
+ case DVD_COMMAND_SEEK:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowSeek(block->offset, cbForStateBusy);
+ return;
+ case DVD_COMMAND_CHANGE_DISK:
+ DVDLowStopMotor(cbForStateBusy);
+ return;
+ case DVD_COMMAND_BS_CHANGE_DISK:
+ DVDLowStopMotor(cbForStateBusy);
+ return;
+ case DVD_COMMAND_INITSTREAM:
+ __DIRegs[1] = __DIRegs[1];
+ if (AutoFinishing != 0) {
+ executing->current_transfer_size = 0;
+ DVDLowRequestAudioStatus(0, cbForStateBusy);
+ return;
+ }
+ executing->current_transfer_size = 1;
+ DVDLowAudioStream(0, block->length, block->offset, cbForStateBusy);
+ return;
+ case DVD_COMMAND_CANCELSTREAM:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowAudioStream(0x10000, 0U, 0U, cbForStateBusy);
+ return;
+ case DVD_COMMAND_STOP_STREAM_AT_END:
+ __DIRegs[1] = __DIRegs[1];
+ AutoFinishing = 1;
+ DVDLowAudioStream(0, 0U, 0U, cbForStateBusy);
+ return;
+ case DVD_COMMAND_REQUEST_AUDIO_ERROR:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowRequestAudioStatus(0, cbForStateBusy);
+ return;
+ case DVD_COMMAND_REQUEST_PLAY_ADDR:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowRequestAudioStatus(0x10000, cbForStateBusy);
+ return;
+ case DVD_COMMAND_REQUEST_START_ADDR:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowRequestAudioStatus(0x20000, cbForStateBusy);
+ return;
+ case DVD_COMMAND_REQUEST_LENGTH:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowRequestAudioStatus(0x30000, cbForStateBusy);
+ return;
+ case DVD_COMMAND_AUDIO_BUFFER_CONFIG:
+ __DIRegs[1] = __DIRegs[1];
+ DVDLowAudioBufferConfig(block->offset, block->length, cbForStateBusy);
+ return;
+ case DVD_COMMAND_INQUIRY:
+ __DIRegs[1] = __DIRegs[1];
+ block->current_transfer_size = 0x20;
+ DVDLowInquiry(block->buffer, cbForStateBusy);
+ return;
+ default:
+ checkOptionalCommand(block, cbForStateBusy);
+ return;
+ }
+}
+
+static u32 ImmCommand[3] = {0xFFFFFFFF, 0xFFFFFFFF, 0xFFFFFFFF};
+
+static BOOL IsImmCommandWithResult(u32 command) {
+ u32 i;
+
+ if ((command == DVD_COMMAND_REQUEST_AUDIO_ERROR) || (command == DVD_COMMAND_REQUEST_PLAY_ADDR)
+ || (command == DVD_COMMAND_REQUEST_START_ADDR) || (command == DVD_COMMAND_REQUEST_LENGTH)) {
+ return 1;
+ }
+
+ for (i = 0; i < 3; i++) {
+ if (command == ImmCommand[i]) {
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static int IsDmaCommand(u32 command) {
+ if ((command == DVD_COMMAND_READ) || (command == DVD_COMMAND_BSREAD)
+ || (command == DVD_COMMAND_READID) || (command == DVD_COMMAND_INQUIRY)) {
+ return 1;
+ }
+
+ if (command == DmaCommand[0]) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void cbForStateBusy(unsigned long intType) {
+ struct DVDCommandBlock * finished;
+ long result;
+
+ if (intType == 16) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateTimeout();
+ return;
+ }
+
+ if ((CurrCommand == DVD_COMMAND_CHANGE_DISK) || (CurrCommand == DVD_COMMAND_BS_CHANGE_DISK)) {
+ if (intType & DVD_INTTYPE_DE) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(0x01234567);
+ return;
+ }
+ ASSERTLINE(0x675, intType == DVD_INTTYPE_TC);
+ NumInternalRetry = 0;
+ if (CurrCommand == DVD_COMMAND_BS_CHANGE_DISK) {
+ ResetRequired = 1;
+ }
+
+ if (CheckCancel(7) == FALSE) {
+ executing->state = DVD_STATE_MOTOR_STOPPED;
+ stateMotorStopped();
+ }
+ return;
+ }
+ ASSERTLINE(0x689, (intType & DVD_INTTYPE_CVR) == 0);
+ if (IsDmaCommand(CurrCommand)) {
+ executing->transferred_size += executing->current_transfer_size - __DIRegs[6];
+ }
+ if (intType & 8) {
+ Canceling = 0;
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_CANCELED;
+ if (finished->callback) {
+ finished->callback(-3, finished);
+ }
+ if (CancelCallback) {
+ CancelCallback(0, finished);
+ }
+ stateReady();
+ return;
+ }
+ if (intType & 1) {
+ ASSERTLINE(0x6AF, (intType & DVD_INTTYPE_DE) == 0);
+ NumInternalRetry = 0;
+ if (CheckCancel(0) != FALSE) {
+ return;
+ }
+
+ if (IsDmaCommand(CurrCommand)) {
+ if (executing->transferred_size != executing->length) {
+ stateBusy(executing);
+ return;
+ }
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_END;
+ if (finished->callback) {
+ finished->callback(finished->transferred_size, finished);
+ }
+ stateReady();
+ return;
+ } else if (IsImmCommandWithResult(CurrCommand)) {
+
+ if (CurrCommand == DVD_COMMAND_REQUEST_START_ADDR || CurrCommand == DVD_COMMAND_REQUEST_PLAY_ADDR) {
+ result = __DIRegs[8] * 4;
+ } else {
+ result = __DIRegs[8];
+ }
+
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_END;
+ if (finished->callback) {
+ finished->callback(result, finished);
+ }
+ stateReady();
+ return;
+ } else if (CurrCommand == DVD_COMMAND_INITSTREAM) {
+ if (executing->current_transfer_size == 0) {
+ if (__DIRegs[8] & 1) {
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_IGNORED;
+ if (finished->callback) {
+ finished->callback(-2, finished);
+ }
+ stateReady();
+ return;
+ }
+ AutoFinishing = 0;
+ executing->current_transfer_size = 1;
+ DVDLowAudioStream(0, executing->length, executing->offset, cbForStateBusy);
+ return;
+ }
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_END;
+ if (finished->callback) {
+ finished->callback(0, finished);
+ }
+ stateReady();
+ return;
+ } else {
+ finished = executing;
+ executing = &DummyCommandBlock;
+ finished->state = DVD_STATE_END;
+ if (finished->callback) {
+ finished->callback(0, finished);
+ }
+ stateReady();
+ return;
+ }
+ } else {
+ ASSERTLINE(0x72E, intType == DVD_INTTYPE_DE);
+
+ if (CurrCommand == 14) {
+ executing->state = DVD_STATE_FATAL_ERROR;
+ stateError(0x01234567);
+ return;
+ }
+
+ if ((CurrCommand == 1 || CurrCommand == 4 || CurrCommand == 5 || CurrCommand == 14)
+ && (executing->transferred_size == executing->length)) {
+
+ if (CheckCancel(0)) {
+ return;
+ }
+ finished = executing;
+ executing = &DummyCommandBlock;
+
+ finished->state = DVD_STATE_END;
+ if (finished->callback) {
+ (finished->callback)((s32)finished->transferred_size, finished);
+ }
+ stateReady();
+ return;
+ }
+
+ stateGettingError();
+ }
+}
+
+static int issueCommand(long prio, struct DVDCommandBlock * block) {
+ int level;
+ int result;
+
+ if (autoInvalidation != 0 && (block->command == DVD_COMMAND_READ || block->command == DVD_COMMAND_BSREAD
+ || block->command == DVD_COMMAND_READID || block->command == DVD_COMMAND_INQUIRY)) {
+ DCInvalidateRange(block->buffer, block->length);
+ }
+ level = OSDisableInterrupts();
+#if DEBUG
+ if (executing == block || block->state == DVD_STATE_WAITING && __DVDIsBlockInWaitingQueue(block)) {
+ ASSERTMSGLINE(0x781, FALSE, "DVD library: Specified command block (or file info) is already in use\n");
+ }
+#endif
+ block->state = DVD_STATE_WAITING;
+ result = __DVDPushWaitingQueue(prio, block);
+ if (executing == NULL && PauseFlag == 0) {
+ stateReady();
+ }
+ OSRestoreInterrupts(level);
+ return result;
+}
+
+int DVDReadAbsAsyncPrio(struct DVDCommandBlock * block, void * addr, long length, long offset, void (* callback)(long, struct DVDCommandBlock *), long prio) {
+ int idle;
+
+ ASSERTMSGLINE(0x7A9, block, "DVDReadAbsAsync(): null pointer is specified to command block address.");
+ ASSERTMSGLINE(0x7AA, addr, "DVDReadAbsAsync(): null pointer is specified to addr.");
+ ASSERTMSGLINE(0x7AC, !OFFSET(addr, 32), "DVDReadAbsAsync(): address must be aligned with 32 byte boundary.");
+ ASSERTMSGLINE(0x7AE, !(length & (32-1)), "DVDReadAbsAsync(): length must be a multiple of 32.");
+ ASSERTMSGLINE(0x7B0, !(offset & (4-1)), "DVDReadAbsAsync(): offset must be a multiple of 4.");
+ ASSERTMSGLINE(0x7B2, length > 0, "DVD read: 0 or negative value was specified to length of the read\n");
+ block->command = DVD_COMMAND_READ;
+ block->buffer = addr;
+ block->length = length;
+ block->offset = offset;
+ block->transferred_size = 0;
+ block->callback = callback;
+ idle = issueCommand(prio, block);
+ ASSERTMSGLINE(0x7BC, idle, "DVDReadAbsAsync(): command block is used for processing previous request.");
+ return idle;
+}
+
+int DVDSeekAbsAsyncPrio(struct DVDCommandBlock * block, long offset, void (* callback)(long, struct DVDCommandBlock *), long prio) {
+ int idle;
+
+ ASSERTMSGLINE(0x7D3, block, "DVDSeekAbs(): null pointer is specified to command block address.");
+ ASSERTMSGLINE(0x7D5, !(offset & (4-1)), "DVDSeekAbs(): offset must be a multiple of 4.");
+ block->command = DVD_COMMAND_SEEK;
+ block->offset = offset;
+ block->callback = callback;
+ idle = issueCommand(prio, block);
+ ASSERTMSGLINE(0x7DC, idle, "DVDSeekAbs(): command block is used for processing previous request.");
+ return idle;
+}
+
+int DVDReadAbsAsyncForBS(struct DVDCommandBlock * block, void * addr, long length, long offset, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ ASSERTMSGLINE(0x7FA, block, "DVDReadAbsAsyncForBS(): null pointer is specified to command block address.");
+ ASSERTMSGLINE(0x7FB, addr, "DVDReadAbsAsyncForBS(): null pointer is specified to addr.");
+ ASSERTMSGLINE(0x7FD, !OFFSET(addr, 32), "DVDReadAbsAsyncForBS(): address must be aligned with 32 byte boundary.");
+ ASSERTMSGLINE(0x7FF, !(length & (32-1)), "DVDReadAbsAsyncForBS(): length must be a multiple of 32.");
+ ASSERTMSGLINE(0x801, !(offset & (4-1)), "DVDReadAbsAsyncForBS(): offset must be a multiple of 4.");
+ block->command = DVD_COMMAND_BSREAD;
+ block->buffer = addr;
+ block->length = length;
+ block->offset = offset;
+ block->transferred_size = 0;
+ block->callback = callback;
+ idle = issueCommand(2, block);
+ ASSERTMSGLINE(0x80B, idle, "DVDReadAbsAsyncForBS(): command block is used for processing previous request.");
+ return idle;
+}
+
+int DVDReadDiskID(struct DVDCommandBlock * block, struct DVDDiskID * diskID, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ ASSERTMSGLINE(0x822, block, "DVDReadDiskID(): null pointer is specified to command block address.");
+ ASSERTMSGLINE(0x823, diskID, "DVDReadDiskID(): null pointer is specified to id address.");
+ ASSERTMSGLINE(0x825, !OFFSET(diskID, 32), "DVDReadDiskID(): id must be aligned with 32 byte boundary.");
+
+ block->command = DVD_COMMAND_READID;
+ block->buffer = diskID;
+ block->length = 0x20;
+ block->offset = 0;
+ block->transferred_size = 0;
+ block->callback = callback;
+ idle = issueCommand(2, block);
+ ASSERTMSGLINE(0x82F, idle, "DVDReadDiskID(): command block is used for processing previous request.");
+ return idle;
+}
+
+int DVDPrepareStreamAbsAsync(struct DVDCommandBlock * block, unsigned long length, unsigned long offset, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_INITSTREAM;
+ block->length = length;
+ block->offset = offset;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+int DVDCancelStreamAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_CANCELSTREAM;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDCancelStream(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDCancelStreamAsync(block, cbForCancelStreamSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForCancelStreamSync(long result, struct DVDCommandBlock * block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDStopStreamAtEndAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_STOP_STREAM_AT_END;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDStopStreamAtEnd(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDStopStreamAtEndAsync(block, cbForStopStreamAtEndSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForStopStreamAtEndSync(long result, struct DVDCommandBlock *block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDGetStreamErrorStatusAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_REQUEST_AUDIO_ERROR;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDGetStreamErrorStatus(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDGetStreamErrorStatusAsync(block, cbForGetStreamErrorStatusSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForGetStreamErrorStatusSync(long result, struct DVDCommandBlock *block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDGetStreamPlayAddrAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_REQUEST_PLAY_ADDR;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDGetStreamPlayAddr(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDGetStreamPlayAddrAsync(block, cbForGetStreamPlayAddrSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForGetStreamPlayAddrSync(long result, struct DVDCommandBlock *block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDGetStreamStartAddrAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_REQUEST_START_ADDR;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDGetStreamStartAddr(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDGetStreamStartAddrAsync(block, cbForGetStreamStartAddrSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForGetStreamStartAddrSync(long result, struct DVDCommandBlock *block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDGetStreamLengthAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_REQUEST_LENGTH;
+ block->callback = callback;
+ idle = issueCommand(1, block);
+ return idle;
+}
+
+long DVDGetStreamLength(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDGetStreamLengthAsync(block, cbForGetStreamLengthSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ retVal = block->transferred_size;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForGetStreamLengthSync(long result, struct DVDCommandBlock *block) {
+ block->transferred_size = (u32)result;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+void __DVDAudioBufferConfig(struct DVDCommandBlock * block, unsigned long enable, unsigned long size, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ block->command = DVD_COMMAND_AUDIO_BUFFER_CONFIG;
+ block->offset = enable;
+ block->length = size;
+ block->callback = callback;
+ idle = issueCommand(2, block);
+}
+
+int DVDChangeDiskAsyncForBS(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ ASSERTMSGLINE(0xA4F, block, "DVDChangeDiskAsyncForBS(): null pointer is specified to command block address.");
+ block->command = DVD_COMMAND_BS_CHANGE_DISK;
+ block->callback = callback;
+ idle = issueCommand(2, block);
+ ASSERTMSGLINE(0xA55, idle, "DVDChangeDiskAsyncForBS(): command block is used for processing previous request.");
+ return idle;
+}
+
+int DVDChangeDiskAsync(DVDCommandBlock* block, DVDDiskID* id, DVDCBCallback callback) {
+ int idle;
+
+ ASSERTMSGLINE(2896, block, "DVDChangeDisk(): null pointer is specified to command block address.");
+ ASSERTMSGLINE(2897, id, "DVDChangeDisk(): null pointer is specified to id address.");
+
+ if (id->company[0] == 0) {
+ OSReport("DVDChangeDiskAsync(): You can't specify NULL to company name. \n");
+ DVD_ASSERTMSGLINE(2902, 0, "");
+ }
+
+ block->command = DVD_COMMAND_CHANGE_DISK;
+ block->disk_id = id;
+ block->callback = callback;
+ DCInvalidateRange(bootInfo->fst_location, bootInfo->fst_max_length);
+
+ idle = issueCommand(2, block);
+ ASSERTMSGLINE(2913, idle, "DVDChangeDisk(): command block is used for processing previous request.");
+ return idle;
+}
+
+long DVDChangeDisk(struct DVDCommandBlock * block, struct DVDDiskID * id) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDChangeDiskAsync(block, id, cbForChangeDiskSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END) {
+ retVal = 0;
+ break;
+ } else if (state == DVD_STATE_FATAL_ERROR) {
+ retVal = -1;
+ break;
+ } else if (state == DVD_STATE_CANCELED) {
+ retVal = -3;
+ break;
+ }
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForChangeDiskSync() {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDInquiryAsync(struct DVDCommandBlock * block, struct DVDDriveInfo * info, void (* callback)(long, struct DVDCommandBlock *)) {
+ int idle;
+
+ ASSERTMSGLINE(0xAC9, block, "DVDInquiry(): Null address was specified for block");
+ ASSERTMSGLINE(0xACA, info, "DVDInquiry(): Null address was specified for info");
+ ASSERTMSGLINE(0xACC, !OFFSET(info, 32), "DVDInquiry(): Address for info is not 32 bytes aligned");
+
+ block->command = 0xE;
+ block->buffer = info;
+ block->length = 0x20;
+ block->transferred_size = 0;
+ block->callback = callback;
+ idle = issueCommand(2, block);
+ return idle;
+}
+
+long DVDInquiry(struct DVDCommandBlock * block, struct DVDDriveInfo * info) {
+ int result;
+ long state;
+ int enabled;
+ long retVal;
+
+ result = DVDInquiryAsync(block, info, cbForInquirySync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END) {
+ retVal = (u32)block->transferred_size;
+ break;
+ } else if (state == DVD_STATE_FATAL_ERROR) {
+ retVal = -1;
+ break;
+ } else if (state == DVD_STATE_CANCELED) {
+ retVal = -3;
+ break;
+ }
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForInquirySync(long result, struct DVDCommandBlock *block) {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+void DVDReset() {
+ DVDLowReset();
+ __DIRegs[0] = 0x2A;
+ __DIRegs[1] = __DIRegs[1];
+ ResetRequired = 0;
+ ResumeFromHere = 0;
+}
+
+int DVDResetRequired() {
+ return ResetRequired;
+}
+
+long DVDGetCommandBlockStatus(const struct DVDCommandBlock * block) {
+ BOOL enabled;
+ s32 retVal;
+
+ ASSERTMSGLINE(0xB39, block, "DVDGetCommandBlockStatus(): null pointer is specified to command block address.");
+ enabled = OSDisableInterrupts();
+
+ if (block->state == 3) {
+ retVal = 1;
+ } else {
+ retVal = block->state;
+ }
+
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+long DVDGetDriveStatus() {
+ BOOL enabled = OSDisableInterrupts();
+ s32 retVal;
+
+ if (FatalErrorFlag != FALSE) {
+ retVal = DVD_STATE_FATAL_ERROR;
+ } else {
+ if (PausingFlag != FALSE) {
+ retVal = DVD_STATE_PAUSING;
+ } else {
+ if (executing == NULL) {
+ retVal = DVD_STATE_END;
+ } else if (executing == &DummyCommandBlock) {
+ retVal = DVD_STATE_END;
+ } else {
+ retVal = DVDGetCommandBlockStatus((struct DVDCommandBlock*)executing);
+ }
+ }
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+int DVDSetAutoInvalidation(int autoInval) {
+ int prev;
+
+ prev = autoInvalidation;
+ autoInvalidation = autoInval;
+ return prev;
+}
+
+void DVDPause() {
+ int level;
+
+ level = OSDisableInterrupts();
+ PauseFlag = 1;
+ if (executing == NULL) {
+ PausingFlag = 1;
+ }
+ OSRestoreInterrupts(level);
+}
+
+void DVDResume() {
+ int level;
+
+ level = OSDisableInterrupts();
+ PauseFlag = 0;
+ if (PausingFlag != 0) {
+ PausingFlag = 0;
+ stateReady();
+ }
+ OSRestoreInterrupts(level);
+}
+
+int DVDCancelAsync(struct DVDCommandBlock * block, void (* callback)(long, struct DVDCommandBlock *)) {
+ BOOL enabled;
+ DVDLowCallback old;
+
+ enabled = OSDisableInterrupts();
+
+ switch (block->state) {
+ case DVD_STATE_FATAL_ERROR:
+ case DVD_STATE_END:
+ case DVD_STATE_CANCELED:
+ if (callback)
+ (*callback)(0, block);
+ break;
+
+ case DVD_STATE_BUSY:
+ if (Canceling) {
+ OSRestoreInterrupts(enabled);
+ return FALSE;
+ }
+
+ Canceling = TRUE;
+ CancelCallback = callback;
+ if (block->command == DVD_COMMAND_BSREAD || block->command == DVD_COMMAND_READ) {
+ DVDLowBreak();
+ }
+ break;
+
+ case DVD_STATE_WAITING:
+ __DVDDequeueWaitingQueue(block);
+ block->state = DVD_STATE_CANCELED;
+ if (block->callback)
+ (block->callback)(-3, block);
+ if (callback)
+ (*callback)(0, block);
+ break;
+
+ case DVD_STATE_COVER_CLOSED:
+ switch (block->command) {
+ case DVD_COMMAND_READID:
+ case DVD_COMMAND_BSREAD:
+ case DVD_COMMAND_AUDIO_BUFFER_CONFIG:
+ case DVD_COMMAND_BS_CHANGE_DISK:
+ if (callback)
+ (*callback)(0, block);
+ break;
+
+ default:
+ if (Canceling) {
+ OSRestoreInterrupts(enabled);
+ return FALSE;
+ }
+ Canceling = TRUE;
+ CancelCallback = callback;
+ break;
+ }
+ break;
+
+ case DVD_STATE_NO_DISK:
+ case DVD_STATE_COVER_OPEN:
+ case DVD_STATE_WRONG_DISK:
+ case DVD_STATE_MOTOR_STOPPED:
+ case DVD_STATE_RETRY:
+ old = DVDLowClearCallback();
+ ASSERTLINE(0xC13, old == cbForStateMotorStopped);
+ if (old != cbForStateMotorStopped) {
+ OSRestoreInterrupts(enabled);
+ return FALSE;
+ }
+
+ if (block->state == DVD_STATE_NO_DISK)
+ ResumeFromHere = 3;
+ if (block->state == DVD_STATE_COVER_OPEN)
+ ResumeFromHere = 4;
+ if (block->state == DVD_STATE_WRONG_DISK)
+ ResumeFromHere = 1;
+ if (block->state == DVD_STATE_RETRY)
+ ResumeFromHere = 2;
+ if (block->state == DVD_STATE_MOTOR_STOPPED)
+ ResumeFromHere = 7;
+
+ block->state = DVD_STATE_CANCELED;
+ if (block->callback) {
+ (block->callback)(-3, block);
+ }
+ if (callback) {
+ (callback)(0, block);
+ }
+ stateReady();
+ break;
+ }
+
+ OSRestoreInterrupts(enabled);
+ return TRUE;
+}
+
+long DVDCancel(struct DVDCommandBlock * block) {
+ int result;
+ long state;
+ unsigned long command;
+ int enabled;
+
+ result = DVDCancelAsync((void*)block, cbForCancelSync);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+ while(1) {
+ state = block->state;
+ if (state == DVD_STATE_END || state == DVD_STATE_FATAL_ERROR || state == DVD_STATE_CANCELED) {
+ break;
+ }
+ if (state == DVD_STATE_COVER_CLOSED) {
+ command = block->command;
+ // ((command - DVD_COMMAND_BSREAD) <= 1) is a fakematch, correct line should be:
+ // if ((command == DVD_COMMAND_BSREAD) || (command == DVD_COMMAND_READID) || (command == DVD_COMMAND_AUDIO_BUFFER_CONFIG) || (command == DVD_COMMAND_BS_CHANGE_DISK)) {
+ if (((command - DVD_COMMAND_BSREAD) <= 1) || (command == DVD_COMMAND_AUDIO_BUFFER_CONFIG) || (command == DVD_COMMAND_BS_CHANGE_DISK)) {
+ break;
+ }
+ }
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return 0;
+}
+
+static void cbForCancelSync() {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDCancelAllAsync(void (* callback)(long, struct DVDCommandBlock *)) {
+ int enabled;
+ struct DVDCommandBlock * p;
+ int retVal;
+
+ enabled = OSDisableInterrupts();
+ DVDPause();
+ while ((p = __DVDPopWaitingQueue())) {
+ DVDCancelAsync(p, NULL);
+ }
+ if (executing) {
+ retVal = DVDCancelAsync(executing, callback);
+ } else {
+ retVal = 1;
+ if (callback) {
+ callback(0, NULL);
+ }
+ }
+ DVDResume();
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+long DVDCancelAll() {
+ int result;
+ int enabled;
+
+ enabled = OSDisableInterrupts();
+ CancelAllSyncComplete = 0;
+ result = DVDCancelAllAsync(cbForCancelAllSync);
+ if (result == 0) {
+ OSRestoreInterrupts(enabled);
+ return -1;
+ }
+ while(1) {
+ if (CancelAllSyncComplete == 0) {
+ OSSleepThread(&__DVDThreadQueue);
+ } else {
+ break;
+ }
+ }
+ OSRestoreInterrupts(enabled);
+ return 0;
+}
+
+static void cbForCancelAllSync() {
+ CancelAllSyncComplete = 1;
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+struct DVDDiskID * DVDGetCurrentDiskID() {
+ return (void*)OSPhysicalToCached(0);
+}
+
+BOOL DVDCheckDisk()
+{
+ BOOL enabled;
+ s32 retVal;
+ s32 state;
+ u32 coverReg;
+
+ enabled = OSDisableInterrupts();
+
+ if (FatalErrorFlag) {
+ state = -1;
+ } else if (PausingFlag) {
+ state = 8;
+ } else {
+ if (executing == NULL) {
+ state = 0;
+ } else if (executing == &DummyCommandBlock) {
+ state = 0;
+ } else {
+ state = executing->state;
+ }
+ }
+
+ switch (state) {
+ case DVD_STATE_BUSY:
+ case DVD_STATE_IGNORED:
+ case DVD_STATE_CANCELED:
+ case DVD_STATE_WAITING:
+ retVal = TRUE;
+ break;
+
+ case DVD_STATE_FATAL_ERROR:
+ case DVD_STATE_RETRY:
+ case DVD_STATE_MOTOR_STOPPED:
+ case DVD_STATE_COVER_CLOSED:
+ case DVD_STATE_NO_DISK:
+ case DVD_STATE_COVER_OPEN:
+ case DVD_STATE_WRONG_DISK:
+ retVal = FALSE;
+ break;
+
+ case DVD_STATE_END:
+ case DVD_STATE_PAUSING:
+ 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);
+}
diff --git a/src/dolphin/dvd/dvdFatal.c b/src/dolphin/dvd/dvdFatal.c
new file mode 100644
index 00000000..35c6527d
--- /dev/null
+++ b/src/dolphin/dvd/dvdFatal.c
@@ -0,0 +1,94 @@
+#include "dolphin/dvd/dvdFatal.h"
+#include "dolphin/gx/GXStruct.h"
+#include "dolphin/os/OS.h"
+
+static void (*FatalFunc)();
+
+const char* Japanese =
+ "\n\n\nエラーが発生しました。\n\n"
+ "本体のパワーボタンを押して電源をOFFにし、\n"
+ "本体の取扱説明書の指示に従ってください。";
+
+const char* English =
+ "\n\n\nAn error has occurred.\n"
+ "Turn the power off and refer to the\n"
+ "Nintendo GameCube Instruction Booklet\n"
+ "for further instructions.";
+
+// TODO: need solution to compile special characters in a cleaner way
+const char* const Europe[6] = {
+ {
+ "\n\n\nAn error has occurred.\n"
+ "Turn the power off and refer to the\n"
+ "Nintendo GameCube Instruction Booklet\n"
+ "for further instructions."
+ },
+ {
+ "\n\n\nEin Fehler ist aufgetreten.\n"
+ "Bitte schalten Sie den Nintendo GameCube\n"
+ "aus und lesen Sie die Bedienungsanleitung,\n"
+ "um weitere Informationen zu erhalten."
+ },
+ {
+ "\n\n\nUne erreur est survenue.\n"
+ "Eteignez la console et r\xE9" "f" "\xE9rez-vous au\n"
+ "manuel d'instructions Nintendo GameCube\n"
+ "pour de plus amples informations."
+ },
+ {
+ "\n\n\nSe ha producido un error.\n"
+ "Apaga la consola y consulta el manual\n"
+ "de instrucciones de Nintendo GameCube\n"
+ "para obtener m\xE1" "s informaci\xF3" "n."
+ },
+ {
+ "\n\n\nSi \xE8" " verificato un errore.\n"
+ "Spegni (OFF) e controlla il manuale\n"
+ "d'istruzioni del Nintendo GameCube\n"
+ "per ulteriori indicazioni."
+ },
+ {
+ "\n\n\nEr is een fout opgetreden.\n"
+ "Zet de Nintendo GameCube uit en\n"
+ "raadpleeg de handleiding van de\n"
+ "Nintendo GameCube voor nadere\n"
+ "instructies."
+ },
+};
+
+static void ShowMessage(void) {
+ const char* message;
+ GXColor bg = {0x00, 0x00, 0x00, 0x00};
+ GXColor fg = {0xFF, 0xFF, 0xFF, 0x00};
+
+ if (VIGetTvFormat() == VI_NTSC) {
+ if (OSGetFontEncode() == OS_FONT_ENCODE_SJIS) {
+ message = Japanese;
+ } else {
+ message = English;
+ }
+ } else {
+ message = Europe[OSGetLanguage()];
+ }
+
+ OSFatal(fg, bg, message);
+}
+
+int DVDSetAutoFatalMessaging(BOOL enable) {
+ BOOL enabled;
+ int prev;
+
+ enabled = OSDisableInterrupts();
+
+ prev = FatalFunc ? 1 : 0;
+ FatalFunc = enable ? ShowMessage : NULL;
+
+ OSRestoreInterrupts(enabled);
+ return prev;
+}
+
+void __DVDPrintFatalMessage(void) {
+ if (FatalFunc) {
+ FatalFunc();
+ }
+}
diff --git a/src/dolphin/dvd/dvderror.c b/src/dolphin/dvd/dvderror.c
new file mode 100644
index 00000000..a44c372d
--- /dev/null
+++ b/src/dolphin/dvd/dvderror.c
@@ -0,0 +1,74 @@
+#include "dolphin/dvd/dvderror.h"
+#include "dolphin/os/OS.h"
+
+static u32 ErrorTable[18] = {
+ 0x00000000,
+ 0x00023A00,
+ 0x00062800,
+ 0x00030200,
+ 0x00031100,
+ 0x00052000,
+ 0x00052001,
+ 0x00052100,
+ 0x00052400,
+ 0x00052401,
+ 0x00052402,
+ 0x000B5A01,
+ 0x00056300,
+ 0x00020401,
+ 0x00020400,
+ 0x00040800,
+ 0x00100007,
+ 0x00000000,
+};
+
+#define DIDNT_MATCH 29
+
+static u8 ErrorCode2Num(u32 errorCode) {
+ u32 i;
+
+ for (i = 0; i < 18; i++) {
+ if (errorCode == ErrorTable[i]) {
+ ASSERTLINE(0x49, i < DIDNT_MATCH);
+ return i;
+ }
+ }
+
+ if (errorCode >= 0x100000 && errorCode <= 0x100008) {
+ return 17;
+ }
+
+ return DIDNT_MATCH;
+}
+
+static u8 Convert(u32 error) {
+ u32 statusCode;
+ u32 errorCode;
+ u8 errorNum;
+
+ if (error == 0x01234567) {
+ return -1;
+ } else if (error == 0x01234568) {
+ return -2;
+ }
+
+ statusCode = (error >> 24) & 0xFF;
+ errorCode = error & 0x00FFFFFF;
+ errorNum = ErrorCode2Num(errorCode);
+ if (statusCode >= 6) {
+ statusCode = 6;
+ }
+
+ return statusCode * 30 + errorNum;
+}
+
+void __DVDStoreErrorCode(u32 error)
+{
+ OSSramEx* sram;
+ u8 num;
+
+ num = Convert(error);
+ sram = __OSLockSramEx();
+ sram->dvdErrorCode = num;
+ __OSUnlockSramEx(TRUE);
+}
diff --git a/src/dolphin/dvd/dvdfs.c b/src/dolphin/dvd/dvdfs.c
new file mode 100644
index 00000000..8ccb9f22
--- /dev/null
+++ b/src/dolphin/dvd/dvdfs.c
@@ -0,0 +1,664 @@
+#include "dolphin/dvd/dvdfs.h"
+#include "dolphin/dvd/dvdlow.h"
+#include "dolphin/os/OS.h"
+
+struct FSTEntry {
+ /* 0x00 */ u32 isDirAndStringOff;
+ /* 0x04 */ u32 parentOrPosition;
+ /* 0x08 */ u32 nextEntryOrLength;
+};
+
+// .sbss
+static struct OSBootInfo * BootInfo; // size: 0x4, address: 0x0
+static struct FSTEntry * FstStart; // size: 0x4, address: 0x4
+static char * FstStringStart; // size: 0x4, address: 0x8
+static unsigned long MaxEntryNum; // size: 0x4, address: 0xC
+static unsigned long currentDirectory; // size: 0x4, address: 0x10
+struct OSThreadQueue __DVDThreadQueue; // size: 0x8, address: 0x18
+unsigned long __DVDLongFileNameFlag; // size: 0x4, address: 0x14
+
+// functions
+static BOOL isSame(const char* path, const char* string);
+static u32 myStrncpy(char* dest, char* src, u32 maxlen);
+static u32 entryToPath(u32 entry, char* path, u32 maxlen);
+static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen);
+static void cbForReadAsync(s32 result, DVDCommandBlock* block);
+static void cbForReadSync();
+static void cbForSeekAsync(long result, struct DVDCommandBlock * block);
+static void cbForSeekSync();
+static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block);
+static void cbForPrepareStreamSync();
+
+void __DVDFSInit() {
+ BootInfo = (void*)OSPhysicalToCached(0);
+ FstStart = BootInfo->fst_location;
+ if (FstStart) {
+ MaxEntryNum = FstStart->nextEntryOrLength;
+ FstStringStart = (char*)FstStart + (MaxEntryNum * 0xC);
+ }
+}
+
+/* For convenience */
+#define entryIsDir(i) (((FstStart[i].isDirAndStringOff & 0xff000000) == 0) ? FALSE : TRUE)
+#define stringOff(i) (FstStart[i].isDirAndStringOff & ~0xff000000)
+#define parentDir(i) (FstStart[i].parentOrPosition)
+#define nextDir(i) (FstStart[i].nextEntryOrLength)
+#define filePosition(i) (FstStart[i].parentOrPosition)
+#define fileLength(i) (FstStart[i].nextEntryOrLength)
+
+static BOOL isSame(const char* path, const char* string) {
+ while (*string != '\0') {
+ if (tolower(*path++) != tolower(*string++)) {
+ return FALSE;
+ }
+ }
+
+ if ((*path == '/') || (*path == '\0')) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+int DVDConvertPathToEntrynum(const char* pathPtr) {
+ const char* ptr;
+ char* stringPtr;
+ BOOL isDir;
+ u32 length;
+ u32 dirLookAt;
+ u32 i;
+ const char* origPathPtr = pathPtr;
+ const char* extentionStart;
+ BOOL illegal;
+ BOOL extention;
+
+ ASSERTMSGLINE(0x133, pathPtr, "DVDConvertPathToEntrynum(): null pointer is specified ");
+
+ dirLookAt = currentDirectory;
+
+ while (1) {
+ if (*pathPtr == '\0') {
+ return (s32)dirLookAt;
+ } else if (*pathPtr == '/') {
+ dirLookAt = 0;
+ pathPtr++;
+ continue;
+ } else if (*pathPtr == '.') {
+ if (*(pathPtr + 1) == '.') {
+ if (*(pathPtr + 2) == '/') {
+ dirLookAt = parentDir(dirLookAt);
+ pathPtr += 3;
+ continue;
+ } else if (*(pathPtr + 2) == '\0') {
+ return (s32)parentDir(dirLookAt);
+ }
+ } else if (*(pathPtr + 1) == '/') {
+ pathPtr += 2;
+ continue;
+ } else if (*(pathPtr + 1) == '\0') {
+ return (s32)dirLookAt;
+ }
+ }
+
+ if (__DVDLongFileNameFlag == 0) {
+ extention = FALSE;
+ illegal = FALSE;
+
+ for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++) {
+ if (*ptr == '.') {
+ if ((ptr - pathPtr > 8) || (extention == TRUE)) {
+ illegal = TRUE;
+ break;
+ }
+ extention = TRUE;
+ extentionStart = ptr + 1;
+
+ } else if (*ptr == ' ')
+ illegal = TRUE;
+ }
+
+ if ((extention == TRUE) && (ptr - extentionStart > 3))
+ illegal = TRUE;
+
+ if (illegal)
+ OSPanic(__FILE__, 0x17B,
+ "DVDConvertEntrynumToPath(possibly DVDOpen or DVDChangeDir or DVDOpenDir): "
+ "specified directory or file (%s) doesn't match standard 8.3 format. This is a "
+ "temporary restriction and will be removed soon\n",
+ origPathPtr);
+ } else {
+ for (ptr = pathPtr; (*ptr != '\0') && (*ptr != '/'); ptr++)
+ ;
+ }
+
+ isDir = (*ptr == '\0') ? FALSE : TRUE;
+ length = (u32)(ptr - pathPtr);
+
+ ptr = pathPtr;
+
+ for (i = dirLookAt + 1; i < nextDir(dirLookAt); i = entryIsDir(i) ? nextDir(i) : (i + 1)) {
+ if ((entryIsDir(i) == FALSE) && (isDir == TRUE)) {
+ continue;
+ }
+
+ stringPtr = FstStringStart + stringOff(i);
+
+ if (isSame(ptr, stringPtr) == TRUE) {
+ goto next_hier;
+ }
+ }
+
+ return -1;
+
+next_hier:
+ if (!isDir) {
+ return (s32)i;
+ }
+
+ dirLookAt = i;
+ pathPtr += length + 1;
+ }
+}
+
+BOOL DVDFastOpen(s32 entrynum, DVDFileInfo* fileInfo) {
+ ASSERTMSGLINE(0x1BC, fileInfo, "DVDFastOpen(): null pointer is specified to file info address ");
+ ASSERTMSG1LINE(0x1BF, (entrynum >= 0) && ((u32) entrynum < (u32) MaxEntryNum), "DVDFastOpen(): specified entry number '%d' is out of range ", entrynum);
+ ASSERTMSG1LINE(0x1C2, !entryIsDir(entrynum), "DVDFastOpen(): entry number '%d' is assigned to a directory ", entrynum);
+
+ if ((entrynum < 0) || (entrynum >= MaxEntryNum) || entryIsDir(entrynum)) {
+ return FALSE;
+ }
+
+ fileInfo->start_address = filePosition(entrynum);
+ fileInfo->length = fileLength(entrynum);
+ fileInfo->callback = (DVDCallback)NULL;
+ fileInfo->block.state = DVD_STATE_END;
+
+ return TRUE;
+}
+
+BOOL DVDOpen(const char* fileName, DVDFileInfo* fileInfo) {
+ s32 entry;
+ char currentDir[128];
+
+ ASSERTMSGLINE(0x1E0, fileName, "DVDOpen(): null pointer is specified to file name ");
+ ASSERTMSGLINE(0x1E1, fileInfo, "DVDOpen(): null pointer is specified to file info address ");
+
+ entry = DVDConvertPathToEntrynum(fileName);
+
+ if (0 > entry) {
+ DVDGetCurrentDir(currentDir, 128);
+ OSReport("Warning: DVDOpen(): file '%s' was not found under %s.\n", fileName, currentDir);
+ return FALSE;
+ }
+
+ if (entryIsDir(entry)) {
+ ASSERTMSG1LINE(0x1EF, !entryIsDir(entry), "DVDOpen(): directory '%s' is specified as a filename ", fileName);
+ return FALSE;
+ }
+
+ fileInfo->start_address = filePosition(entry);
+ fileInfo->length = fileLength(entry);
+ fileInfo->callback = (DVDCallback)NULL;
+ fileInfo->block.state = DVD_STATE_END;
+
+ return TRUE;
+}
+
+BOOL DVDClose(DVDFileInfo* fileInfo) {
+ ASSERTMSGLINE(0x207, fileInfo, "DVDClose(): null pointer is specified to file info address ");
+ DVDCancel(&(fileInfo->block));
+ return TRUE;
+}
+
+static u32 myStrncpy(char* dest, char* src, u32 maxlen) {
+ u32 i = maxlen;
+
+ while ((i > 0) && (*src != 0)) {
+ *dest++ = *src++;
+ i--;
+ }
+
+ return (maxlen - i);
+}
+
+static u32 entryToPath(u32 entry, char* path, u32 maxlen) {
+ char* name;
+ u32 loc;
+
+ if (entry == 0) {
+ return 0;
+ }
+
+ name = FstStringStart + stringOff(entry);
+
+ loc = entryToPath(parentDir(entry), path, maxlen);
+
+ if (loc == maxlen) {
+ return loc;
+ }
+
+ *(path + loc++) = '/';
+
+ loc += myStrncpy(path + loc, name, maxlen - loc);
+
+ return loc;
+}
+
+static BOOL DVDConvertEntrynumToPath(s32 entrynum, char* path, u32 maxlen) {
+ u32 loc;
+
+ ASSERTMSG1LINE(0x263, (entrynum >= 0) && (entrynum < MaxEntryNum), "DVDConvertEntrynumToPath: specified entrynum(%d) is out of range ", entrynum);
+ ASSERTMSG1LINE(0x265, maxlen > 1, "DVDConvertEntrynumToPath: maxlen should be more than 1 (%d is specified)", maxlen);
+ ASSERTMSGLINE(0x26A, entryIsDir(entrynum), "DVDConvertEntrynumToPath: cannot convert an entry num for a file to path ");
+
+ loc = entryToPath((u32)entrynum, path, maxlen);
+
+ if (loc == maxlen) {
+ path[maxlen - 1] = '\0';
+ return FALSE;
+ }
+
+ if (entryIsDir(entrynum)) {
+ if (loc == maxlen - 1) {
+ path[loc] = '\0';
+ return FALSE;
+ }
+
+ path[loc++] = '/';
+ }
+
+ path[loc] = '\0';
+ return TRUE;
+}
+
+BOOL DVDGetCurrentDir(char* path, u32 maxlen) {
+ ASSERTMSG1LINE(0x294, (maxlen > 1), "DVDGetCurrentDir: maxlen should be more than 1 (%d is specified)", maxlen);
+ return DVDConvertEntrynumToPath((s32)currentDirectory, path, maxlen);
+}
+
+BOOL DVDChangeDir(const char* dirName) {
+ s32 entry;
+ char currentDir[128];
+
+ ASSERTMSGLINE(0x2AA, dirName, "DVDChangeDir(): null pointer is specified to directory name ");
+ entry = DVDConvertPathToEntrynum(dirName);
+ ASSERTMSG2LINE(0x2B2, entry >= 0, "DVDChangeDir(): directory '%s' is not found under %s ", dirName, (DVDGetCurrentDir(currentDir, 128), currentDir));
+ ASSERTMSG1LINE(0x2B6, entryIsDir(entry), "DVDChangeDir(): file '%s' is specified as a directory name ", dirName);
+
+ if ((entry < 0) || (entryIsDir(entry) == FALSE)) {
+ return FALSE;
+ }
+
+ currentDirectory = (u32)entry;
+
+ return TRUE;
+}
+
+BOOL DVDReadAsyncPrio(DVDFileInfo* fileInfo, void* addr, s32 length, s32 offset,
+ DVDCallback callback, s32 prio) {
+
+ ASSERTMSGLINE(0x2D5, fileInfo, "DVDReadAsync(): null pointer is specified to file info address ");
+ ASSERTMSGLINE(0x2D6, addr, "DVDReadAsync(): null pointer is specified to addr ");
+ ASSERTMSGLINE(0x2DA, !OFFSET(addr, 32), "DVDReadAsync(): address must be aligned with 32 byte boundaries ");
+ ASSERTMSGLINE(0x2DC, !(length & 0x1F), "DVDReadAsync(): length must be multiple of 32 byte ");
+ ASSERTMSGLINE(0x2DE, !(offset & 3), "DVDReadAsync(): offset must be multiple of 4 byte ");
+
+ if (!((0 <= offset) && (offset < fileInfo->length))) {
+ OSPanic(__FILE__, 0x2E6, "DVDReadAsync(): specified area is out of the file ");
+ }
+
+ if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
+ OSPanic(__FILE__, 0x2EC, "DVDReadAsync(): specified area is out of the file ");
+ }
+
+ fileInfo->callback = callback;
+ DVDReadAbsAsyncPrio(&(fileInfo->block), addr, length, (s32)(fileInfo->start_address + offset),
+ cbForReadAsync, prio);
+
+ return TRUE;
+}
+#ifndef offsetof
+#define offsetof(type, memb) ((u32) & ((type*)0)->memb)
+#endif
+
+static void cbForReadAsync(s32 result, DVDCommandBlock* block) {
+ DVDFileInfo* fileInfo;
+
+ fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, block));
+ ASSERTLINE(0x2FB, (void*) &fileInfo->block == (void*) block);
+ if (fileInfo->callback) {
+ (fileInfo->callback)(result, fileInfo);
+ }
+}
+
+int DVDReadPrio(struct DVDFileInfo * fileInfo, void * addr, long length, long offset, long prio) {
+ int result;
+ struct DVDCommandBlock * block;
+ long state;
+ int enabled;
+ long retVal;
+
+ ASSERTMSGLINE(0x31B, fileInfo, "DVDRead(): null pointer is specified to file info address ");
+ ASSERTMSGLINE(0x31C, addr, "DVDRead(): null pointer is specified to addr ");
+ ASSERTMSGLINE(0x320, !OFFSET(addr, 32), "DVDRead(): address must be aligned with 32 byte boundaries ");
+ ASSERTMSGLINE(0x322, !(length & 0x1F), "DVDRead(): length must be multiple of 32 byte ");
+ ASSERTMSGLINE(0x324, !(offset & 3), "DVDRead(): offset must be multiple of 4 byte ");
+
+ if (!((0 <= offset) && (offset < fileInfo->length))) {
+ OSPanic(__FILE__, 0x32C, "DVDRead(): specified area is out of the file ");
+ }
+
+ if (!((0 <= offset + length) && (offset + length < fileInfo->length + DVD_MIN_TRANSFER_SIZE))) {
+ OSPanic(__FILE__, 0x332, "DVDRead(): specified area is out of the file ");
+ }
+
+ block = &fileInfo->block;
+ result = DVDReadAbsAsyncPrio(block, addr, length, fileInfo->start_address + offset, cbForReadSync, prio);
+ if (result == 0) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = ((volatile DVDCommandBlock*)block)->state;
+ if (state == 0) {
+ retVal = (s32)block->transferred_size;
+ break;
+ } else if (state == -1) {
+ retVal = -1;
+ break;
+ } else if (state == 10) {
+ retVal = -3;
+ break;
+ }
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForReadSync() {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+int DVDSeekAsyncPrio(struct DVDFileInfo * fileInfo, long offset, void (* callback)(long, struct DVDFileInfo *), long prio) {
+ ASSERTMSGLINE(0x377, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
+ ASSERTMSGLINE(0x37B, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
+
+ if (!((0 <= offset) && (offset < fileInfo->length))) {
+ OSPanic(__FILE__, 0x380, "DVDSeek(): offset is out of the file ");
+ }
+
+ fileInfo->callback = callback;
+ DVDSeekAbsAsyncPrio(&fileInfo->block, (u32)(char*)fileInfo->start_address + offset, cbForSeekAsync, prio);
+ return 1;
+}
+
+static void cbForSeekAsync(long result, struct DVDCommandBlock * block) {
+ struct DVDFileInfo * fileInfo;
+
+ fileInfo = (struct DVDFileInfo *)&block->next;
+ ASSERTLINE(0x392, (void*) &fileInfo->block == (void*) block);
+ if (fileInfo->callback) {
+ (fileInfo->callback)(result, fileInfo);
+ }
+}
+
+long DVDSeekPrio(struct DVDFileInfo * fileInfo, long offset, long prio) {
+ int result;
+ struct DVDCommandBlock * block;
+ long state;
+ int enabled;
+ long retVal;
+
+ ASSERTMSGLINE(0x3B0, fileInfo, "DVDSeek(): null pointer is specified to file info address ");
+ ASSERTMSGLINE(0x3B4, !(offset & 3), "DVDSeek(): offset must be multiple of 4 byte ");
+ ASSERTMSGLINE(0x3B8, (offset >= 0) && ((u32) offset < (u32) fileInfo->length), "DVDSeek(): offset is out of the file ");
+
+ block = &fileInfo->block;
+ result = DVDSeekAbsAsyncPrio(block, (u32)(char*)fileInfo->start_address + offset, cbForSeekSync, prio);
+ if (!result) {
+ return -1;
+ }
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = ((volatile DVDCommandBlock*)block)->state;
+ if (state == 0) {
+ retVal = 0;
+ break;
+ } else if (state == -1) {
+ retVal = -1;
+ break;
+ } else if (state == 10) {
+ retVal = -3;
+ break;
+ }
+ OSSleepThread(&__DVDThreadQueue);
+ }
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForSeekSync() {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+// long DVDGetFileInfoStatus(struct DVDFileInfo * fileInfo) {
+// return DVDGetCommandBlockStatus(&fileInfo->block);
+// }
+
+BOOL DVDFastOpenDir(s32 entrynum, DVDDirectory * dir) {
+ ASSERTMSGLINE(0x40D, dir, "DVDFastOpenDir(): null pointer is specified to dir structure address ");
+ ASSERTMSG1LINE(0x410, entrynum >= 0 && entrynum < MaxEntryNum, "DVDFastOpenDir(): specified entry number \'%d\' is out of range ", entrynum);
+ ASSERTMSG1LINE(0x413, entryIsDir(entrynum), "DVDFastOpenDir(): entry number \'%d\' is assigned to a file ", entrynum);
+
+ if (entrynum < 0 || entrynum >= MaxEntryNum || !entryIsDir(entrynum)) {
+ return FALSE;
+ }
+
+ dir->entry_number = entrynum;
+ dir->location = entrynum + 1;
+ dir->next = FstStart[entrynum].nextEntryOrLength;
+ return TRUE;
+}
+
+BOOL DVDOpenDir(const char* dirName, DVDDirectory* dir) {
+ long entry;
+ char currentDir[128];
+
+ ASSERTMSGLINE(0x430, dirName, "DVDOpendir(): null pointer is specified to directory name ");
+ ASSERTMSGLINE(0x431, dir, "DVDOpenDir(): null pointer is specified to dir structure address ");
+ entry = DVDConvertPathToEntrynum(dirName);
+ if (entry < 0) {
+ DVDGetCurrentDir(currentDir, sizeof(currentDir));
+ OSReport("Warning: DVDOpenDir(): file \'%s\' was not found under %s.\n", dirName, currentDir);
+ return FALSE;
+ }
+
+ if (!entryIsDir(entry)) {
+ ASSERTMSG1LINE(0x43F, entryIsDir(entry), "DVDOpendir(): file \'%s\' is specified as a directory name ", dirName);
+ return FALSE;
+ }
+
+ dir->entry_number = entry;
+ dir->location = entry + 1;
+ dir->next = nextDir(entry);
+ return TRUE;
+}
+
+int DVDReadDir(DVDDirectory * dir, DVDDirectoryEntry* dirent) {
+ unsigned long loc;
+
+ loc = dir->location;
+ if ((loc <= (u32) dir->entry_number) || ((u32) dir->next <= loc)) {
+ return 0;
+ }
+ dirent->entry_number = loc;
+ dirent->is_directory = entryIsDir(loc);
+ dirent->name = FstStringStart + stringOff(loc);
+ dir->location = entryIsDir(loc) ? nextDir(loc) : loc + 1;
+ return 1;
+}
+
+int DVDCloseDir(DVDDirectory* dir) {
+ return 1;
+}
+
+void * DVDGetFSTLocation() {
+ return BootInfo->fst_location;
+}
+
+#define RoundUp32KB(x) (((u32)(x) + 32 * 1024 - 1) & ~(32 * 1024 - 1))
+#define Is32KBAligned(x) (((u32)(x) & (32 * 1024 - 1)) == 0)
+
+BOOL DVDPrepareStreamAsync(DVDFileInfo* fileInfo, u32 length, u32 offset, DVDCallback callback) {
+ u32 start;
+
+ ASSERTMSGLINE(0x49C, fileInfo, "DVDPrepareStreamAsync(): NULL file info was specified");
+
+ start = fileInfo->start_address + offset;
+
+ if (!Is32KBAligned(start)) {
+ OSPanic(__FILE__, 0x4A5,
+ "DVDPrepareStreamAsync(): Specified start address (filestart(0x%x) + offset(0x%x)) is "
+ "not 32KB aligned",
+ fileInfo->start_address, offset);
+ }
+
+ if (length == 0)
+ length = fileInfo->length - offset;
+
+ if (!Is32KBAligned(length)) {
+ OSPanic(__FILE__, 0x4AF,
+ "DVDPrepareStreamAsync(): Specified length (0x%x) is not a multiple of 32768(32*1024)",
+ length);
+ }
+
+ if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) {
+ OSPanic(__FILE__, 0x4B7,
+ "DVDPrepareStreamAsync(): The area specified (offset(0x%x), length(0x%x)) is out of "
+ "the file",
+ offset, length);
+ }
+
+ fileInfo->callback = callback;
+ return DVDPrepareStreamAbsAsync(&(fileInfo->block), length, fileInfo->start_address + offset,
+ cbForPrepareStreamAsync);
+}
+
+static void cbForPrepareStreamAsync(s32 result, DVDCommandBlock* block) {
+ DVDFileInfo* fileInfo;
+
+ fileInfo = (DVDFileInfo*)((char*)block - offsetof(DVDFileInfo, block));
+
+ ASSERTLINE(0x4C7, (void*) &fileInfo->block == (void*) block);
+
+ if (fileInfo->callback) {
+ (fileInfo->callback)(result, fileInfo);
+ }
+}
+
+/* This is based on the revolution SDK, these may not match in all cases */
+s32 DVDPrepareStream(DVDFileInfo* fileInfo, u32 length, u32 offset) {
+ BOOL result;
+ DVDCommandBlock* block;
+ s32 state;
+ BOOL enabled;
+ s32 retVal;
+ u32 start;
+
+ ASSERTMSGLINE(0x4E9, fileInfo, "DVDPrepareStream(): NULL file info was specified");
+
+ start = fileInfo->start_address + offset;
+
+ if (!Is32KBAligned(start)) {
+ OSPanic(__FILE__, 0x4EF,
+ "DVDPrepareStream(): Specified start address (filestart(0x%x) + offset(0x%x)) is not "
+ "32KB aligned",
+ fileInfo->start_address, offset);
+ }
+
+ if (length == 0)
+ length = fileInfo->length - offset;
+
+ if (!Is32KBAligned(length)) {
+ OSPanic(__FILE__, 0x4F9,
+ "DVDPrepareStream(): Specified length (0x%x) is not a multiple of 32768(32*1024)",
+ length);
+ }
+
+ if (!((offset < fileInfo->length) && (offset + length <= fileInfo->length))) {
+ OSPanic(
+ __FILE__, 0x501,
+ "DVDPrepareStream(): The area specified (offset(0x%x), length(0x%x)) is out of the file",
+ offset, length);
+ }
+
+ block = &(fileInfo->block);
+ result = DVDPrepareStreamAbsAsync(block, length, start, cbForPrepareStreamSync);
+
+ if (result == FALSE) {
+ return -1;
+ }
+
+ enabled = OSDisableInterrupts();
+
+ while(1) {
+ state = ((volatile DVDCommandBlock*)block)->state;
+
+ if (state == DVD_STATE_END) {
+ retVal = 0;
+ break;
+ }
+ if (state == DVD_STATE_FATAL_ERROR) {
+ retVal = DVD_RESULT_FATAL_ERROR;
+ break;
+ }
+ if (state == DVD_STATE_CANCELED) {
+ retVal = DVD_RESULT_CANCELED;
+ break;
+ }
+
+ OSSleepThread(&__DVDThreadQueue);
+ }
+
+ OSRestoreInterrupts(enabled);
+ return retVal;
+}
+
+static void cbForPrepareStreamSync(s32 result, DVDCommandBlock* block) {
+ OSWakeupThread(&__DVDThreadQueue);
+}
+
+s32 DVDGetTransferredSize(DVDFileInfo* fileinfo) {
+ s32 bytes;
+ DVDCommandBlock* cb;
+
+ cb = &(fileinfo->block);
+
+ switch (cb->state) {
+ case DVD_STATE_COVER_CLOSED:
+ case DVD_STATE_NO_DISK:
+ case DVD_STATE_COVER_OPEN:
+ case DVD_STATE_WRONG_DISK:
+ case DVD_STATE_FATAL_ERROR:
+ case DVD_STATE_MOTOR_STOPPED:
+ case DVD_STATE_CANCELED:
+ case DVD_STATE_RETRY:
+ case DVD_STATE_END:
+ bytes = (s32)cb->transferred_size;
+ break;
+ case DVD_STATE_WAITING:
+ bytes = 0;
+ break;
+ case DVD_STATE_BUSY:
+ bytes = (s32)(cb->transferred_size + (cb->current_transfer_size - __DIRegs[6]));
+ break;
+ default:
+ ASSERTMSG1LINE(0x556, FALSE, "DVDGetTransferredSize(): Illegal state (%d)", cb->state);
+ break;
+ }
+ return bytes;
+}
diff --git a/src/dolphin/dvd/dvdidutils.c b/src/dolphin/dvd/dvdidutils.c
new file mode 100644
index 00000000..5493f537
--- /dev/null
+++ b/src/dolphin/dvd/dvdidutils.c
@@ -0,0 +1,95 @@
+#include "dolphin/dvd/dvdidutils.h"
+#include "dolphin/os/OS.h"
+
+static u32 strnlen(const char* str, u32 maxlen) {
+ u32 i;
+
+ for (i = 0; i < maxlen; i++) {
+ if (*str++ == 0) {
+ return i;
+ }
+ }
+
+ return maxlen;
+}
+
+int DVDCompareDiskID(DVDDiskID* id1, DVDDiskID* id2) {
+#ifdef DEBUG
+ const char* game1;
+ const char* game2;
+ const char* company1;
+ const char* company2;
+ u8 diskNum1;
+ u8 diskNum2;
+ u8 version1;
+ u8 version2;
+ u32 length;
+
+ ASSERTMSGLINE(64, id1, "DVDCompareDiskID(): Specified id1 is NULL\n");
+ ASSERTMSGLINE(65, id2, "DVDCompareDiskID(): Specified id2 is NULL\n");
+
+ game1 = id1->game_name;
+ game2 = id2->game_name;
+ company1 = id1->company;
+ company2 = id2->company;
+ diskNum1 = id1->disk_number;
+ diskNum2 = id2->disk_number;
+ version1 = id1->game_version;
+ version2 = id2->game_version;
+
+ length = strnlen(game1, sizeof(game1));
+ ASSERTMSGLINE(78, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id1 is neither NULL nor 4 character long\n");
+ ASSERTMSGLINE(79, company1, "DVDCompareDiskID(): Specified company name for id1 is NULL\n");
+ ASSERTMSGLINE(80, company1[1] != 0, "DVDCompareDiskID(): Specified company name for id1 is not 2 character long\n");
+ ASSERTMSGLINE(81, diskNum1 == 0xFF || ((diskNum1 / 16) < 10 && diskNum1 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id1 is neither 0xff nor a BCD number");
+ ASSERTMSGLINE(82, version1 == 0xFF || ((version1 / 16) < 10 && version1 % 16 < 10), "DVDCompareDiskID(): Specified version number for id1 is neither 0xff nor a BCD number");
+
+ length = strnlen(game2, sizeof(game2));
+ ASSERTMSGLINE(85, length == 0 || length == 4, "DVDCompareDiskID(): Specified game name for id2 is neither NULL nor 4 character long\n");
+ ASSERTMSGLINE(86, company2, "DVDCompareDiskID(): Specified company name for id2 is NULL\n");
+ ASSERTMSGLINE(87, company2[1] != 0, "DVDCompareDiskID(): Specified company name for id2 is not 2 character long\n");
+ ASSERTMSGLINE(88, diskNum2 == 0xFF || ((diskNum2 / 16) < 10 && diskNum2 % 16 < 10), "DVDCompareDiskID(): Specified disk number for id2 is neither 0xff nor a BCD number");
+ ASSERTMSGLINE(89, version2 == 0xFF || ((version2 / 16) < 10 && version2 % 16 < 10), "DVDCompareDiskID(): Specified version number for id2 is neither 0xff nor a BCD number");
+#endif
+
+ if (id1->game_name[0] != 0 && id2->game_name[0] != 0 && strncmp(id1->game_name, id2->game_name, 4) != 0) {
+ return 0;
+ }
+
+ if (id1->company[0] == 0 || id2->company[0] == 0 || strncmp(id1->company, id2->company, 2) != 0) {
+ return 0;
+ }
+
+ if (id1->disk_number != 0xFF && id2->disk_number != 0xFF && id1->disk_number != id2->disk_number) {
+ return 0;
+ }
+
+ if (id1->game_version != 0xFF && id2->game_version != 0xFF && id1->game_version != id2->game_version) {
+ return 0;
+ }
+
+ return 1;
+}
+
+DVDDiskID* DVDGenerateDiskID(DVDDiskID* id, const char* game, const char* company, u8 diskNum, u8 version) {
+ ASSERTMSGLINE(123, id, "DVDGenerateDiskID(): Specified id is NULL\n");
+ ASSERTMSGLINE(124, game == NULL || strlen(game) == 4, "DVDGenerateDiskID(): Specified game name is neither NULL nor 4 character long\n");
+ ASSERTMSGLINE(125, company, "DVDGenerateDiskID(): Specified company name is NULL\n");
+ ASSERTMSGLINE(126, strlen(company) == 2, "DVDGenerateDiskID(): Specified company name is not 2 character long\n");
+ ASSERTMSGLINE(127, diskNum == 0xFF || ((diskNum / 16) < 10 && diskNum % 16 < 10), "DVDGenerateDiskID(): Specified disk number is neither 0xff nor a BCD number");
+ ASSERTMSGLINE(128, version == 0xFF || ((version / 16) < 10 && version % 16 < 10), "DVDGenerateDiskID(): Specified version number is neither 0xff nor a BCD number");
+
+ memset(id, 0, sizeof(DVDDiskID));
+
+ if (game != NULL) {
+ strncpy(id->game_name, game, 4);
+ }
+
+ if (company != NULL) {
+ strncpy(id->company, company, 2);
+ }
+
+ id->disk_number = diskNum;
+ id->game_version = version;
+ return id;
+}
diff --git a/src/dolphin/dvd/dvdlow.c b/src/dolphin/dvd/dvdlow.c
new file mode 100644
index 00000000..8a8fde43
--- /dev/null
+++ b/src/dolphin/dvd/dvdlow.c
@@ -0,0 +1,544 @@
+#include "dolphin/dvd/dvdlow.h"
+#include "dolphin/os/OS.h"
+
+static BOOL FirstRead = TRUE;
+static volatile BOOL StopAtNextInt = FALSE;
+static u32 LastLength = 0;
+static DVDLowCallback Callback = NULL;
+static DVDLowCallback ResetCoverCallback = NULL;
+static volatile OSTime LastResetEnd = 0;
+static volatile u32 ResetOccurred = FALSE;
+static volatile BOOL WaitingCoverClose = FALSE;
+static volatile BOOL Breaking = FALSE;
+static volatile u32 WorkAroundType = 0;
+static u32 WorkAroundSeekLocation = 0;
+static volatile OSTime LastReadFinished = 0;
+static OSTime LastReadIssued = 0;
+static volatile BOOL LastCommandWasRead = FALSE;
+static volatile u32 NextCommandNumber = 0;
+
+typedef struct {
+ void* addr;
+ u32 length;
+ u32 offset;
+} DVDBuffer;
+
+typedef struct {
+ s32 cmd;
+ void* addr;
+ u32 length;
+ u32 offset;
+ DVDLowCallback callback;
+} DVDCommand;
+
+static DVDCommand CommandList[3];
+static OSAlarm AlarmForWA;
+static OSAlarm AlarmForTimeout;
+static OSAlarm AlarmForBreak;
+static DVDBuffer Prev;
+static DVDBuffer Curr;
+
+void __DVDInitWA()
+{
+ NextCommandNumber = 0;
+ CommandList[0].cmd = -1;
+ __DVDLowSetWAType(0, 0);
+ OSInitAlarm();
+}
+
+static void Read(void* addr, u32 length, u32 offset, DVDLowCallback callback);
+
+static BOOL ProcessNextCommand()
+{
+ s32 n = NextCommandNumber;
+
+ ASSERTLINE(0x127, n < 3);
+ if (CommandList[n].cmd == 1) {
+ ++NextCommandNumber;
+ Read(CommandList[n].addr, CommandList[n].length, CommandList[n].offset, CommandList[n].callback);
+ return TRUE;
+ } else if (CommandList[n].cmd == 2) {
+ ++NextCommandNumber;
+ DVDLowSeek(CommandList[n].offset, CommandList[n].callback);
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+void __DVDInterruptHandler(__OSInterrupt interrupt, OSContext* context)
+{
+ DVDLowCallback cb;
+ OSContext exceptionContext;
+ u32 cause = 0;
+ u32 reg;
+ u32 intr;
+ u32 mask;
+
+ if (LastCommandWasRead) {
+ LastReadFinished = __OSGetSystemTime();
+ FirstRead = FALSE;
+ Prev.addr = Curr.addr;
+ Prev.length = Curr.length;
+ Prev.offset = Curr.offset;
+ if (StopAtNextInt == TRUE) {
+ cause |= 8;
+ }
+ }
+
+ LastCommandWasRead = FALSE;
+ StopAtNextInt = FALSE;
+ reg = __DIRegs[0];
+ mask = reg & 0x2a;
+ intr = (reg & 0x54) & (mask << 1);
+
+ if (intr & 0x40) {
+ cause |= 8;
+ }
+
+ if (intr & 0x10) {
+ cause |= 1;
+ }
+
+ if (intr & 4) {
+ cause |= 2;
+ }
+
+ if (cause) {
+ ResetOccurred = FALSE;
+ OSCancelAlarm(&AlarmForTimeout);
+ }
+
+ __DIRegs[0] = intr | mask;
+
+ if (ResetOccurred && (__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(200)) {
+ reg = __DIRegs[1];
+ mask = reg & 0x2;
+ intr = (reg & 4) & (mask << 1);
+ if (intr & 4) {
+ if (ResetCoverCallback) {
+ ResetCoverCallback(4);
+ }
+ ResetCoverCallback = NULL;
+ }
+
+ __DIRegs[1] = __DIRegs[1];
+ } else if (WaitingCoverClose) {
+ reg = __DIRegs[1];
+ mask = reg & 2;
+ intr = (reg & 4) & (mask << 1);
+
+ if (intr & 4) {
+ cause |= 4;
+ }
+
+ __DIRegs[1] = intr | mask;
+ WaitingCoverClose = FALSE;
+ } else {
+ __DIRegs[1] = 0;
+ }
+
+ if ((cause & 8) && !Breaking) {
+ cause &= ~8;
+ }
+
+ if ((cause & 1)) {
+ if (ProcessNextCommand()) {
+ return;
+ }
+ } else {
+ CommandList[0].cmd = -1;
+ NextCommandNumber = 0;
+ }
+
+ OSClearContext(&exceptionContext);
+ OSSetCurrentContext(&exceptionContext);
+
+ if (cause) {
+ cb = Callback;
+ Callback = NULL;
+ if (cb) {
+ cb(cause);
+ }
+
+ Breaking = FALSE;
+ }
+
+ OSClearContext(&exceptionContext);
+ OSSetCurrentContext(context);
+}
+
+static void AlarmHandler(OSAlarm* alarm, OSContext* context) {
+ BOOL processed = ProcessNextCommand();
+
+ ASSERTLINE(0x28A, processed);
+}
+
+static void AlarmHandlerForTimeout(OSAlarm* alarm, OSContext* context)
+{
+ OSContext tmpContext;
+ DVDLowCallback callback;
+ __OSMaskInterrupts(0x400);
+ OSClearContext(&tmpContext);
+ OSSetCurrentContext(&tmpContext);
+ callback = Callback;
+ Callback = NULL;
+ if (callback) {
+ callback(0x10);
+ }
+ OSClearContext(&tmpContext);
+ OSSetCurrentContext(context);
+}
+
+static void SetTimeoutAlarm(OSTime timeout)
+{
+ OSCreateAlarm(&AlarmForTimeout);
+ OSSetAlarm(&AlarmForTimeout, timeout, AlarmHandlerForTimeout);
+}
+
+static void Read(void* addr, u32 length, u32 offset, DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ LastCommandWasRead = TRUE;
+ LastReadIssued = __OSGetSystemTime();
+
+ __DIRegs[2] = 0xa8000000;
+ __DIRegs[3] = offset / 4;
+ __DIRegs[4] = length;
+ __DIRegs[5] = (u32)addr;
+ __DIRegs[6] = length;
+ LastLength = length;
+ __DIRegs[7] = 3;
+
+ if (length > 0xa00000) {
+ SetTimeoutAlarm(OSSecondsToTicks(20));
+ } else {
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ }
+}
+
+static BOOL AudioBufferOn(void)
+{
+ DVDDiskID* id;
+
+ id = DVDGetCurrentDiskID();
+ if (id->is_streaming) {
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static BOOL HitCache(DVDBuffer* cur, DVDBuffer* prev)
+{
+ u32 uVar1 = (prev->offset + prev->length - 1) >> 15;
+ u32 uVar2 = (cur->offset >> 15);
+ u32 iVar3 = AudioBufferOn() ? 5 : 15;
+
+ if ((uVar2 > uVar1 - 2) || (uVar2 < uVar1 + iVar3 + 3)) {
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void DoJustRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
+{
+ CommandList[0].cmd = -1;
+ NextCommandNumber = 0;
+ Read(addr, length, offset, callback);
+}
+
+static void SeekTwiceBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
+{
+ u32 newOffset;
+ if ((offset & ~0x7FFF) == 0) {
+ newOffset = 0;
+ } else {
+ newOffset = (offset & ~0x7FFF) + WorkAroundSeekLocation;
+ }
+ CommandList[0].cmd = 2;
+ CommandList[0].offset = newOffset;
+ CommandList[0].callback = callback;
+ CommandList[1].cmd = 1;
+ CommandList[1].addr = addr;
+ CommandList[1].length = length;
+ CommandList[1].offset = offset;
+ CommandList[1].callback = callback;
+ CommandList[2].cmd = -1;
+ NextCommandNumber = 0;
+ DVDLowSeek(newOffset, callback);
+}
+
+static void WaitBeforeRead(void* addr, u32 length, u32 offset, DVDLowCallback callback, OSTime timeout)
+{
+ CommandList[0].cmd = 1;
+ CommandList[0].addr = addr;
+ CommandList[0].length = length;
+ CommandList[0].offset = offset;
+ CommandList[0].callback = callback;
+ CommandList[1].cmd = -1;
+ NextCommandNumber = 0;
+ OSCreateAlarm(&AlarmForWA);
+ OSSetAlarm(&AlarmForWA, timeout, AlarmHandler);
+}
+
+BOOL DVDLowRead(void* addr, u32 length, u32 offset, DVDLowCallback callback)
+{
+ u32 blockNumOfPrevEnd;
+ u32 blockNumOfCurrStart;
+ OSTime diff;
+
+ ASSERTMSGLINE(0x341, (((u32)addr) & 31) == 0, "DVDLowRead(): address must be aligned with 32 byte boundary.");
+ ASSERTMSGLINE(0x342, (length & 31) == 0, "DVDLowRead(): length must be a multiple of 32.");
+ ASSERTMSGLINE(0x343, (offset & 3) == 0, "DVDLowRead(): offset must be a multiple of 4.");
+ ASSERTMSGLINE(0x345, length != 0, "DVD read: 0 was specified to length of the read\n");
+
+ __DIRegs[6] = length;
+ Curr.addr = addr;
+ Curr.length = length;
+ Curr.offset = offset;
+
+ if (WorkAroundType == 0) {
+ DoJustRead(addr, length, offset, callback);
+ } else if (WorkAroundType == 1) {
+ if (FirstRead) {
+ SeekTwiceBeforeRead(addr, length, offset, callback);
+ } else {
+ if (!HitCache(&Curr, &Prev)) {
+ DoJustRead(addr, length, offset, callback);
+ } else {
+ blockNumOfPrevEnd = (u32)((Prev.offset + Prev.length - 1) >> 15) & 0x1FFFF;
+ blockNumOfCurrStart = (u32)((Curr.offset >> 15) & 0x1FFFF);
+ if (blockNumOfPrevEnd == blockNumOfCurrStart || blockNumOfPrevEnd + 1 == blockNumOfCurrStart) {
+ diff = __OSGetSystemTime() - LastReadFinished;
+ if (OSMillisecondsToTicks(5) < diff) {
+ DoJustRead(addr, length, offset, callback);
+ } else {
+ WaitBeforeRead(addr, length, offset, callback, OSMillisecondsToTicks(5) - diff + OSMicrosecondsToTicks(500));
+ }
+ } else {
+ SeekTwiceBeforeRead(addr, length, offset, callback);
+ }
+ }
+ }
+ } else {
+ ASSERTLINE(0x380, FALSE);
+ }
+
+ return TRUE;
+}
+
+BOOL DVDLowSeek(u32 offset, DVDLowCallback callback)
+{
+ ASSERTMSGLINE(0x394, (offset & 3) == 0, "DVDLowSeek(): offset must be a multiple of 4.");
+
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = 0xab000000;
+ __DIRegs[3] = offset / 4;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowWaitCoverClose(DVDLowCallback callback)
+{
+ Callback = callback;
+ WaitingCoverClose = TRUE;
+ StopAtNextInt = FALSE;
+ __DIRegs[1] = 2;
+ return TRUE;
+}
+
+BOOL DVDLowReadDiskID(DVDDiskID* diskID, DVDLowCallback callback)
+{
+ ASSERTMSGLINE(0x3d2, (((u32)diskID) & 31) == 0, "DVDLowReadID(): id must be aligned with 32 byte boundary.");
+
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = 0xa8000040;
+ __DIRegs[3] = 0;
+ __DIRegs[4] = sizeof(DVDDiskID);
+ __DIRegs[5] = (u32)diskID;
+ __DIRegs[6] = sizeof(DVDDiskID);
+ __DIRegs[7] = 3;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowStopMotor(DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = 0xe3000000;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowRequestError(DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = 0xe0000000;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowInquiry(DVDDriveInfo* info, DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = 0x12000000;
+ __DIRegs[4] = sizeof(DVDDriveInfo);
+ __DIRegs[5] = (u32)info;
+ __DIRegs[6] = sizeof(DVDDriveInfo);
+ __DIRegs[7] = 3;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowAudioStream(u32 subcmd, u32 length, u32 offset, DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = subcmd | 0xe1000000;
+ __DIRegs[3] = offset >> 2;
+ __DIRegs[4] = length;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowRequestAudioStatus(u32 subcmd, DVDLowCallback callback)
+{
+ Callback = callback;
+ StopAtNextInt = FALSE;
+ __DIRegs[2] = subcmd | 0xe2000000;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+BOOL DVDLowAudioBufferConfig(BOOL enable, u32 size, DVDLowCallback callback)
+{
+#ifdef DEBUG
+ u32 bufSize;
+ u32 trigger;
+#endif
+
+ Callback = callback;
+ StopAtNextInt = FALSE;
+
+#ifdef DEBUG
+ bufSize = size & 0xF;
+ trigger = (size >> 4) & 0xF;
+ ASSERTLINE(0x4BD, bufSize < 16);
+ ASSERTLINE(0x4BE, trigger <= 2);
+#endif
+
+ __DIRegs[2] = 0xe4000000 | (enable != 0 ? 0x10000 : 0) | size;
+ __DIRegs[7] = 1;
+ SetTimeoutAlarm(OSSecondsToTicks(10));
+ return TRUE;
+}
+
+void DVDLowReset()
+{
+ u32 reg;
+ OSTime resetStart;
+
+ __DIRegs[1] = 2;
+ reg = __PIRegs[9];
+ __PIRegs[9] = (reg & ~4) | 1;
+
+ resetStart = __OSGetSystemTime();
+ while ((__OSGetSystemTime() - resetStart) < OSMicrosecondsToTicks(12))
+ ;
+
+ __PIRegs[9] = reg | 4 | 1;
+ ResetOccurred = TRUE;
+ LastResetEnd = __OSGetSystemTime();
+}
+
+DVDLowCallback DVDLowSetResetCoverCallback(DVDLowCallback callback)
+{
+ DVDLowCallback old;
+ BOOL enabled;
+
+ enabled = OSDisableInterrupts();
+ old = ResetCoverCallback;
+ ResetCoverCallback = callback;
+ OSRestoreInterrupts(enabled);
+ return old;
+}
+
+static void DoBreak(void)
+{
+ u32 statusReg;
+
+ statusReg = __DIRegs[0];
+ statusReg |= 0x40 | 1;
+ __DIRegs[0] = statusReg;
+ Breaking = TRUE;
+}
+
+static void SetBreakAlarm(OSTime timeout);
+
+static void AlarmHandlerForBreak(OSAlarm* alarm, OSContext* context)
+{
+ if (__DIRegs[6] < LastLength) {
+ DoBreak();
+ } else {
+ SetBreakAlarm(OSMillisecondsToTicks(20));
+ }
+}
+
+static void SetBreakAlarm(OSTime timeout)
+{
+ OSCreateAlarm(&AlarmForBreak);
+ OSSetAlarm(&AlarmForBreak, timeout, AlarmHandlerForBreak);
+}
+
+BOOL DVDLowBreak()
+{
+ StopAtNextInt = TRUE;
+ Breaking = TRUE;
+ return TRUE;
+}
+
+DVDLowCallback DVDLowClearCallback()
+{
+ DVDLowCallback old;
+ __DIRegs[1] = 0;
+ old = Callback;
+ Callback = NULL;
+ return old;
+}
+
+u32 DVDLowGetCoverStatus(void)
+{
+ if ((__OSGetSystemTime() - LastResetEnd) < OSMillisecondsToTicks(100)) {
+ return 0;
+ }
+
+ if (__DIRegs[1] & 1) {
+ return 1;
+ }
+
+ return 2;
+}
+
+
+void __DVDLowSetWAType(u32 type, u32 location)
+{
+ BOOL enabled;
+
+ enabled = OSDisableInterrupts();
+ ASSERTLINE(0x5B1, type < DVD_WATYPE_MAX);
+ WorkAroundType = type;
+ WorkAroundSeekLocation = location;
+ OSRestoreInterrupts(enabled);
+}
diff --git a/src/dolphin/dvd/dvdqueue.c b/src/dolphin/dvd/dvdqueue.c
new file mode 100644
index 00000000..683226f0
--- /dev/null
+++ b/src/dolphin/dvd/dvdqueue.c
@@ -0,0 +1,164 @@
+#include "dolphin/dvd/dvdqueue.h"
+#include "dolphin/os/OS.h"
+
+static struct {
+ /* 0x00 */ struct DVDCommandBlock * next;
+ /* 0x04 */ struct DVDCommandBlock * prev;
+} WaitingQueue[4];
+
+static struct DVDCommandBlock * PopWaitingQueuePrio(long prio);
+
+void __DVDClearWaitingQueue(void) {
+ unsigned long i;
+ struct DVDCommandBlock * q;
+
+ for(i = 0; i < 4; i++) {
+ q = (struct DVDCommandBlock *)&WaitingQueue[i].next;
+ q->next = q;
+ q->prev = q;
+ }
+}
+
+int __DVDPushWaitingQueue(long prio, struct DVDCommandBlock * block) {
+ int enabled = OSDisableInterrupts();
+ struct DVDCommandBlock * q = (struct DVDCommandBlock *)&WaitingQueue[prio];
+
+ q->prev->next = block;
+ block->prev = q->prev;
+ block->next = q;
+ q->prev = block;
+ OSRestoreInterrupts(enabled);
+ return 1;
+}
+
+static struct DVDCommandBlock * PopWaitingQueuePrio(long prio) {
+ struct DVDCommandBlock * tmp;
+ int enabled;
+ struct DVDCommandBlock * q;
+
+ enabled = OSDisableInterrupts();
+ q = (struct DVDCommandBlock *)&WaitingQueue[prio];
+ ASSERTLINE(0x57, q->next != q);
+ tmp = q->next;
+ q->next = tmp->next;
+ tmp->next->prev = q;
+ OSRestoreInterrupts(enabled);
+ tmp->next = 0;
+ tmp->prev = 0;
+ return tmp;
+}
+
+struct DVDCommandBlock * __DVDPopWaitingQueue(void) {
+ unsigned long i;
+ int enabled;
+ struct DVDCommandBlock * q;
+
+ enabled = OSDisableInterrupts();
+ for(i = 0; i < 4; i++) {
+ q = (struct DVDCommandBlock *)&WaitingQueue[i];
+ if (q->next != q) {
+ OSRestoreInterrupts(enabled);
+ return PopWaitingQueuePrio(i);
+ }
+ }
+ OSRestoreInterrupts(enabled);
+ return NULL;
+}
+
+int __DVDCheckWaitingQueue(void) {
+ unsigned long i;
+ int enabled;
+ struct DVDCommandBlock * q;
+
+ enabled = OSDisableInterrupts();
+ for(i = 0; i < 4; i++) {
+ q = (struct DVDCommandBlock *)&WaitingQueue[i];
+ if (q->next != q) {
+ OSRestoreInterrupts(enabled);
+ return 1;
+ }
+ }
+ OSRestoreInterrupts(enabled);
+ return 0;
+}
+
+int __DVDDequeueWaitingQueue(struct DVDCommandBlock * block) {
+ int enabled;
+ struct DVDCommandBlock * prev;
+ struct DVDCommandBlock * next;
+
+ enabled = OSDisableInterrupts();
+ prev = block->prev;
+ next = block->next;
+ if (prev == NULL || next == NULL) {
+ OSRestoreInterrupts(enabled);
+ return 0;
+ }
+ prev->next = next;
+ next->prev = prev;
+ OSRestoreInterrupts(enabled);
+ return 1;
+}
+
+int __DVDIsBlockInWaitingQueue(struct DVDCommandBlock * block) {
+ unsigned long i;
+ struct DVDCommandBlock * start;
+ struct DVDCommandBlock * q;
+
+ for(i = 0; i < 4; i++) {
+ start = (struct DVDCommandBlock *)&WaitingQueue[i];
+ if (start->next == start) {
+ continue;
+ }
+ for(q = start->next; q != start; q = q->next) {
+ if (q == block) {
+ return 1;
+ }
+ }
+ }
+ return 0;
+}
+
+static char * CommandNames[16] = {
+ "",
+ "READ",
+ "SEEK",
+ "CHANGE_DISK",
+ "BSREAD",
+ "READID",
+ "INITSTREAM",
+ "CANCELSTREAM",
+ "STOP_STREAM_AT_END",
+ "REQUEST_AUDIO_ERROR",
+ "REQUEST_PLAY_ADDR",
+ "REQUEST_START_ADDR",
+ "REQUEST_LENGTH",
+ "AUDIO_BUFFER_CONFIG",
+ "INQUIRY",
+ "BS_CHANGE_DISK",
+};
+
+void DVDDumpWaitingQueue(void) {
+ unsigned long i;
+ struct DVDCommandBlock * start;
+ struct DVDCommandBlock * q;
+
+ OSReport("==== DVD Waiting Queue Status ====\n");
+ for(i = 0; i < 4; i++) {
+ OSReport("< Queue #%d > ", i);
+ start = (struct DVDCommandBlock *)&WaitingQueue[i];
+ if (start->next == start) {
+ OSReport("None\n");
+ } else {
+ OSReport("\n");
+ for(q = start->next; q != start; q = q->next) {
+ OSReport("0x%08x: Command: %s ", q, CommandNames[q->command]);
+ if (q->command == 1) {
+ OSReport("Disk offset: %d, Length: %d, Addr: 0x%08x\n", q->offset, q->length, q->buffer);
+ } else {
+ OSReport("\n");
+ }
+ }
+ }
+ }
+}
diff --git a/src/dolphin/dvd/fstload.c b/src/dolphin/dvd/fstload.c
new file mode 100644
index 00000000..6287b149
--- /dev/null
+++ b/src/dolphin/dvd/fstload.c
@@ -0,0 +1,82 @@
+#include "dolphin/dvd/fstload.h"
+#include "dolphin/os/OS.h"
+
+// .bss
+static unsigned char bb2Buf[63]; // size: 0x3F, address: 0x0
+
+// .sbss
+static unsigned long status; // size: 0x4, address: 0x0
+static struct DVDBB2 * bb2; // size: 0x4, address: 0x4
+static struct DVDDiskID * idTmp; // size: 0x4, address: 0x8
+
+// functions
+static void cb(long result, struct DVDCommandBlock * block);
+void __fstLoad();
+
+static void cb(long result, struct DVDCommandBlock * block) {
+ if (result > 0) {
+ switch(status) {
+ case 0:
+ status = 1;
+ DVDReadAbsAsyncForBS(block, bb2, 0x20, 0x420, cb);
+ return;
+ case 1:
+ status = 2;
+ DVDReadAbsAsyncForBS(block, bb2->FSTAddress, (bb2->FSTLength + 0x1F) & 0xFFFFFFE0, bb2->FSTPosition, cb);
+ default:
+ return;
+ }
+ }
+ if (result == -1) {
+ return;
+ } else if (result == -4) {
+ status = 0;
+ DVDReset();
+ DVDReadDiskID(block, idTmp, cb);
+ }
+}
+
+void __fstLoad() {
+ struct OSBootInfo * bootInfo;
+ struct DVDDiskID * id;
+ unsigned char idTmpBuf[63];
+ long state;
+ void * arenaHi;
+ static struct DVDCommandBlock block;
+
+ arenaHi = OSGetArenaHi();
+ bootInfo = (void*)OSPhysicalToCached(0);
+ idTmp = (void*)OSRoundUp32B(idTmpBuf);
+ bb2 = (void*)OSRoundUp32B(bb2Buf);
+ DVDReset();
+ DVDReadDiskID(&block, idTmp, cb);
+ while (1) {
+ state = DVDGetDriveStatus();
+ if (state == 0) {
+ break;
+ }
+
+ // weird switch that seemingly wont do anything but break out of its own switch. What was this for? Early DVD development pre-hardware?
+ switch(state) {
+ case DVD_STATE_FATAL_ERROR: break;
+ case DVD_STATE_BUSY: break;
+ case DVD_STATE_WAITING: break;
+ case DVD_STATE_COVER_CLOSED: break;
+ case DVD_STATE_NO_DISK: break;
+ case DVD_STATE_COVER_OPEN: break;
+ case DVD_STATE_MOTOR_STOPPED: break;
+ }
+ }
+ bootInfo->fst_location = (void*)bb2->FSTAddress;
+ bootInfo->fst_max_length = bb2->FSTMaxLength;
+ id = &bootInfo->disk_info;
+ memcpy(id, idTmp, 0x20);
+ OSReport("\n");
+ OSReport(" Game Name ... %c%c%c%c\n", id->game_name[0], id->game_name[1], id->game_name[2], id->game_name[3]);
+ OSReport(" Company ..... %c%c\n", id->company[0], id->company[1]);
+ OSReport(" Disk # ...... %d\n", id->disk_number);
+ OSReport(" Game ver .... %d\n", id->game_version);
+ OSReport(" Streaming ... %s\n", !(id->is_streaming) ? "OFF" : "ON");
+ OSReport("\n");
+ OSSetArenaHi(bb2->FSTAddress);
+}