Make WII_IPC_HLE_Device_DI call DVDInterface
This commit is contained in:
parent
54f1e3a3c1
commit
d1c8a8bd9f
|
@ -7,9 +7,7 @@
|
||||||
|
|
||||||
#include "AudioCommon/AudioCommon.h"
|
#include "AudioCommon/AudioCommon.h"
|
||||||
|
|
||||||
#include "Common/ChunkFile.h"
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Thread.h"
|
|
||||||
|
|
||||||
#include "Core/ConfigManager.h"
|
#include "Core/ConfigManager.h"
|
||||||
#include "Core/CoreTiming.h"
|
#include "Core/CoreTiming.h"
|
||||||
|
@ -91,16 +89,6 @@ enum
|
||||||
DI_CONFIG_REGISTER = 0x24
|
DI_CONFIG_REGISTER = 0x24
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
// DVD IntteruptTypes
|
|
||||||
enum DI_InterruptType
|
|
||||||
{
|
|
||||||
INT_DEINT = 0,
|
|
||||||
INT_TCINT = 1,
|
|
||||||
INT_BRKINT = 2,
|
|
||||||
INT_CVRINT = 3,
|
|
||||||
};
|
|
||||||
|
|
||||||
// debug commands which may be ORd
|
// debug commands which may be ORd
|
||||||
enum
|
enum
|
||||||
{
|
{
|
||||||
|
@ -265,10 +253,13 @@ void EjectDiscCallback(u64 userdata, int cyclesLate);
|
||||||
void InsertDiscCallback(u64 userdata, int cyclesLate);
|
void InsertDiscCallback(u64 userdata, int cyclesLate);
|
||||||
|
|
||||||
void UpdateInterrupts();
|
void UpdateInterrupts();
|
||||||
void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt);
|
void GenerateDIInterrupt(DIInterruptType _DVDInterrupt);
|
||||||
void ExecuteCommand();
|
|
||||||
void FinishExecuteRead();
|
void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF);
|
||||||
u64 SimulateDiscReadTime();
|
DVDCommandResult ExecuteReadCommand(u64 DVD_offset, u32 output_address,
|
||||||
|
u32 DVD_length, u32 output_length, bool raw = false);
|
||||||
|
|
||||||
|
u64 SimulateDiscReadTime(u64 offset, u32 length);
|
||||||
s64 CalculateRawDiscReadTime(u64 offset, s64 length);
|
s64 CalculateRawDiscReadTime(u64 offset, s64 length);
|
||||||
|
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
|
@ -305,8 +296,7 @@ static void TransferComplete(u64 userdata, int cyclesLate)
|
||||||
{
|
{
|
||||||
m_DICR.TSTART = 0;
|
m_DICR.TSTART = 0;
|
||||||
m_DILENGTH.Length = 0;
|
m_DILENGTH.Length = 0;
|
||||||
GenerateDIInterrupt(INT_TCINT);
|
GenerateDIInterrupt((DIInterruptType)userdata);
|
||||||
g_ErrorCode = 0;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -480,13 +470,11 @@ bool IsLidOpen()
|
||||||
return (m_DICVR.CVR == 1);
|
return (m_DICVR.CVR == 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClearCoverInterrupt()
|
bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool raw)
|
||||||
{
|
|
||||||
m_DICVR.CVRINT = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength)
|
|
||||||
{
|
{
|
||||||
|
if (raw)
|
||||||
|
return VolumeHandler::RAWReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength);
|
||||||
|
else
|
||||||
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength);
|
return VolumeHandler::ReadToPtr(Memory::GetPointer(_iRamAddress), _iDVDOffset, _iLength);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -559,7 +547,21 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||||
m_DICR.Hex = val & 7;
|
m_DICR.Hex = val & 7;
|
||||||
if (m_DICR.TSTART)
|
if (m_DICR.TSTART)
|
||||||
{
|
{
|
||||||
ExecuteCommand();
|
DVDCommandResult result = ExecuteCommand(
|
||||||
|
m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex, m_DICMDBUF[2].Hex,
|
||||||
|
m_DIMAR.Hex, m_DILENGTH.Hex, true);
|
||||||
|
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed)
|
||||||
|
{
|
||||||
|
// Make sure fast disc speed performs "instant" reads; in addition
|
||||||
|
// to being used to speed up games, fast disc speed is used as a
|
||||||
|
// workaround for crashes in Star Wars Rogue Leader.
|
||||||
|
TransferComplete(result.interrupt_type, 0);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
// The transfer is finished after a delay
|
||||||
|
CoreTiming::ScheduleEvent((int)result.ticks_until_completion, tc, result.interrupt_type);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
@ -594,7 +596,7 @@ void UpdateInterrupts()
|
||||||
CoreTiming::ForceExceptionCheck(50);
|
CoreTiming::ForceExceptionCheck(50);
|
||||||
}
|
}
|
||||||
|
|
||||||
void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt)
|
void GenerateDIInterrupt(DIInterruptType _DVDInterrupt)
|
||||||
{
|
{
|
||||||
switch (_DVDInterrupt)
|
switch (_DVDInterrupt)
|
||||||
{
|
{
|
||||||
|
@ -607,115 +609,264 @@ void GenerateDIInterrupt(DI_InterruptType _DVDInterrupt)
|
||||||
UpdateInterrupts();
|
UpdateInterrupts();
|
||||||
}
|
}
|
||||||
|
|
||||||
void ExecuteCommand()
|
void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF)
|
||||||
{
|
{
|
||||||
// This variable is used to simulate the time is takes to execute a command.
|
if (write_to_DIIMMBUF)
|
||||||
// 1 / 15000 seconds is just some arbitrary default value.
|
m_DIIMMBUF.Hex = value;
|
||||||
// Commands that implement more precise timing are supposed to overwrite this.
|
else
|
||||||
u64 ticks_until_TC = SystemTimers::GetTicksPerSecond() / 15000;
|
Memory::Write_U32(value, output_address);
|
||||||
|
}
|
||||||
|
|
||||||
// _dbg_assert_(DVDINTERFACE, _DICR.RW == 0); // only DVD to Memory
|
DVDCommandResult ExecuteReadCommand(u64 DVD_offset, u32 output_address,
|
||||||
int GCAM = ((SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD) &&
|
u32 DVD_length, u32 output_length, bool raw)
|
||||||
(SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD))
|
{
|
||||||
? 1 : 0;
|
if (DVD_length > output_length)
|
||||||
|
{
|
||||||
|
WARN_LOG(DVDINTERFACE, "Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
||||||
|
DVD_length = output_length;
|
||||||
|
}
|
||||||
|
|
||||||
|
DVDCommandResult result;
|
||||||
|
result.ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length);
|
||||||
|
|
||||||
|
// Is this check needed?
|
||||||
|
if (output_address == 0)
|
||||||
|
{
|
||||||
|
PanicAlert("DVDLowRead : _BufferOut == 0");
|
||||||
|
result.interrupt_type = INT_DEINT;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (raw)
|
||||||
|
{
|
||||||
|
// We must make sure it is in a valid area! (#001 check)
|
||||||
|
// * 0x00000000 - 0x00014000 (limit of older IOS versions)
|
||||||
|
// * 0x460a0000 - 0x460a0008
|
||||||
|
// * 0x7ed40000 - 0x7ed40008
|
||||||
|
u32 DVD_offset_32 = (u32)(DVD_offset >> 2);
|
||||||
|
// Are these checks correct? They seem to mix 32-bit offsets and 8-bit lengths
|
||||||
|
if (!((DVD_offset_32 > 0x00000000 && DVD_offset_32 < 0x00014000) ||
|
||||||
|
(((DVD_offset_32 + DVD_length) > 0x00000000) && (DVD_offset_32 + DVD_length) < 0x00014000) ||
|
||||||
|
(DVD_offset_32 > 0x460a0000 && DVD_offset_32 < 0x460a0008) ||
|
||||||
|
(((DVD_offset_32 + DVD_length) > 0x460a0000) && (DVD_offset_32 + DVD_length) < 0x460a0008) ||
|
||||||
|
(DVD_offset_32 > 0x7ed40000 && DVD_offset_32 < 0x7ed40008) ||
|
||||||
|
(((DVD_offset_32 + DVD_length) > 0x7ed40000) && (DVD_offset_32 + DVD_length) < 0x7ed40008)))
|
||||||
|
{
|
||||||
|
WARN_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: trying to read out of bounds @ %09" PRIx64, DVD_offset);
|
||||||
|
g_ErrorCode = ERROR_READY | ERROR_BLOCK_OOB;
|
||||||
|
// Should cause software to call DVDLowRequestError
|
||||||
|
result.interrupt_type = INT_BRKINT;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!DVDRead(DVD_offset, output_address, DVD_length, raw))
|
||||||
|
PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error");
|
||||||
|
|
||||||
|
result.interrupt_type = INT_TCINT;
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
DVDCommandResult ExecuteCommand(u32 command_0, u32 command_1, u32 command_2,
|
||||||
|
u32 output_address, u32 output_length, bool write_to_DIIMMBUF)
|
||||||
|
{
|
||||||
|
DVDCommandResult result;
|
||||||
|
result.interrupt_type = INT_TCINT;
|
||||||
|
result.ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000;
|
||||||
|
|
||||||
|
bool GCAM = (SConfig::GetInstance().m_SIDevice[0] == SIDEVICE_AM_BASEBOARD) &&
|
||||||
|
(SConfig::GetInstance().m_EXIDevice[2] == EXIDEVICE_AM_BASEBOARD);
|
||||||
|
|
||||||
|
// DVDLowRequestError needs access to the error code set by the previous command
|
||||||
|
if (command_0 >> 24 != DVDLowRequestError)
|
||||||
|
g_ErrorCode = 0;
|
||||||
|
|
||||||
if (GCAM)
|
if (GCAM)
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE,
|
ERROR_LOG(DVDINTERFACE, "DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x",
|
||||||
"DVD: %08x, %08x, %08x, DMA=addr:%08x,len:%08x,ctrl:%08x",
|
command_0, command_1, command_2, output_address, output_length, m_DICR.Hex);
|
||||||
m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex, m_DICMDBUF[2].Hex,
|
|
||||||
m_DIMAR.Hex, m_DILENGTH.Hex, m_DICR.Hex);
|
|
||||||
// decrypt command. But we have a zero key, that simplifies things a lot.
|
// decrypt command. But we have a zero key, that simplifies things a lot.
|
||||||
// If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd
|
// If you get crazy dvd command errors, make sure 0x80000000 - 0x8000000c is zero'd
|
||||||
m_DICMDBUF[0].Hex <<= 24;
|
command_0 <<= 24;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
switch (command_0 >> 24)
|
||||||
switch (m_DICMDBUF[0].CMDBYTE0)
|
|
||||||
{
|
{
|
||||||
|
// Seems to be used by both GC and Wii
|
||||||
case DVDLowInquiry:
|
case DVDLowInquiry:
|
||||||
if (GCAM)
|
if (GCAM)
|
||||||
{
|
{
|
||||||
// 0x29484100...
|
// 0x29484100...
|
||||||
// was 21 i'm not entirely sure about this, but it works well.
|
// was 21 i'm not entirely sure about this, but it works well.
|
||||||
m_DIIMMBUF.Hex = 0x21000000;
|
WriteImmediate(0x21000000, output_address, write_to_DIIMMBUF);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// small safety check, dunno if it's needed
|
// (shuffle2) Taken from my Wii
|
||||||
if ((m_DICMDBUF[1].Hex == 0) && (m_DILENGTH.Length == 0x20))
|
Memory::Write_U32(0x00000002, output_address);
|
||||||
{
|
Memory::Write_U32(0x20060526, output_address + 4);
|
||||||
u8* driveInfo = Memory::GetPointer(m_DIMAR.Address);
|
// This was in the oubuf even though this cmd is only supposed to reply with 64bits
|
||||||
// gives the correct output in GCOS - 06 2001/08 (61)
|
// However, this and other tests strongly suggest that the buffer is static, and it's never - or rarely cleared.
|
||||||
// there may be other stuff missing ?
|
Memory::Write_U32(0x41000000, output_address + 8);
|
||||||
driveInfo[4] = 0x20;
|
|
||||||
driveInfo[5] = 0x01;
|
|
||||||
driveInfo[6] = 0x06;
|
|
||||||
driveInfo[7] = 0x08;
|
|
||||||
driveInfo[8] = 0x61;
|
|
||||||
|
|
||||||
// Just for fun
|
INFO_LOG(DVDINTERFACE, "DVDLowInquiry (Buffer 0x%08x, 0x%x)",
|
||||||
INFO_LOG(DVDINTERFACE, "Drive Info: %02x %02x%02x/%02x (%02x)",
|
output_address, output_length);
|
||||||
driveInfo[6], driveInfo[4], driveInfo[5], driveInfo[7], driveInfo[8]);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// "Set Extension"...not sure what it does
|
// Only seems to be used from WII_IPC, not through direct access
|
||||||
|
case DVDLowReadDiskID:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID");
|
||||||
|
result = ExecuteReadCommand(0, output_address, command_1, output_length, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Only seems to be used from WII_IPC, not through direct access
|
||||||
|
case DVDLowRead:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1);
|
||||||
|
result = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowWaitForCoverClose:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowWaitForCoverClose");
|
||||||
|
result.interrupt_type = (DIInterruptType)4; // ???
|
||||||
|
break;
|
||||||
|
|
||||||
|
// "Set Extension"...not sure what it does. GC only?
|
||||||
case 0x55:
|
case 0x55:
|
||||||
INFO_LOG(DVDINTERFACE, "SetExtension");
|
INFO_LOG(DVDINTERFACE, "SetExtension");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DMA Read from Disc
|
// Probably only used though WII_IPC
|
||||||
|
case DVDLowGetCoverReg:
|
||||||
|
WriteImmediate(m_DICVR.Hex, output_address, write_to_DIIMMBUF);
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", m_DICVR.Hex);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowNotifyReset:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowNotifyReset");
|
||||||
|
PanicAlert("DVDLowNotifyReset");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDvdPhysical:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdPhysical");
|
||||||
|
PanicAlert("DVDLowReadDvdPhysical");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDvdCopyright:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdCopyright");
|
||||||
|
PanicAlert("DVDLowReadDvdCopyright");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDvdDiscKey:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdDiscKey");
|
||||||
|
PanicAlert("DVDLowReadDvdDiscKey");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowClearCoverInterrupt:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowClearCoverInterrupt");
|
||||||
|
m_DICVR.CVRINT = 0;
|
||||||
|
|
||||||
|
// Less than ~1/155th of a second hangs Oregon Trail at "loading wheel".
|
||||||
|
// More than ~1/140th of a second hangs Resident Evil Archives: Resident Evil Zero.
|
||||||
|
result.ticks_until_completion = SystemTimers::GetTicksPerSecond() / 146;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowGetCoverStatus:
|
||||||
|
WriteImmediate(g_bDiscInside ? 2 : 1, output_address, write_to_DIIMMBUF);
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", g_bDiscInside ? "" : "Not ");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReset:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowReset");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowClosePartition:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowClosePartition");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowUnencryptedRead:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowUnencryptedRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1);
|
||||||
|
result = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowEnableDvdVideo:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowEnableDvdVideo");
|
||||||
|
break;
|
||||||
|
|
||||||
|
// New Super Mario Bros. Wii sends these commands,
|
||||||
|
// but it seems we don't need to implement anything.
|
||||||
|
// Probably only used by Wii
|
||||||
|
case 0x95:
|
||||||
|
case 0x96:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "Unimplemented BCA command 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||||
|
command_0, output_address, output_length);
|
||||||
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReportKey:
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowReportKey");
|
||||||
|
// Does not work on retail discs/drives
|
||||||
|
// Retail games send this command to see if they are running on real retail hw
|
||||||
|
g_ErrorCode = ERROR_READY | ERROR_INV_CMD;
|
||||||
|
result.interrupt_type = INT_BRKINT;
|
||||||
|
break;
|
||||||
|
|
||||||
|
// DMA Read from Disc. Only seems to be used through direct access, not WII_IPC
|
||||||
case 0xA8:
|
case 0xA8:
|
||||||
if (g_bDiscInside)
|
if (g_bDiscInside)
|
||||||
{
|
{
|
||||||
switch (m_DICMDBUF[0].CMDBYTE3)
|
switch (command_0 & 0xFF)
|
||||||
{
|
{
|
||||||
case 0x00: // Read Sector
|
case 0x00: // Read Sector
|
||||||
{
|
{
|
||||||
u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;
|
u64 iDVDOffset = (u64)command_1 << 2;
|
||||||
|
|
||||||
DEBUG_LOG(DVDINTERFACE, "Read: DVDOffset=%08x, DMABuffer=%08x, SrcLength=%08x, DMALength=%08x",
|
INFO_LOG(DVDINTERFACE, "Read: DVDOffset=%08" PRIx64 ", DMABuffer = %08x, SrcLength = %08x, DMALength = %08x",
|
||||||
iDVDOffset, m_DIMAR.Address, m_DICMDBUF[2].Hex, m_DILENGTH.Length);
|
iDVDOffset, output_address, command_2, output_length);
|
||||||
_dbg_assert_(DVDINTERFACE, m_DICMDBUF[2].Hex == m_DILENGTH.Length);
|
|
||||||
|
|
||||||
if (GCAM)
|
if (GCAM)
|
||||||
{
|
{
|
||||||
if (iDVDOffset & 0x80000000) // read request to hardware buffer
|
if (iDVDOffset & 0x80000000) // read request to hardware buffer
|
||||||
{
|
{
|
||||||
u32 len = m_DILENGTH.Length / 4;
|
|
||||||
switch (iDVDOffset)
|
switch (iDVDOffset)
|
||||||
{
|
{
|
||||||
case 0x80000000:
|
case 0x80000000:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (80000000)");
|
||||||
for (u32 i = 0; i < len; i++)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
Memory::Write_U32(0, m_DIMAR.Address + i * 4);
|
Memory::Write_U32(0, output_address + i);
|
||||||
break;
|
break;
|
||||||
case 0x80000040:
|
case 0x80000040:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (2) (80000040)");
|
||||||
for (u32 i = 0; i < len; i++)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
Memory::Write_U32(~0, m_DIMAR.Address + i * 4);
|
Memory::Write_U32(~0, output_address + i);
|
||||||
Memory::Write_U32(0x00000020, m_DIMAR.Address); // DIMM SIZE, LE
|
Memory::Write_U32(0x00000020, output_address); // DIMM SIZE, LE
|
||||||
Memory::Write_U32(0x4743414D, m_DIMAR.Address + 4); // GCAM signature
|
Memory::Write_U32(0x4743414D, output_address + 4); // GCAM signature
|
||||||
break;
|
break;
|
||||||
case 0x80000120:
|
case 0x80000120:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000120)");
|
||||||
for (u32 i = 0; i < len; i++)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
|
Memory::Write_U32(0x01010101, output_address + i);
|
||||||
break;
|
break;
|
||||||
case 0x80000140:
|
case 0x80000140:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ FIRMWARE STATUS (80000140)");
|
||||||
for (u32 i = 0; i < len; i++)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
Memory::Write_U32(0x01010101, m_DIMAR.Address + i * 4);
|
Memory::Write_U32(0x01010101, output_address + i);
|
||||||
break;
|
break;
|
||||||
case 0x84000020:
|
case 0x84000020:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD STATUS (1) (84000020)");
|
||||||
for (u32 i = 0; i < len; i++)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
Memory::Write_U32(0x00000000, m_DIMAR.Address + i * 4);
|
Memory::Write_U32(0x00000000, output_address + i);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %x", iDVDOffset);
|
ERROR_LOG(DVDINTERFACE, "GC-AM: UNKNOWN MEDIA BOARD LOCATION %" PRIx64, iDVDOffset);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
@ -724,56 +875,43 @@ void ExecuteCommand()
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)");
|
ERROR_LOG(DVDINTERFACE, "GC-AM: READ MEDIA BOARD COMM AREA (1f900020)");
|
||||||
u8* source = media_buffer + iDVDOffset - 0x1f900000;
|
u8* source = media_buffer + iDVDOffset - 0x1f900000;
|
||||||
Memory::CopyToEmu(m_DIMAR.Address, source, m_DILENGTH.Length);
|
Memory::CopyToEmu(output_address, source, output_length);
|
||||||
for (u32 i = 0; i < m_DILENGTH.Length; i += 4)
|
for (u32 i = 0; i < output_length; i += 4)
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(m_DIMAR.Address + i));
|
ERROR_LOG(DVDINTERFACE, "GC-AM: %08x", Memory::Read_U32(output_address + i));
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ticks_until_TC = SimulateDiscReadTime();
|
result = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length);
|
||||||
|
|
||||||
// Here is the actual disc reading
|
|
||||||
if (!DVDRead(iDVDOffset, m_DIMAR.Address, m_DILENGTH.Length))
|
|
||||||
{
|
|
||||||
PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error");
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 0x40: // Read DiscID
|
case 0x40: // Read DiscID
|
||||||
_dbg_assert_(DVDINTERFACE, m_DICMDBUF[1].Hex == 0);
|
INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address));
|
||||||
_dbg_assert_(DVDINTERFACE, m_DICMDBUF[2].Hex == m_DILENGTH.Length);
|
result = ExecuteReadCommand(0, output_address, command_2, output_length);
|
||||||
_dbg_assert_(DVDINTERFACE, m_DILENGTH.Length == 0x20);
|
|
||||||
if (!DVDRead(m_DICMDBUF[1].Hex, m_DIMAR.Address, m_DILENGTH.Length))
|
|
||||||
PanicAlertT("Can't read from DVD_Plugin - DVD-Interface: Fatal Error");
|
|
||||||
WARN_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(m_DIMAR.Address));
|
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
_dbg_assert_msg_(DVDINTERFACE, 0, "Unknown Read Subcommand");
|
ERROR_LOG(DVDINTERFACE, "Unknown read subcommand: %08x", command_0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
// there is no disc to read
|
// there is no disc to read
|
||||||
m_DICR.TSTART = 0;
|
|
||||||
m_DILENGTH.Length = 0;
|
|
||||||
g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H;
|
g_ErrorCode = ERROR_NO_DISK | ERROR_COVER_H;
|
||||||
GenerateDIInterrupt(INT_DEINT);
|
result.interrupt_type = INT_DEINT;
|
||||||
return;
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// GC-AM
|
// GC-AM only
|
||||||
case 0xAA:
|
case 0xAA:
|
||||||
if (GCAM)
|
if (GCAM)
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", m_DIMAR.Address, m_DILENGTH.Length);
|
ERROR_LOG(DVDINTERFACE, "GC-AM: 0xAA, DMABuffer=%08x, DMALength=%08x", output_address, output_length);
|
||||||
u32 iDVDOffset = m_DICMDBUF[1].Hex << 2;
|
u64 iDVDOffset = (u64)command_1 << 2;
|
||||||
unsigned int len = m_DILENGTH.Length;
|
u32 len = output_length;
|
||||||
int offset = iDVDOffset - 0x1F900000;
|
s64 offset = iDVDOffset - 0x1F900000;
|
||||||
/*
|
/*
|
||||||
if (iDVDOffset == 0x84800000)
|
if (iDVDOffset == 0x84800000)
|
||||||
{
|
{
|
||||||
|
@ -782,7 +920,7 @@ void ExecuteCommand()
|
||||||
else*/
|
else*/
|
||||||
if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40)
|
if ((offset < 0) || ((offset + len) > 0x40) || len > 0x40)
|
||||||
{
|
{
|
||||||
u32 addr = m_DIMAR.Address;
|
u32 addr = output_address;
|
||||||
if (iDVDOffset == 0x84800000)
|
if (iDVDOffset == 0x84800000)
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD");
|
ERROR_LOG(DVDINTERFACE, "FIRMWARE UPLOAD");
|
||||||
|
@ -794,7 +932,7 @@ void ExecuteCommand()
|
||||||
|
|
||||||
while (len >= 4)
|
while (len >= 4)
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
|
ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, Memory::Read_U32(addr));
|
||||||
addr += 4;
|
addr += 4;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
iDVDOffset += 4;
|
iDVDOffset += 4;
|
||||||
|
@ -806,7 +944,7 @@ void ExecuteCommand()
|
||||||
Memory::CopyFromEmu(media_buffer + offset, addr, len);
|
Memory::CopyFromEmu(media_buffer + offset, addr, len);
|
||||||
while (len >= 4)
|
while (len >= 4)
|
||||||
{
|
{
|
||||||
ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08x: %08x", iDVDOffset, Memory::Read_U32(addr));
|
ERROR_LOG(DVDINTERFACE, "GC-AM Media Board WRITE (0xAA): %08" PRIx64 ": %08x", iDVDOffset, Memory::Read_U32(addr));
|
||||||
addr += 4;
|
addr += 4;
|
||||||
len -= 4;
|
len -= 4;
|
||||||
iDVDOffset += 4;
|
iDVDOffset += 4;
|
||||||
|
@ -815,12 +953,12 @@ void ExecuteCommand()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Seek (immediate)
|
// Seems to be used by both GC and Wii
|
||||||
case DVDLowSeek:
|
case DVDLowSeek:
|
||||||
if (!GCAM)
|
if (!GCAM)
|
||||||
{
|
{
|
||||||
// We don't care :)
|
// Currently unimplemented
|
||||||
DEBUG_LOG(DVDINTERFACE, "Seek: offset=%08x (ignoring)", m_DICMDBUF[1].Hex << 2);
|
INFO_LOG(DVDINTERFACE, "Seek: offset=%09" PRIx64 " (ignoring)", (u64)command_1 << 2);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -893,27 +1031,62 @@ void ExecuteCommand()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
memset(media_buffer + 0x20, 0, 0x20);
|
memset(media_buffer + 0x20, 0, 0x20);
|
||||||
m_DIIMMBUF.Hex = 0x66556677; // just a random value that works.
|
WriteImmediate(0x66556677, output_address, write_to_DIIMMBUF); // just a random value that works.
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDvd:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowReadDvd");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDvdConfig:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowReadDvdConfig");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowStopLaser:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowStopLaser");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
case DVDLowOffset:
|
case DVDLowOffset:
|
||||||
DEBUG_LOG(DVDINTERFACE, "DVDLowOffset: ignoring...");
|
ERROR_LOG(DVDINTERFACE, "DVDLowOffset");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowReadDiskBca:
|
||||||
|
WARN_LOG(DVDINTERFACE, "DVDLowReadDiskBca");
|
||||||
|
Memory::Write_U32(1, output_address + 0x30);
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowRequestDiscStatus:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowRequestDiscStatus");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowRequestRetryNumber:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowRequestRetryNumber");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowSetMaximumRotation:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowSetMaximumRotation");
|
||||||
|
break;
|
||||||
|
// Probably only used by Wii
|
||||||
|
case DVDLowSerMeasControl:
|
||||||
|
ERROR_LOG(DVDINTERFACE, "DVDLowSerMeasControl");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Request Error Code
|
// Used by both GC and Wii
|
||||||
case DVDLowRequestError:
|
case DVDLowRequestError:
|
||||||
ERROR_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", g_ErrorCode);
|
INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", g_ErrorCode);
|
||||||
m_DIIMMBUF.Hex = g_ErrorCode;
|
WriteImmediate(g_ErrorCode, output_address, write_to_DIIMMBUF);
|
||||||
|
g_ErrorCode = 0;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Audio Stream (Immediate)
|
// Audio Stream (Immediate). Only seems to be used by some GC games
|
||||||
// m_DICMDBUF[0].CMDBYTE1 = Subcommand
|
// (command_0 >> 16) & 0xFF = Subcommand
|
||||||
// m_DICMDBUF[1].Hex << 2 = Offset on disc
|
// command_1 << 2 = Offset on disc
|
||||||
// m_DICMDBUF[2].Hex = Length of the stream
|
// command_2 = Length of the stream
|
||||||
case 0xE1:
|
case 0xE1:
|
||||||
{
|
{
|
||||||
u8 cancel_stream = m_DICMDBUF[0].CMDBYTE1;
|
u8 cancel_stream = (command_0 >> 16) & 0xFF;
|
||||||
if (cancel_stream)
|
if (cancel_stream)
|
||||||
{
|
{
|
||||||
g_bStopAtTrackEnd = false;
|
g_bStopAtTrackEnd = false;
|
||||||
|
@ -926,17 +1099,16 @@ void ExecuteCommand()
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
u32 pos = m_DICMDBUF[1].Hex << 2;
|
if ((command_1 == 0) && (command_2 == 0))
|
||||||
u32 length = m_DICMDBUF[2].Hex;
|
|
||||||
|
|
||||||
if ((pos == 0) && (length == 0))
|
|
||||||
{
|
{
|
||||||
g_bStopAtTrackEnd = true;
|
g_bStopAtTrackEnd = true;
|
||||||
}
|
}
|
||||||
else if (!g_bStopAtTrackEnd)
|
else if (!g_bStopAtTrackEnd)
|
||||||
{
|
{
|
||||||
NextStart = pos;
|
// Setting NextStart (a u32) like this discards two bits,
|
||||||
NextLength = length;
|
// but GC games can't be 4 GiB big, so it shouldn't matter
|
||||||
|
NextStart = command_1 << 2;
|
||||||
|
NextLength = command_2;
|
||||||
if (!g_bStream)
|
if (!g_bStream)
|
||||||
{
|
{
|
||||||
CurrentStart = NextStart;
|
CurrentStart = NextStart;
|
||||||
|
@ -948,50 +1120,59 @@ void ExecuteCommand()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
INFO_LOG(DVDINTERFACE, "(Audio) Stream cmd: %08x offset: %08" PRIx64 " length: %08x",
|
||||||
WARN_LOG(DVDINTERFACE, "(Audio) Stream subcmd = %08x offset = %08x length=%08x",
|
command_0, (u64)command_1 << 2, command_2);
|
||||||
m_DICMDBUF[0].Hex, m_DICMDBUF[1].Hex << 2, m_DICMDBUF[2].Hex);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Request Audio Status (Immediate)
|
// Request Audio Status (Immediate). Only seems to be used by some GC games
|
||||||
case 0xE2:
|
case 0xE2:
|
||||||
{
|
{
|
||||||
switch (m_DICMDBUF[0].CMDBYTE1)
|
switch (command_0 >> 16 & 0xFF)
|
||||||
{
|
{
|
||||||
case 0x00: // Returns streaming status
|
case 0x00: // Returns streaming status
|
||||||
DEBUG_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x", AudioPos, CurrentStart + CurrentLength, CurrentStart, CurrentLength);
|
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x", AudioPos, CurrentStart + CurrentLength, CurrentStart, CurrentLength);
|
||||||
m_DIIMMBUF.REGVAL0 = 0;
|
WriteImmediate((g_bStream) ? 1 : 0, output_address, write_to_DIIMMBUF);
|
||||||
m_DIIMMBUF.REGVAL1 = 0;
|
|
||||||
m_DIIMMBUF.REGVAL2 = 0;
|
|
||||||
m_DIIMMBUF.REGVAL3 = (g_bStream) ? 1 : 0;
|
|
||||||
break;
|
break;
|
||||||
case 0x01: // Returns the current offset
|
case 0x01: // Returns the current offset
|
||||||
DEBUG_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", AudioPos);
|
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", AudioPos);
|
||||||
m_DIIMMBUF.Hex = AudioPos >> 2;
|
WriteImmediate(AudioPos >> 2, output_address, write_to_DIIMMBUF);
|
||||||
break;
|
break;
|
||||||
case 0x02: // Returns the start offset
|
case 0x02: // Returns the start offset
|
||||||
DEBUG_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", CurrentStart);
|
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", CurrentStart);
|
||||||
m_DIIMMBUF.Hex = CurrentStart >> 2;
|
WriteImmediate(CurrentStart >> 2, output_address, write_to_DIIMMBUF);
|
||||||
break;
|
break;
|
||||||
case 0x03: // Returns the total length
|
case 0x03: // Returns the total length
|
||||||
DEBUG_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", CurrentLength);
|
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", CurrentLength);
|
||||||
m_DIIMMBUF.Hex = CurrentLength;
|
WriteImmediate(CurrentLength >> 2, output_address, write_to_DIIMMBUF);
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", m_DICMDBUF[0].CMDBYTE1, g_bStream? "on":"off");
|
WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", command_0 >> 16 & 0xFF, g_bStream ? "on" : "off");
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case DVDLowStopMotor:
|
case DVDLowStopMotor:
|
||||||
DEBUG_LOG(DVDINTERFACE, "Stop motor");
|
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s",
|
||||||
|
command_1 ? "eject" : "", command_2 ? "kill!" : "");
|
||||||
|
|
||||||
|
if (command_1)
|
||||||
|
EjectDiscCallback(0, 0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// DVD Audio Enable/Disable (Immediate)
|
// DVD Audio Enable/Disable (Immediate). GC uses this, and apparently Wii also does...?
|
||||||
case DVDLowAudioBufferConfig:
|
case DVDLowAudioBufferConfig:
|
||||||
if (m_DICMDBUF[0].CMDBYTE1 == 1)
|
// For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm (dead link?)
|
||||||
|
//
|
||||||
|
// Upon Power up or reset , 2 commands must be issued for proper use of audio streaming:
|
||||||
|
// DVDReadDiskID A8000040,00000000,00000020
|
||||||
|
// DVDLowAudioBufferConfig E4xx00yy,00000000,00000020
|
||||||
|
//
|
||||||
|
// xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID
|
||||||
|
// yy=0 (if xx=0) or 0xA (if xx=1)
|
||||||
|
|
||||||
|
if ((command_0 >> 16) & 0xFF)
|
||||||
{
|
{
|
||||||
// TODO: What is this actually supposed to do?
|
// TODO: What is this actually supposed to do?
|
||||||
g_bStream = true;
|
g_bStream = true;
|
||||||
|
@ -1005,31 +1186,33 @@ void ExecuteCommand()
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// yet another command we prolly don't care about
|
// yet another (GC?) command we prolly don't care about
|
||||||
case 0xEE:
|
case 0xEE:
|
||||||
DEBUG_LOG(DVDINTERFACE, "SetStatus - Unimplemented");
|
INFO_LOG(DVDINTERFACE, "SetStatus");
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Debug commands; see yagcd. We don't really care
|
// Debug commands; see yagcd. We don't really care
|
||||||
// NOTE: commands to stream data will send...a raw data stream
|
// NOTE: commands to stream data will send...a raw data stream
|
||||||
// This will appear as unknown commands, unless the check is re-instated to catch such data.
|
// This will appear as unknown commands, unless the check is re-instated to catch such data.
|
||||||
|
// Can probably only be used through direct access
|
||||||
case 0xFE:
|
case 0xFE:
|
||||||
INFO_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", m_DICMDBUF[0].Hex);
|
ERROR_LOG(DVDINTERFACE, "Unsupported DVD Drive debug command 0x%08x", command_0);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
// Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME"
|
// Unlock Commands. 1: "MATSHITA" 2: "DVD-GAME"
|
||||||
// Just for fun
|
// Just for fun
|
||||||
|
// Can probably only be used through direct access
|
||||||
case 0xFF:
|
case 0xFF:
|
||||||
{
|
{
|
||||||
if (m_DICMDBUF[0].Hex == 0xFF014D41 &&
|
if (command_0 == 0xFF014D41 &&
|
||||||
m_DICMDBUF[1].Hex == 0x54534849 &&
|
command_1 == 0x54534849 &&
|
||||||
m_DICMDBUF[2].Hex == 0x54410200)
|
command_2 == 0x54410200)
|
||||||
{
|
{
|
||||||
INFO_LOG(DVDINTERFACE, "Unlock test 1 passed");
|
INFO_LOG(DVDINTERFACE, "Unlock test 1 passed");
|
||||||
}
|
}
|
||||||
else if (m_DICMDBUF[0].Hex == 0xFF004456 &&
|
else if (command_0 == 0xFF004456 &&
|
||||||
m_DICMDBUF[1].Hex == 0x442D4741 &&
|
command_1 == 0x442D4741 &&
|
||||||
m_DICMDBUF[2].Hex == 0x4D450300)
|
command_2 == 0x4D450300)
|
||||||
{
|
{
|
||||||
INFO_LOG(DVDINTERFACE, "Unlock test 2 passed");
|
INFO_LOG(DVDINTERFACE, "Unlock test 2 passed");
|
||||||
}
|
}
|
||||||
|
@ -1041,45 +1224,20 @@ void ExecuteCommand()
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
PanicAlertT("Unknown DVD command %08x - fatal error", m_DICMDBUF[0].Hex);
|
ERROR_LOG(DVDINTERFACE, "Unknown command 0x%08x (Buffer 0x%08x, 0x%x)",
|
||||||
_dbg_assert_(DVDINTERFACE, 0);
|
command_0, output_address, output_length);
|
||||||
|
PanicAlertT("Unknown DVD command %08x - fatal error", command_0);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (ticks_until_TC)
|
return result;
|
||||||
{
|
|
||||||
// The transfer is finished after a delay
|
|
||||||
CoreTiming::ScheduleEvent((int)ticks_until_TC, tc);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// transfer is done
|
|
||||||
m_DICR.TSTART = 0;
|
|
||||||
m_DILENGTH.Length = 0;
|
|
||||||
GenerateDIInterrupt(INT_TCINT);
|
|
||||||
g_ErrorCode = 0;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Simulates the timing aspects of reading data from a disc.
|
// Simulates the timing aspects of reading data from a disc.
|
||||||
// Sets g_last_read_offset and g_last_read_time, and returns ticks_until_TC.
|
// Returns the amount of ticks needed to finish executing the command,
|
||||||
u64 SimulateDiscReadTime()
|
// and sets some state that is used the next time this function runs.
|
||||||
|
u64 SimulateDiscReadTime(u64 offset, u32 length)
|
||||||
{
|
{
|
||||||
u64 DVD_offset = (u64)m_DICMDBUF[1].Hex << 2;
|
|
||||||
u64 current_time = CoreTiming::GetTicks();
|
|
||||||
u64 ticks_until_TC;
|
|
||||||
|
|
||||||
if (SConfig::GetInstance().m_LocalCoreStartupParameter.bFastDiscSpeed)
|
|
||||||
{
|
|
||||||
// Make sure fast disc speed performs "instant" reads; in addition
|
|
||||||
// to being used to speed up games, fast disc speed is used as a
|
|
||||||
// workaround for crashes in certain games, including Star Wars
|
|
||||||
// Rogue Leader.
|
|
||||||
ticks_until_TC = 0;
|
|
||||||
g_last_read_time = current_time;
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
// The drive buffers 1 MiB (?) of data after every read request;
|
// The drive buffers 1 MiB (?) of data after every read request;
|
||||||
// if a read request is covered by this buffer (or if it's
|
// if a read request is covered by this buffer (or if it's
|
||||||
// faster to wait for the data to be buffered), the drive
|
// faster to wait for the data to be buffered), the drive
|
||||||
|
@ -1103,17 +1261,20 @@ u64 SimulateDiscReadTime()
|
||||||
// We can refine this if someone comes up with a more complete
|
// We can refine this if someone comes up with a more complete
|
||||||
// model for seek times.
|
// model for seek times.
|
||||||
|
|
||||||
|
u64 current_time = CoreTiming::GetTicks();
|
||||||
|
u64 ticks_until_completion;
|
||||||
|
|
||||||
// Number of ticks it takes to seek and read directly from the disk.
|
// Number of ticks it takes to seek and read directly from the disk.
|
||||||
u64 disk_read_duration = CalculateRawDiscReadTime(DVD_offset, m_DILENGTH.Length) +
|
u64 disk_read_duration = CalculateRawDiscReadTime(offset, length) +
|
||||||
SystemTimers::GetTicksPerSecond() / 1000 * DISC_ACCESS_TIME_MS;
|
SystemTimers::GetTicksPerSecond() / 1000 * DISC_ACCESS_TIME_MS;
|
||||||
|
|
||||||
if (DVD_offset + m_DILENGTH.Length - g_last_read_offset > 1024 * 1024)
|
if (offset + length - g_last_read_offset > 1024 * 1024)
|
||||||
{
|
{
|
||||||
// No buffer; just use the simple seek time + read time.
|
// No buffer; just use the simple seek time + read time.
|
||||||
DEBUG_LOG(DVDINTERFACE, "Seeking %" PRId64 " bytes",
|
DEBUG_LOG(DVDINTERFACE, "Seeking %" PRId64 " bytes",
|
||||||
s64(g_last_read_offset) - s64(DVD_offset));
|
s64(g_last_read_offset) - s64(offset));
|
||||||
ticks_until_TC = disk_read_duration;
|
ticks_until_completion = disk_read_duration;
|
||||||
g_last_read_time = current_time + ticks_until_TC;
|
g_last_read_time = current_time + ticks_until_completion;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -1124,37 +1285,36 @@ u64 SimulateDiscReadTime()
|
||||||
// Time at which the buffer will contain the data we need.
|
// Time at which the buffer will contain the data we need.
|
||||||
u64 buffer_fill_time = g_last_read_time +
|
u64 buffer_fill_time = g_last_read_time +
|
||||||
CalculateRawDiscReadTime(g_last_read_offset,
|
CalculateRawDiscReadTime(g_last_read_offset,
|
||||||
DVD_offset + m_DILENGTH.Length - g_last_read_offset);
|
offset + length - g_last_read_offset);
|
||||||
// Number of ticks it takes to transfer the data from the buffer to memory.
|
// Number of ticks it takes to transfer the data from the buffer to memory.
|
||||||
u64 buffer_read_duration = m_DILENGTH.Length *
|
u64 buffer_read_duration = length *
|
||||||
(SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE);
|
(SystemTimers::GetTicksPerSecond() / BUFFER_TRANSFER_RATE);
|
||||||
|
|
||||||
if (current_time > buffer_fill_time)
|
if (current_time > buffer_fill_time)
|
||||||
{
|
{
|
||||||
DEBUG_LOG(DVDINTERFACE, "Fast buffer read at %" PRId64, s64(DVD_offset));
|
DEBUG_LOG(DVDINTERFACE, "Fast buffer read at %" PRIx64, offset);
|
||||||
ticks_until_TC = buffer_read_duration;
|
ticks_until_completion = buffer_read_duration;
|
||||||
g_last_read_time = buffer_fill_time;
|
g_last_read_time = buffer_fill_time;
|
||||||
}
|
}
|
||||||
else if (current_time + disk_read_duration > buffer_fill_time)
|
else if (current_time + disk_read_duration > buffer_fill_time)
|
||||||
{
|
{
|
||||||
DEBUG_LOG(DVDINTERFACE, "Slow buffer read at %" PRId64, s64(DVD_offset));
|
DEBUG_LOG(DVDINTERFACE, "Slow buffer read at %" PRIx64, offset);
|
||||||
ticks_until_TC = std::max(buffer_fill_time - current_time,
|
ticks_until_completion = std::max(buffer_fill_time - current_time,
|
||||||
buffer_read_duration);
|
buffer_read_duration);
|
||||||
g_last_read_time = buffer_fill_time;
|
g_last_read_time = buffer_fill_time;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
DEBUG_LOG(DVDINTERFACE, "Short seek %" PRId64 " bytes",
|
DEBUG_LOG(DVDINTERFACE, "Short seek %" PRId64 " bytes",
|
||||||
s64(g_last_read_offset) - s64(DVD_offset));
|
s64(g_last_read_offset) - s64(offset));
|
||||||
ticks_until_TC = disk_read_duration;
|
ticks_until_completion = disk_read_duration;
|
||||||
g_last_read_time = current_time + ticks_until_TC;
|
g_last_read_time = current_time + ticks_until_completion;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
g_last_read_offset = (DVD_offset + m_DILENGTH.Length - 2048) & ~2047;
|
g_last_read_offset = (offset + length - 2048) & ~2047;
|
||||||
|
|
||||||
return ticks_until_TC;
|
return ticks_until_completion;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Returns the number of ticks it takes to read an amount of
|
// Returns the number of ticks it takes to read an amount of
|
||||||
|
@ -1199,6 +1359,7 @@ s64 CalculateRawDiscReadTime(u64 offset, s64 length)
|
||||||
speed = std::sqrt(((average_offset - GC_DISC_LOCATION_1_OFFSET) /
|
speed = std::sqrt(((average_offset - GC_DISC_LOCATION_1_OFFSET) /
|
||||||
GC_BYTES_PER_AREA_UNIT + GC_DISC_AREA_UP_TO_LOCATION_1) / PI);
|
GC_BYTES_PER_AREA_UNIT + GC_DISC_AREA_UP_TO_LOCATION_1) / PI);
|
||||||
}
|
}
|
||||||
|
DEBUG_LOG(DVDINTERFACE, "Disc speed: %f MiB/s", speed / 1024 / 1024);
|
||||||
|
|
||||||
return (s64)(SystemTimers::GetTicksPerSecond() / speed * length);
|
return (s64)(SystemTimers::GetTicksPerSecond() / speed * length);
|
||||||
}
|
}
|
||||||
|
|
|
@ -13,35 +13,13 @@ namespace MMIO { class Mapping; }
|
||||||
namespace DVDInterface
|
namespace DVDInterface
|
||||||
{
|
{
|
||||||
|
|
||||||
void Init();
|
|
||||||
void Shutdown();
|
|
||||||
void DoState(PointerWrap &p);
|
|
||||||
|
|
||||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
|
||||||
|
|
||||||
// Disc detection and swapping
|
|
||||||
void SetDiscInside(bool _DiscInside);
|
|
||||||
bool IsDiscInside();
|
|
||||||
void ChangeDisc(const std::string& fileName);
|
|
||||||
|
|
||||||
// Lid Functions
|
|
||||||
void SetLidOpen(bool _bOpen = true);
|
|
||||||
bool IsLidOpen();
|
|
||||||
|
|
||||||
// Used as low level control by WII_IPC_HLE_Device_DI
|
|
||||||
void ClearCoverInterrupt();
|
|
||||||
|
|
||||||
// DVD Access Functions
|
|
||||||
bool DVDRead(u32 _iDVDOffset, u32 _iRamAddress, u32 _iLength);
|
|
||||||
extern bool g_bStream;
|
|
||||||
|
|
||||||
// Not sure about endianness here. I'll just name them like this...
|
// Not sure about endianness here. I'll just name them like this...
|
||||||
enum DIErrorLow
|
enum DIErrorLow
|
||||||
{
|
{
|
||||||
ERROR_READY = 0x00000000, // Ready.
|
ERROR_READY = 0x00000000, // Ready.
|
||||||
ERROR_COVER_L = 0x01000000, // Cover is opened.
|
ERROR_COVER_L = 0x01000000, // Cover is opened.
|
||||||
ERROR_CHANGE_DISK = 0x02000000, // Disk change.
|
ERROR_CHANGE_DISK = 0x02000000, // Disk change.
|
||||||
ERROR_NO_DISK = 0x03000000, // No Disk.
|
ERROR_NO_DISK = 0x03000000, // No disk.
|
||||||
ERROR_MOTOR_STOP_L = 0x04000000, // Motor stop.
|
ERROR_MOTOR_STOP_L = 0x04000000, // Motor stop.
|
||||||
ERROR_NO_DISKID_L = 0x05000000 // Disk ID not read.
|
ERROR_NO_DISKID_L = 0x05000000 // Disk ID not read.
|
||||||
};
|
};
|
||||||
|
@ -51,13 +29,13 @@ enum DIErrorHigh
|
||||||
ERROR_MOTOR_STOP_H = 0x020400, // Motor stopped.
|
ERROR_MOTOR_STOP_H = 0x020400, // Motor stopped.
|
||||||
ERROR_NO_DISKID_H = 0x020401, // Disk ID not read.
|
ERROR_NO_DISKID_H = 0x020401, // Disk ID not read.
|
||||||
ERROR_COVER_H = 0x023a00, // Medium not present / Cover opened.
|
ERROR_COVER_H = 0x023a00, // Medium not present / Cover opened.
|
||||||
ERROR_SEEK_NDONE = 0x030200, // No Seek complete.
|
ERROR_SEEK_NDONE = 0x030200, // No seek complete.
|
||||||
ERROR_READ = 0x031100, // UnRecoverd read error.
|
ERROR_READ = 0x031100, // Unrecovered read error.
|
||||||
ERROR_PROTOCOL = 0x040800, // Transfer protocol error.
|
ERROR_PROTOCOL = 0x040800, // Transfer protocol error.
|
||||||
ERROR_INV_CMD = 0x052000, // Invalid command operation code.
|
ERROR_INV_CMD = 0x052000, // Invalid command operation code.
|
||||||
ERROR_AUDIO_BUF = 0x052001, // Audio Buffer not set.
|
ERROR_AUDIO_BUF = 0x052001, // Audio Buffer not set.
|
||||||
ERROR_BLOCK_OOB = 0x052100, // Logical block address out of bounds.
|
ERROR_BLOCK_OOB = 0x052100, // Logical block address out of bounds.
|
||||||
ERROR_INV_FIELD = 0x052400, // Invalid Field in command packet.
|
ERROR_INV_FIELD = 0x052400, // Invalid field in command packet.
|
||||||
ERROR_INV_AUDIO = 0x052401, // Invalid audio command.
|
ERROR_INV_AUDIO = 0x052401, // Invalid audio command.
|
||||||
ERROR_INV_PERIOD = 0x052402, // Configuration out of permitted period.
|
ERROR_INV_PERIOD = 0x052402, // Configuration out of permitted period.
|
||||||
ERROR_END_USR_AREA = 0x056300, // End of user area encountered on this track.
|
ERROR_END_USR_AREA = 0x056300, // End of user area encountered on this track.
|
||||||
|
@ -99,4 +77,39 @@ enum DICommand
|
||||||
DVDLowAudioBufferConfig = 0xe4
|
DVDLowAudioBufferConfig = 0xe4
|
||||||
};
|
};
|
||||||
|
|
||||||
|
enum DIInterruptType
|
||||||
|
{
|
||||||
|
INT_DEINT = 0,
|
||||||
|
INT_TCINT = 1,
|
||||||
|
INT_BRKINT = 2,
|
||||||
|
INT_CVRINT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
struct DVDCommandResult
|
||||||
|
{
|
||||||
|
DIInterruptType interrupt_type;
|
||||||
|
u64 ticks_until_completion;
|
||||||
|
};
|
||||||
|
|
||||||
|
void Init();
|
||||||
|
void Shutdown();
|
||||||
|
void DoState(PointerWrap &p);
|
||||||
|
|
||||||
|
void RegisterMMIO(MMIO::Mapping* mmio, u32 base);
|
||||||
|
|
||||||
|
// Disc detection and swapping
|
||||||
|
void SetDiscInside(bool _DiscInside);
|
||||||
|
bool IsDiscInside();
|
||||||
|
void ChangeDisc(const std::string& fileName);
|
||||||
|
|
||||||
|
// Lid Functions
|
||||||
|
void SetLidOpen(bool _bOpen = true);
|
||||||
|
bool IsLidOpen();
|
||||||
|
|
||||||
|
// DVD Access Functions
|
||||||
|
bool DVDRead(u64 _iDVDOffset, u32 _iRamAddress, u32 _iLength, bool raw = false);
|
||||||
|
extern bool g_bStream;
|
||||||
|
DVDCommandResult ExecuteCommand(u32 command_0, u32 command_1, u32 command_2,
|
||||||
|
u32 output_address, u32 output_length, bool write_to_DIIMMBUF);
|
||||||
|
|
||||||
} // end of namespace DVDInterface
|
} // end of namespace DVDInterface
|
||||||
|
|
|
@ -7,9 +7,7 @@
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/Logging/LogManager.h"
|
#include "Common/Logging/LogManager.h"
|
||||||
|
|
||||||
#include "Core/Core.h"
|
|
||||||
#include "Core/VolumeHandler.h"
|
#include "Core/VolumeHandler.h"
|
||||||
#include "Core/HW/CPU.h"
|
|
||||||
#include "Core/HW/DVDInterface.h"
|
#include "Core/HW/DVDInterface.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/HW/SystemTimers.h"
|
#include "Core/HW/SystemTimers.h"
|
||||||
|
@ -17,40 +15,17 @@
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE.h"
|
||||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h"
|
#include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h"
|
||||||
|
|
||||||
#include "DiscIO/FileMonitor.h"
|
|
||||||
#include "DiscIO/Filesystem.h"
|
|
||||||
#include "DiscIO/VolumeCreator.h"
|
|
||||||
|
|
||||||
using namespace DVDInterface;
|
using namespace DVDInterface;
|
||||||
|
|
||||||
|
|
||||||
#define DI_COVER_REG_INITIALIZED 0 // Should be 4, but doesn't work correctly...
|
|
||||||
#define DI_COVER_REG_NO_DISC 1
|
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName )
|
CWII_IPC_HLE_Device_di::CWII_IPC_HLE_Device_di(u32 _DeviceID, const std::string& _rDeviceName )
|
||||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||||
, m_pFileSystem(nullptr)
|
|
||||||
, m_ErrorStatus(0)
|
|
||||||
, m_CoverStatus(DI_COVER_REG_NO_DISC)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
|
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
|
||||||
{
|
{}
|
||||||
if (m_pFileSystem)
|
|
||||||
{
|
|
||||||
delete m_pFileSystem;
|
|
||||||
m_pFileSystem = nullptr;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode)
|
bool CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
{
|
{
|
||||||
if (VolumeHandler::IsValid())
|
|
||||||
{
|
|
||||||
m_pFileSystem = DiscIO::CreateFileSystem(VolumeHandler::GetVolume());
|
|
||||||
m_CoverStatus |= DI_COVER_REG_INITIALIZED;
|
|
||||||
m_CoverStatus &= ~DI_COVER_REG_NO_DISC;
|
|
||||||
}
|
|
||||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
||||||
m_Active = true;
|
m_Active = true;
|
||||||
return true;
|
return true;
|
||||||
|
@ -58,12 +33,6 @@ bool CWII_IPC_HLE_Device_di::Open(u32 _CommandAddress, u32 _Mode)
|
||||||
|
|
||||||
bool CWII_IPC_HLE_Device_di::Close(u32 _CommandAddress, bool _bForce)
|
bool CWII_IPC_HLE_Device_di::Close(u32 _CommandAddress, bool _bForce)
|
||||||
{
|
{
|
||||||
if (m_pFileSystem)
|
|
||||||
{
|
|
||||||
delete m_pFileSystem;
|
|
||||||
m_pFileSystem = nullptr;
|
|
||||||
}
|
|
||||||
m_ErrorStatus = 0;
|
|
||||||
if (!_bForce)
|
if (!_bForce)
|
||||||
Memory::Write_U32(0, _CommandAddress + 4);
|
Memory::Write_U32(0, _CommandAddress + 4);
|
||||||
m_Active = false;
|
m_Active = false;
|
||||||
|
@ -76,14 +45,26 @@ bool CWII_IPC_HLE_Device_di::IOCtl(u32 _CommandAddress)
|
||||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||||
u32 Command = Memory::Read_U32(BufferIn) >> 24;
|
|
||||||
|
u32 command_0 = Memory::Read_U32(BufferIn);
|
||||||
|
u32 command_1 = Memory::Read_U32(BufferIn + 4);
|
||||||
|
u32 command_2 = Memory::Read_U32(BufferIn + 8);
|
||||||
|
|
||||||
DEBUG_LOG(WII_IPC_DVD, "IOCtl Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)",
|
DEBUG_LOG(WII_IPC_DVD, "IOCtl Command(0x%08x) BufferIn(0x%08x, 0x%x) BufferOut(0x%08x, 0x%x)",
|
||||||
Command, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
command_0, BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
||||||
|
|
||||||
u32 ReturnValue = ExecuteCommand(BufferIn, BufferInSize, BufferOut, BufferOutSize);
|
// TATSUNOKO VS CAPCOM: Gets here with BufferOut == 0!!!
|
||||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
if (BufferOut != 0)
|
||||||
|
{
|
||||||
|
// Set out buffer to zeroes as a safety precaution
|
||||||
|
// to avoid answering nonsense values
|
||||||
|
Memory::Memset(BufferOut, 0, BufferOutSize);
|
||||||
|
}
|
||||||
|
|
||||||
|
DVDCommandResult result = ExecuteCommand(command_0, command_1, command_2,
|
||||||
|
BufferOut, BufferOutSize, false);
|
||||||
|
Memory::Write_U32(result.interrupt_type, _CommandAddress + 0x4);
|
||||||
|
// TODO: Don't discard result.ticks_until_completion
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -135,318 +116,6 @@ bool CWII_IPC_HLE_Device_di::IOCtlV(u32 _CommandAddress)
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32 _BufferOut, u32 _BufferOutSize)
|
|
||||||
{
|
|
||||||
u32 Command = Memory::Read_U32(_BufferIn) >> 24;
|
|
||||||
|
|
||||||
// TATSUNOKO VS CAPCOM: Gets here with _BufferOut == 0!!!
|
|
||||||
if (_BufferOut != 0)
|
|
||||||
{
|
|
||||||
// Set out buffer to zeroes as a safety precaution to avoid answering
|
|
||||||
// nonsense values
|
|
||||||
Memory::Memset(_BufferOut, 0, _BufferOutSize);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Initializing a filesystem if it was just loaded
|
|
||||||
if (!m_pFileSystem && VolumeHandler::IsValid())
|
|
||||||
{
|
|
||||||
m_pFileSystem = DiscIO::CreateFileSystem(VolumeHandler::GetVolume());
|
|
||||||
m_CoverStatus |= DI_COVER_REG_INITIALIZED;
|
|
||||||
m_CoverStatus &= ~DI_COVER_REG_NO_DISC;
|
|
||||||
}
|
|
||||||
|
|
||||||
// De-initializing a filesystem if the volume was unmounted
|
|
||||||
if (m_pFileSystem && !VolumeHandler::IsValid())
|
|
||||||
{
|
|
||||||
delete m_pFileSystem;
|
|
||||||
m_pFileSystem = nullptr;
|
|
||||||
m_CoverStatus |= DI_COVER_REG_NO_DISC;
|
|
||||||
}
|
|
||||||
|
|
||||||
switch (Command)
|
|
||||||
{
|
|
||||||
case DVDLowInquiry:
|
|
||||||
{
|
|
||||||
// (shuffle2) Taken from my Wii
|
|
||||||
Memory::Write_U32(0x00000002, _BufferOut);
|
|
||||||
Memory::Write_U32(0x20060526, _BufferOut + 4);
|
|
||||||
// This was in the oubuf even though this cmd is only supposed to reply with 64bits
|
|
||||||
// However, this and other tests strongly suggest that the buffer is static, and it's never - or rarely cleared.
|
|
||||||
Memory::Write_U32(0x41000000, _BufferOut + 8);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowInquiry (Buffer 0x%08x, 0x%x)",
|
|
||||||
_BufferOut, _BufferOutSize);
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDiskID:
|
|
||||||
{
|
|
||||||
VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), 0, _BufferOutSize);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowReadDiskID %s",
|
|
||||||
ArrayToString(Memory::GetPointer(_BufferOut), _BufferOutSize, _BufferOutSize).c_str());
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowRead:
|
|
||||||
{
|
|
||||||
if (_BufferOut == 0)
|
|
||||||
{
|
|
||||||
PanicAlert("DVDLowRead : _BufferOut == 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
u32 Size = Memory::Read_U32(_BufferIn + 0x04);
|
|
||||||
u64 DVDAddress = (u64)Memory::Read_U32(_BufferIn + 0x08) << 2;
|
|
||||||
|
|
||||||
// Don't do anything if the log is unselected
|
|
||||||
if (LogManager::GetInstance()->IsEnabled(LogTypes::FILEMON))
|
|
||||||
{
|
|
||||||
if (m_pFileSystem)
|
|
||||||
{
|
|
||||||
const std::string filename = m_pFileSystem->GetFileName(DVDAddress);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowRead: %s (0x%" PRIx64 ") - (DVDAddr: 0x%" PRIx64 ", Size: 0x%x)",
|
|
||||||
filename.c_str(), m_pFileSystem->GetFileSize(filename), DVDAddress, Size);
|
|
||||||
FileMon::CheckFile(filename, (int)m_pFileSystem->GetFileSize(filename));
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "Filesystem is invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (Size > _BufferOutSize)
|
|
||||||
{
|
|
||||||
PanicAlertT("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
|
||||||
Size = _BufferOutSize;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!VolumeHandler::ReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
|
|
||||||
{
|
|
||||||
PanicAlertT("DVDLowRead - Fatal Error: failed to read from volume");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowWaitForCoverClose:
|
|
||||||
{
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowWaitForCoverClose (Buffer 0x%08x, 0x%x)",
|
|
||||||
_BufferOut, _BufferOutSize);
|
|
||||||
return 4; // ???
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowGetCoverReg:
|
|
||||||
Memory::Write_U32(m_CoverStatus, _BufferOut);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowGetCoverReg 0x%08x", Memory::Read_U32(_BufferOut));
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowNotifyReset:
|
|
||||||
PanicAlert("DVDLowNotifyReset");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDvdPhysical:
|
|
||||||
PanicAlert("DVDLowReadDvdPhysical");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDvdCopyright:
|
|
||||||
PanicAlert("DVDLowReadDvdCopyright");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDvdDiscKey:
|
|
||||||
PanicAlert("DVDLowReadDvdDiscKey");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowClearCoverInterrupt:
|
|
||||||
// TODO: check (seems to work ok)
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowClearCoverInterrupt");
|
|
||||||
ClearCoverInterrupt();
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowGetCoverStatus:
|
|
||||||
Memory::Write_U32(IsDiscInside() ? 2 : 1, _BufferOut);
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowGetCoverStatus: Disc %sInserted", IsDiscInside() ? "" : "Not ");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReset:
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowReset");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowClosePartition:
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowClosePartition");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowUnencryptedRead:
|
|
||||||
{
|
|
||||||
if (_BufferOut == 0)
|
|
||||||
{
|
|
||||||
PanicAlert("DVDLowRead : _BufferOut == 0");
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u32 Size = Memory::Read_U32(_BufferIn + 0x04);
|
|
||||||
|
|
||||||
// We must make sure it is in a valid area! (#001 check)
|
|
||||||
// * 0x00000000 - 0x00014000 (limit of older IOS versions)
|
|
||||||
// * 0x460a0000 - 0x460a0008
|
|
||||||
// * 0x7ed40000 - 0x7ed40008
|
|
||||||
u32 DVDAddress32 = Memory::Read_U32(_BufferIn + 0x08);
|
|
||||||
if (!((DVDAddress32 > 0x00000000 && DVDAddress32 < 0x00014000) ||
|
|
||||||
(((DVDAddress32 + Size) > 0x00000000) && (DVDAddress32 + Size) < 0x00014000) ||
|
|
||||||
(DVDAddress32 > 0x460a0000 && DVDAddress32 < 0x460a0008) ||
|
|
||||||
(((DVDAddress32 + Size) > 0x460a0000) && (DVDAddress32 + Size) < 0x460a0008) ||
|
|
||||||
(DVDAddress32 > 0x7ed40000 && DVDAddress32 < 0x7ed40008) ||
|
|
||||||
(((DVDAddress32 + Size) > 0x7ed40000) && (DVDAddress32 + Size) < 0x7ed40008)))
|
|
||||||
{
|
|
||||||
WARN_LOG(WII_IPC_DVD, "DVDLowUnencryptedRead: trying to read out of bounds @ %x", DVDAddress32);
|
|
||||||
m_ErrorStatus = ERROR_READY | ERROR_BLOCK_OOB;
|
|
||||||
// Should cause software to call DVDLowRequestError
|
|
||||||
return 2;
|
|
||||||
}
|
|
||||||
|
|
||||||
u64 DVDAddress = (u64)DVDAddress32 << 2;
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowUnencryptedRead: DVDAddr: 0x%08" PRIx64 ", Size: 0x%x", DVDAddress, Size);
|
|
||||||
|
|
||||||
if (Size > _BufferOutSize)
|
|
||||||
{
|
|
||||||
PanicAlertT("Detected attempt to read more data from the DVD than fit inside the out buffer. Clamp.");
|
|
||||||
Size = _BufferOutSize;
|
|
||||||
}
|
|
||||||
if (!VolumeHandler::RAWReadToPtr(Memory::GetPointer(_BufferOut), DVDAddress, Size))
|
|
||||||
{
|
|
||||||
PanicAlertT("DVDLowUnencryptedRead - Fatal Error: failed to read from volume");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowEnableDvdVideo:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowEnableDvdVideo");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReportKey:
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowReportKey");
|
|
||||||
// Does not work on retail discs/drives
|
|
||||||
// Retail games send this command to see if they are running on real retail hw
|
|
||||||
m_ErrorStatus = ERROR_READY | ERROR_INV_CMD;
|
|
||||||
return 2;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowSeek:
|
|
||||||
{
|
|
||||||
u64 DVDAddress = Memory::Read_U32(_BufferIn + 0x4) << 2;
|
|
||||||
|
|
||||||
if (m_pFileSystem)
|
|
||||||
{
|
|
||||||
const std::string filename = m_pFileSystem->GetFileName(DVDAddress);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowSeek: %s (0x%" PRIx64 ") - (DVDAddr: 0x%" PRIx64 ")",
|
|
||||||
filename.c_str(), m_pFileSystem->GetFileSize(filename), DVDAddress);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "Filesystem is invalid.");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDvd:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowReadDvd");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDvdConfig:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowReadDvdConfig");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowStopLaser:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowStopLaser");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowOffset:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowOffset");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowReadDiskBca:
|
|
||||||
WARN_LOG(WII_IPC_DVD, "DVDLowReadDiskBca");
|
|
||||||
Memory::Write_U32(1, _BufferOut + 0x30);
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowRequestDiscStatus:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowRequestDiscStatus");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowRequestRetryNumber:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowRequestRetryNumber");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowSetMaximumRotation:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowSetMaximumRotation");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowSerMeasControl:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowSerMeasControl");
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowRequestError:
|
|
||||||
// Identical to the error codes found in yagcd section 5.7.3.5.1 (so far)
|
|
||||||
WARN_LOG(WII_IPC_DVD, "DVDLowRequestError status = 0x%08x", m_ErrorStatus);
|
|
||||||
Memory::Write_U32(m_ErrorStatus, _BufferOut);
|
|
||||||
// When does error status get reset?
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Ex commands are immediate and respond with 4 bytes
|
|
||||||
case DVDLowStopMotor:
|
|
||||||
{
|
|
||||||
u32 eject = Memory::Read_U32(_BufferIn + 4);
|
|
||||||
// Drive won't do anything till reset is issued. I think it replies like nothing is wrong though?
|
|
||||||
u32 kill = Memory::Read_U32(_BufferIn + 8);
|
|
||||||
|
|
||||||
INFO_LOG(WII_IPC_DVD, "DVDLowStopMotor %s %s",
|
|
||||||
eject ? "eject" : "", kill ? "kill!" : "");
|
|
||||||
|
|
||||||
if (eject)
|
|
||||||
{
|
|
||||||
SetLidOpen(true);
|
|
||||||
SetDiscInside(false);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DVDLowAudioBufferConfig:
|
|
||||||
/*
|
|
||||||
For more information: http://www.crazynation.org/GC/GC_DD_TECH/GCTech.htm
|
|
||||||
|
|
||||||
Upon Power up or reset , 2 commands must be issued for proper use of audio streaming:
|
|
||||||
DVDReadDiskID A8000040,00000000,00000020
|
|
||||||
DVDLowAudioBufferConfig E4xx00yy,00000000,00000020
|
|
||||||
|
|
||||||
xx=byte 8 [0 or 1] from the disk header retrieved from DVDReadDiskID
|
|
||||||
yy=0 (if xx=0) or 0xA (if xx=1)
|
|
||||||
*/
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "DVDLowAudioBufferConfig");
|
|
||||||
break;
|
|
||||||
|
|
||||||
// New Super Mario Bros.Wii sends these cmds
|
|
||||||
// but it seems we don't need to implement anything
|
|
||||||
case 0x95:
|
|
||||||
case 0x96:
|
|
||||||
WARN_LOG(WII_IPC_DVD, "Unimplemented command 0x%08x (Buffer 0x%08x, 0x%x)",
|
|
||||||
Command, _BufferOut, _BufferOutSize);
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
ERROR_LOG(WII_IPC_DVD, "Unknown command 0x%08x (Buffer 0x%08x, 0x%x)",
|
|
||||||
Command, _BufferOut, _BufferOutSize);
|
|
||||||
|
|
||||||
PanicAlertT("Unknown command 0x%08x", Command);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// i dunno but prolly 1 is okay all the time :)
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
|
int CWII_IPC_HLE_Device_di::GetCmdDelay(u32 _CommandAddress)
|
||||||
{
|
{
|
||||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||||
|
|
|
@ -27,13 +27,4 @@ public:
|
||||||
bool IOCtlV(u32 _CommandAddress) override;
|
bool IOCtlV(u32 _CommandAddress) override;
|
||||||
|
|
||||||
int GetCmdDelay(u32) override;
|
int GetCmdDelay(u32) override;
|
||||||
|
|
||||||
private:
|
|
||||||
|
|
||||||
u32 ExecuteCommand(u32 BufferIn, u32 BufferInSize, u32 _BufferOut, u32 BufferOutSize);
|
|
||||||
|
|
||||||
DiscIO::IFileSystem* m_pFileSystem;
|
|
||||||
u32 m_ErrorStatus;
|
|
||||||
// This flag seems to only be reset with poweron/off, not sure
|
|
||||||
u32 m_CoverStatus;
|
|
||||||
};
|
};
|
||||||
|
|
Loading…
Reference in New Issue