pureikyubu/Docs/RE/DVDLow.c
Andruxa 574b40f37b Some old reversing found )
RE: DVDLow
RE: DVD file open
RE: Some ETH (BBA lib)
2015-09-07 02:48:37 +03:00

771 lines
23 KiB
C

// Gamecube DVD drive low-level commands. Version 0.02
// Reversed by org. Compile with CodeWarrior.
// $root$/build/libraries/dvd/src/DVDLow.c
#include <dolphin.h>
#include <dvd/DVDLow.h>
// DVD Interface register index.
//
#define DI_SR 0 // Status Register
#define DI_CVR 1 // Cover Register
#define DI_CMDBUF0 2 // Command Buffer 0
#define DI_CMDBUF1 3 // Command Buffer 1
#define DI_CMDBUF2 4 // Command Buffer 2
#define DI_MAR 5 // DMA Memory Address Register
#define DI_LEN 6 // DMA Transfer Length Register
#define DI_CR 7 // Control Register
#define DI_IMMBUF 8 // Immediate Data Buffer
#define DI_CFG 9 // Configuration Register
#define DI_MAX 10
// DI Status Register mask
#define DI_SR_BRKINT (1 << 6)
#define DI_SR_BRKINTMSK (1 << 5)
#define DI_SR_TCINT (1 << 4)
#define DI_SR_TCINTMSK (1 << 3)
#define DI_SR_DEINT (1 << 2)
#define DI_SR_DEINTMSK (1 << 1)
#define DI_SR_BRK (1 << 0)
// DI Cover Register mask
#define DI_CVR_CVRINT (1 << 2)
#define DI_CVR_CVRINTMSK (1 << 1)
#define DI_CVR_CVR (1 << 0)
// DI Control Register mask
#define DI_CR_RW (1 << 2)
#define DI_CR_DMA (1 << 1)
#define DI_CR_TSTART (1 << 0)
// DVD "workaround" is Nintendo hack for missing DVD reads in old revisions.
#define DVD_WATYPE_JUSTREAD 0
#define DVD_WATYPE_CACHE 1 // Fixes DVD cache read issues.
#define DVD_WATYPE_MAX 2
// Prev and Curr index names.
#define WA_ADDR 0
#define WA_LEN 1
#define WA_OFFS 2
// Internal variables.
static vu32 dvdReg[DI_MAX] AT_ADDRESS (OS_BASE_UNCACHED | 0x6000); // DVD registers
static vu32 resetReg AT_ADDRESS (OS_BASE_UNCACHED | 0x3024);
static DVDLowCallback Callback; // low-level operation callback
static DVDLowCallback ResetCoverCallback;
static OSTime LastResetEnd; // last reset completed checkout
static BOOL ResetOccurred;
static int WorkAroundType;
static s32 WorkAroundSeekLocation;
static BOOL StopAtNextInt;
static BOOL Breaking; // Break request flag
static OSAlarm AlarmForWA;
static OSAlarm AlarmForTimeout;
static OSAlarm AlarmForBreak;
static s32 LastLength; // last read length
static BOOL WaitingCoverClose;
static BOOL LastCommandWasRead;
static BOOL FirstRead = TRUE;
static OSTime LastReadIssued, LastReadFinished;
static u32 Prev[3], Curr[3]; // used for read operation. 0:Address, 1:Length, 2:Offset
// Seek/read command queue for cache issue workaround.
//
#define DVDLOW_CMD_READ 1
#define DVDLOW_CMD_SEEK 2
#define DVDLOW_CMD_END -1 // terminate queue execution.
static struct
{
u32 command;
void* address;
u32 length;
u32 offset;
DVDLowCallback callback;
} CommandList[3];
static u32 NextCommandNumber;
// Internal use.
void __DVDInitWA (void);
BOOL ProcessNextCommand (void);
void __DVDInterruptHandler (__OSInterrupt interrupt, OSContext *context);
void AlarmHandler (OSAlarm *alarm, OSContext *context);
void AlarmHandlerForTimeout(OSAlarm *alarm, OSContext *context);
void SetTimeoutAlarm (OSTime timeout);
void Read (void *addr, s32 length, s32 offset, DVDLowCallback callback);
BOOL AudioBufferOn (void);
BOOL HitCache (u32 *curr, u32 *prev);
void DoJustRead (void *addr, s32 length, s32 offset, DVDLowCallback callback);
void SeekTwiceBeforeRead (void *addr, s32 length, s32 offset, DVDLowCallback callback);
void WaitBeforeRead (void *addr, s32 length, s32 offset, DVDLowCallback callback, OSTime wait);
void DoBreak (void);
void AlarmHandlerForBreak (OSAlarm *alarm, OSContext *context);
void SetBreakAlarm (OSTime timeout);
void __DVDLowSetWAType (int type, s32 seekLoc);
// Private OS declarations. Should be in <os/OSPrivate.h> header actually.
OSTime __OSGetSystemTime (void);
// ---------------------------------------------------------------------------------
void __DVDInitWA (void)
{
NextCommandNumber = 0;
CommandList[0].command = DVDLOW_CMD_END;
__DVDLowSetWAType (DVD_WATYPE_JUSTREAD, 0);
OSInitAlarm ();
}
// ---------------------------------------------------------------------------------
// Process next command from queue.
// Return true if there are still some commands in queue.
// Return false if queue terminated.
BOOL ProcessNextCommand (void)
{
int n = NextCommandNumber;
ASSERT (n >= 3);
switch (CommandList[n].command)
{
case DVDLOW_CMD_READ:
NextCommandNumber++;
Read( CommandList[n].address,
CommandList[n].length,
CommandList[n].offset,
CommandList[n].callback );
return TRUE;
case DVDLOW_CMD_SEEK:
NextCommandNumber++;
DVDLowSeek( CommandList[n].offset,
CommandList[n].callback );
return TRUE;
}
return FALSE; // Queue terminated.
}
// ---------------------------------------------------------------------------------
// Handler for DVD interrupt.
void __DVDInterruptHandler (__OSInterrupt interrupt, OSContext *context)
{
#pragma unused(interrupt)
OSContext exceptionContext;
DVDLowCallback cb;
u32 reg, cause, mask, intr;
cause = 0; // Clear callback source.
OSCancelAlarm (&AlarmForTimeout);
if (LastCommandWasRead)
{
LastReadFinished = __OSGetSystemTime ();
FirstRead = FALSE;
Prev[WA_ADDR] = Curr[WA_ADDR]; // replace previous read parameters
Prev[WA_LEN] = Curr[WA_LEN];
Prev[WA_OFFS] = Curr[WA_OFFS];
if (StopAtNextInt) cause |= DVDLOW_CAUSE_BREAK;
}
LastCommandWasRead = FALSE;
StopAtNextInt = FALSE;
// Check regular interrupts cause.
reg = dvdReg[DI_SR];
mask = reg & (DI_SR_BRKINTMSK | DI_SR_TCINTMSK | DI_SR_DEINTMSK);
intr = reg & (DI_SR_BRKINT | DI_SR_TCINT | DI_SR_DEINT);
intr &= (mask << 1);
if (intr & DI_SR_BRKINT) cause |= DVDLOW_CAUSE_BREAK;
if (intr & DI_SR_TCINT) cause |= DVDLOW_CAUSE_TRANSFER;
if (intr & DI_SR_DEINT) cause |= DVDLOW_CAUSE_ERROR;
if (cause) ResetOccurred = FALSE; // DVD reset can be detected only this way :(
dvdReg[DI_SR] = intr | mask; // clear pending interrupts
if ( ResetOccurred &&
((__OSGetSystemTime() - LastResetEnd) < OSTicksToMilliseconds(200)) )
{
// Check cover interrupt cause.
reg = dvdReg[DI_CVR];
mask = reg & DI_CVR_CVRINTMSK;
intr = reg & DI_CVR_CVRINT;
intr &= (mask << 1);
if (intr)
{
if (ResetCoverCallback) ResetCoverCallback (DVDLOW_CAUSE_RESET_COVER);
ResetCoverCallback = NULL;
}
dvdReg[DI_CVR] = dvdReg[DI_CVR]; // Clear pending cover interrupt
}
else
{
if (WaitingCoverClose)
{
reg = dvdReg[DI_CVR];
mask = reg & DI_CVR_CVRINTMSK;
intr = reg & DI_CVR_CVRINT;
intr &= (mask << 1);
if (intr) cause |= DVDLOW_CAUSE_RESET_COVER;
dvdReg[DI_CVR] = intr | mask;
WaitingCoverClose = FALSE;
}
else dvdReg[DI_CVR] = 0;
}
if ( Breaking && (cause & DVDLOW_CAUSE_BREAK) )
{
cause &= ~DVDLOW_CAUSE_BREAK;
}
if (cause & DVDLOW_CAUSE_TRANSFER)
{
if (ProcessNextCommand()) return;
}
else
{
CommandList[0].command = DVDLOW_CMD_END;
NextCommandNumber = 0;
}
OSClearContext (&exceptionContext);
OSSetCurrentContext (&exceptionContext);
if (cause)
{
cb = Callback;
Callback = NULL;
if (cb) cb (cause); // Execute operation callback.
Breaking = FALSE;
}
OSClearContext (&exceptionContext);
OSSetCurrentContext (context);
}
// ---------------------------------------------------------------------------------
void AlarmHandler (OSAlarm *alarm, OSContext *context)
{
#pragma unused(alarm)
#pragma unused(context)
BOOL processed = ProcessNextCommand ();
ASSERT (processed);
}
// ---------------------------------------------------------------------------------
void AlarmHandlerForTimeout (OSAlarm *alarm, OSContext *context)
{
#pragma unused(alarm)
OSContext exceptionContext; // alarm-runtime context
DVDLowCallback cb;
__OSMaskInterrupts (OS_INTERRUPTMASK_PI_DI);
OSClearContext (&exceptionContext);
OSSetCurrentContext (&exceptionContext);
// Execute (and clear) low-level operation callback.
cb = Callback;
Callback = NULL;
if (cb) cb (DVDLOW_CAUSE_TIMEOUT);
OSClearContext (&exceptionContext);
OSSetCurrentContext (context);
}
// ---------------------------------------------------------------------------------
// Set timeout for low-level operations.
void SetTimeoutAlarm (OSTime timeout)
{
OSCreateAlarm (&AlarmForTimeout);
OSSetAlarm (&AlarmForTimeout, timeout, AlarmHandlerForTimeout);
}
// ---------------------------------------------------------------------------------
// Send actual DVD read command.
void Read (void *addr, s32 length, s32 offset, DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
LastCommandWasRead = TRUE;
LastReadIssued = __OSGetSystemTime ();
dvdReg[DI_CMDBUF0] = 0xA8000000 | 0x00; // subcmd = 0x00
dvdReg[DI_CMDBUF1] = offset >> 2;
dvdReg[DI_CMDBUF2] = length;
dvdReg[DI_MAR] = (u32)addr;
dvdReg[DI_LEN] = length;
LastLength = length;
dvdReg[DI_CR] = DI_CR_DMA | DI_CR_TSTART;
if (length > 10*1024*1024) SetTimeoutAlarm (OSSecondsToTicks(20));
else SetTimeoutAlarm (OSSecondsToTicks(10));
}
// ---------------------------------------------------------------------------------
// Return whenever DVD streaming buffer is active or not.
BOOL AudioBufferOn (void)
{
DVDDiskID *id = DVDGetCurrentDiskID ();
return id->streaming ? TRUE : FALSE;
}
// ---------------------------------------------------------------------------------
BOOL HitCache (u32 *curr, u32 *prev)
{
int blockNumOfPrevEnd, blockNumOfCurrStart, cacheBlockSize;
blockNumOfPrevEnd = (prev[WA_OFFS] + prev[WA_LEN] - 1) / 32*1024;
blockNumOfCurrStart = curr[WA_OFFS] / 32*1024;
cacheBlockSize = AudioBufferOn() ? 5 : 15;
if (blockNumOfCurrStart > blockNumOfPrevEnd - 2) return TRUE;
if (blockNumOfCurrStart >= blockNumOfPrevEnd + cacheBlockSize + 3) return FALSE;
else return TRUE;
}
// ---------------------------------------------------------------------------------
void DoJustRead (void *addr, s32 length, s32 offset, DVDLowCallback callback)
{
CommandList[0].command = DVDLOW_CMD_END;
NextCommandNumber = 0;
Read (addr, length, offset, callback);
}
// ---------------------------------------------------------------------------------
void SeekTwiceBeforeRead (void *addr, s32 length, s32 offset, DVDLowCallback callback)
{
s32 offsetToSeek;
if (offset & ~0x7FFF)
{
offsetToSeek = (offset & ~0x7FFF) + WorkAroundSeekLocation;
}
else offsetToSeek = 0;
CommandList[0].command = DVDLOW_CMD_SEEK;
CommandList[0].offset = offsetToSeek;
CommandList[0].callback= callback;
CommandList[1].command = DVDLOW_CMD_READ;
CommandList[1].address = addr;
CommandList[1].length = length;
CommandList[1].offset = offset;
CommandList[1].callback= callback;
CommandList[2].command = DVDLOW_CMD_END; // terminate.
NextCommandNumber = 0;
DVDLowSeek (offsetToSeek, callback);
}
// ---------------------------------------------------------------------------------
void WaitBeforeRead (void *addr, s32 length, s32 offset, DVDLowCallback callback, OSTime wait)
{
CommandList[0].command = DVDLOW_CMD_READ;
CommandList[0].address = addr;
CommandList[0].length = length;
CommandList[0].offset = offset;
CommandList[0].callback= callback;
CommandList[1].command = DVDLOW_CMD_END; // terminate.
NextCommandNumber = 0;
OSCreateAlarm (&AlarmForWA);
OSSetAlarm (&AlarmForWA, wait, AlarmHandler);
}
// ---------------------------------------------------------------------------------
// Low-level DVD sector reading, using cache issue workaround (if enabled).
// This one was tough in reversing, but I like challenge.
/*
* Complete DVD cache issue workaround description (seems to be fixed in production boards):
* Seek twice before very first read. Else:
* 1. If reading doesnt overlap previous one in 32 KB cache, seek twice and read.
* 2. If reading do overlap, but previous reading is completed less than 5 ms ago, do just read.
* 3. If reading do overlap, and previous reading is completed more than 5 ms ago, wait 5ms+500us and read.
* If reading doesnt hit the cache, do just read.
*/
BOOL DVDLowRead (void *addr, s32 length, s32 offset, DVDLowCallback callback)
{
int blockNumOfPrevEnd, blockNumOfCurrStart;
// Sanity checks.
if ((u32)addr & 0x1f)
OSHalt ("DVDLowRead(): address must be aligned with 32 byte boundary.");
if (length & 0x1f)
OSHalt ("DVDLowRead(): length must be a multiple of 32.");
if (offset & 3)
OSHalt ("DVDLowRead(): offset must be a multiple of 4.");
if (length == 0)
OSHalt ("DVD read: 0 was specified to length of the read\n");
dvdReg[DI_LEN] = length;
Curr[WA_ADDR] = (u32)addr; // Save current read parameters.
Curr[WA_LEN] = length;
Curr[WA_OFFS] = offset;
switch (WorkAroundType)
{
case DVD_WATYPE_JUSTREAD:
DoJustRead (addr, length, offset, callback);
break;
case DVD_WATYPE_CACHE: // DVD-drive has 32K read-ahead(?) cache space inside.
if (FirstRead)
{
SeekTwiceBeforeRead (addr, length, offset, callback);
}
else
{
if (HitCache(Curr, Prev) == FALSE) // Reading doesnt hit the 32 KB cache.
{
DoJustRead (addr, length, offset, callback);
}
else
{
blockNumOfPrevEnd = (Prev[WA_OFFS] + Prev[WA_LEN] - 1) / 32*1024;
blockNumOfCurrStart = Curr[WA_OFFS] / 32*1024;
if ( (blockNumOfPrevEnd == blockNumOfCurrStart) || (blockNumOfPrevEnd+1 == blockNumOfCurrStart) )
{ // Reading do overlap cache.
// If last read finished less than 5 milliseconds ago, do just read,
// else wait 5 ms + 500 us before read.
if ( (__OSGetSystemTime() - LastReadFinished) < OSTicksToMilliseconds(5) )
{
DoJustRead (addr, length, offset, callback);
}
else
{
WaitBeforeRead (addr, length, offset, callback, OSTicksToMilliseconds(5) + OSTicksToMicroseconds(500));
}
}
else SeekTwiceBeforeRead (addr, length, offset, callback);
}
}
break;
default: // Unknown workaround type.
ASSERT(FALSE); // Smart ass eh.
}
return TRUE;
}
// ---------------------------------------------------------------------------------
// Move laser head at specified position. Offset must be multiple of 4 by hardware limitations.
BOOL DVDLowSeek (s32 offset, DVDLowCallback callback)
{
if (offset & 3)
OSHalt ("DVDLowSeek(): offset must be a multiple of 4.");
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xAB000000;
dvdReg[DI_CMDBUF1] = offset >> 2;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowWaitCoverClose (DVDLowCallback callback)
{
Callback = callback;
WaitingCoverClose = TRUE;
StopAtNextInt = FALSE;
dvdReg[DI_CVR] = DI_CVR_CVRINTMSK; // Enable cover interrupt.
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowReadDiskID (DVDDiskID *diskID, DVDLowCallback callback)
{
if ((u32)diskID & 0x1f)
OSHalt ("DVDLowReadID(): id must be aligned with 32 byte boundary.");
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xA8000000 | 0x40; // subcmd = 0x40
dvdReg[DI_CMDBUF1] = 0;
dvdReg[DI_CMDBUF2] = sizeof(DVDDiskID);
dvdReg[DI_MAR] = (u32)diskID;
dvdReg[DI_LEN] = sizeof(DVDDiskID);
dvdReg[DI_CR] = DI_CR_DMA | DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowStopMotor (DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xE3000000;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowRequestError (DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xE0000000;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
// Read DVD manufacturer info.
BOOL DVDLowInquiry (DVDDriveInfo *info, DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0x12000000;
dvdReg[DI_CMDBUF2] = sizeof(DVDDriveInfo);
dvdReg[DI_MAR] = (u32)info;
dvdReg[DI_LEN] = sizeof(DVDDriveInfo);
dvdReg[DI_CR] = DI_CR_DMA | DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowAudioStream (u32 subcmd, s32 length, s32 offset, DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xE1000000 | subcmd;
dvdReg[DI_CMDBUF1] = offset >> 2;
dvdReg[DI_CMDBUF2] = length;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
BOOL DVDLowRequestAudioStatus (u32 subcmd, DVDLowCallback callback)
{
Callback = callback;
StopAtNextInt = FALSE;
dvdReg[DI_CMDBUF0] = 0xE2000000 | subcmd;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
// Set DVD streaming buffer configuration.
/*
* DVD Audio Buffer Config Command explained:
*
* -----------------------------------------------------------------------------------------------
* |00|01|02|03|04|05|06|07|08|09|10|11|12|13|14|15|16|17|18|19|20|21|22|23|24|25|26|27|28|29|30|31|
* |-----------------------------------------------------------------------------------------------|
* | 1 1 1 0 0 1| Trig| - - - - - - - -| E| - - - - - - - - - - -| Siz |
* -----------------------------------------------------------------------------------------------
*
* Trig : Trigger. Allowed values are 0, 1 and 2.
* E : Enable flag.
* Siz : Buffer size. Must not exceed 16 bytes.
*/
BOOL DVDLowAudioBufferConfig (BOOL enable, s32 size, DVDLowCallback callback)
{
int bufSize, trigger;
Callback = callback;
StopAtNextInt = FALSE;
bufSize = size & 0xf;
trigger = size >> 28;
ASSERT (bufSize < 16);
ASSERT (trigger <= 2);
dvdReg[DI_CMDBUF0] = 0xE4000000 | (enable ? 0x1000 : 0) | size;
dvdReg[DI_CR] = DI_CR_TSTART;
SetTimeoutAlarm (OSSecondsToTicks(10));
return TRUE;
}
// ---------------------------------------------------------------------------------
// Reset DVD controller.
void DVDLowReset (void)
{
OSTime resetStart;
u32 reg;
dvdReg[DI_CVR] = DI_CVR_CVRINTMSK; // Enable cover interrupt.
reg = resetReg;
resetReg = (reg & ~4) | 1; // Clear bit 29, set bit 31
// Wait some time (12 usec).
resetStart = __OSGetSystemTime ();
while ( (__OSGetSystemTime () - resetStart) < OSMicrosecondsToTicks(12)){};
resetReg = (reg | 4) | 1; // Set bit 29, set bit 31
ResetOccurred = TRUE;
LastResetEnd = __OSGetSystemTime ();
}
// ---------------------------------------------------------------------------------
DVDLowCallback DVDLowSetResetCoverCallback (DVDLowCallback callback)
{
DVDLowCallback old;
BOOL enabled;
enabled = OSDisableInterrupts ();
old = ResetCoverCallback;
ResetCoverCallback = callback;
OSRestoreInterrupts (enabled);
return old;
}
// ---------------------------------------------------------------------------------
// Do actual break (low-level command).
void DoBreak (void)
{
dvdReg[DI_SR] |= DI_SR_BRKINT | DI_SR_BRK; // clear Break interrupt and request for break.
Breaking = TRUE;
}
// ---------------------------------------------------------------------------------
// Timeout handler for break operation.
void AlarmHandlerForBreak (OSAlarm *alarm, OSContext *context)
{
// Break operation if its actually started, else delay 20 ms.
if (dvdReg[DI_LEN] < LastLength) DoBreak ();
else SetBreakAlarm (OSMillisecondsToTicks(20));
}
// ---------------------------------------------------------------------------------
// Set timeout for break operation.
void SetBreakAlarm (OSTime timeout)
{
OSCreateAlarm (&AlarmForBreak);
OSSetAlarm (&AlarmForBreak, timeout, AlarmHandlerForBreak);
}
// ---------------------------------------------------------------------------------
// Break last DVD operation.
BOOL DVDLowBreak (void)
{
StopAtNextInt = TRUE;
Breaking = TRUE;
return TRUE;
}
// ---------------------------------------------------------------------------------
// Clear low-level DVD callback. Return previous callback address.
DVDLowCallback DVDLowClearCallback (void)
{
DVDLowCallback old;
dvdReg[DI_CVR] = 0; // Mask DVD Cover interrupt (disable). WTF?
old = Callback;
Callback = NULL;
return old;
}
// ---------------------------------------------------------------------------------
// Return DVD cover signal state. Good result may appear after 100 milliseconds only.
int DVDLowGetCoverStatus (void)
{
// DVD cover state cannot be detected properly during drive reset.
// So good result may appear after some time (approximately 100 milliseconds)
if ( (__OSGetSystemTime () - LastResetEnd) < OSMillisecondsToTicks (100))
return DVD_COVER_UNKNOWN; // try later :)
return (dvdReg[DI_CVR] & DI_CVR_CVR) ? DVD_COVER_OPEN : DVD_COVER_CLOSED;
}
// ---------------------------------------------------------------------------------
// Set workaround hack parameters.
void __DVDLowSetWAType (int type, s32 seekLoc)
{
BOOL enabled = OSDisableInterrupts ();
ASSERT (type < DVD_WATYPE_MAX);
WorkAroundType = type;
WorkAroundSeekLocation = seekLoc;
OSRestoreInterrupts (enabled);
}