mirror of
https://github.com/zeldaret/tww.git
synced 2026-07-08 21:54:50 -04:00
1732 lines
49 KiB
C
1732 lines
49 KiB
C
#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);
|
|
}
|