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