mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-26 07:45:33 +01:00
Track drive state better, reporting errors if the state is wrong
Also, fix DVDLowStopMotor logging (which was based on the ioctl parameters)
This commit is contained in:
parent
7d6b9bcb40
commit
55a88ba2ed
@ -244,6 +244,17 @@ bool CBoot::DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_a
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool CBoot::DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address)
|
||||||
|
{
|
||||||
|
std::array<u8, 0x20> buffer;
|
||||||
|
if (!disc.Read(0, buffer.size(), buffer.data(), DiscIO::PARTITION_NONE))
|
||||||
|
return false;
|
||||||
|
Memory::CopyToEmu(output_address, buffer.data(), buffer.size());
|
||||||
|
// Clear ERROR_NO_DISKID_L, probably should check if that's currently set
|
||||||
|
DVDInterface::SetLowError(DVDInterface::ERROR_READY);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
void CBoot::UpdateDebugger_MapLoaded()
|
void CBoot::UpdateDebugger_MapLoaded()
|
||||||
{
|
{
|
||||||
Host_NotifyMapLoaded();
|
Host_NotifyMapLoaded();
|
||||||
|
@ -104,6 +104,7 @@ public:
|
|||||||
private:
|
private:
|
||||||
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
|
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
|
||||||
u32 length, const DiscIO::Partition& partition);
|
u32 length, const DiscIO::Partition& partition);
|
||||||
|
static bool DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address);
|
||||||
static void RunFunction(u32 address);
|
static void RunFunction(u32 address);
|
||||||
|
|
||||||
static void UpdateDebugger_MapLoaded();
|
static void UpdateDebugger_MapLoaded();
|
||||||
|
@ -210,7 +210,7 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume)
|
|||||||
|
|
||||||
SetupGCMemory();
|
SetupGCMemory();
|
||||||
|
|
||||||
DVDRead(volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, DiscIO::PARTITION_NONE);
|
DVDReadDiscID(volume, 0x00000000);
|
||||||
|
|
||||||
const bool ntsc = DiscIO::IsNTSC(SConfig::GetInstance().m_region);
|
const bool ntsc = DiscIO::IsNTSC(SConfig::GetInstance().m_region);
|
||||||
|
|
||||||
@ -406,7 +406,7 @@ bool CBoot::EmulatedBS2_Wii(const DiscIO::VolumeDisc& volume)
|
|||||||
if (!SetupWiiMemory(console_type) || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId()))
|
if (!SetupWiiMemory(console_type) || !IOS::HLE::GetIOS()->BootIOS(tmd.GetIOSId()))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
DVDRead(volume, 0x00000000, 0x00000000, 0x20, DiscIO::PARTITION_NONE); // Game Code
|
DVDReadDiscID(volume, 0x00000000);
|
||||||
|
|
||||||
// This is some kind of consistency check that is compared to the 0x00
|
// This is some kind of consistency check that is compared to the 0x00
|
||||||
// values as the game boots. This location keeps the 4 byte ID for as long
|
// values as the game boots. This location keeps the 4 byte ID for as long
|
||||||
|
@ -344,8 +344,10 @@ void Init()
|
|||||||
}
|
}
|
||||||
|
|
||||||
// This doesn't reset any inserted disc or the cover state.
|
// This doesn't reset any inserted disc or the cover state.
|
||||||
void Reset()
|
void Reset(bool spinup)
|
||||||
{
|
{
|
||||||
|
INFO_LOG(DVDINTERFACE, "Reset %s spinup", spinup ? "with" : "without");
|
||||||
|
|
||||||
s_DISR.Hex = 0;
|
s_DISR.Hex = 0;
|
||||||
s_DICMDBUF[0] = 0;
|
s_DICMDBUF[0] = 0;
|
||||||
s_DICMDBUF[1] = 0;
|
s_DICMDBUF[1] = 0;
|
||||||
@ -366,15 +368,33 @@ void Reset()
|
|||||||
s_current_length = 0;
|
s_current_length = 0;
|
||||||
s_pending_samples = 0;
|
s_pending_samples = 0;
|
||||||
|
|
||||||
s_error_code = 0;
|
if (!IsDiscInside())
|
||||||
|
{
|
||||||
|
// ERROR_COVER is used when the cover is open;
|
||||||
|
// ERROR_NO_DISK_L is used when the cover is closed but there is no disc.
|
||||||
|
// On the Wii, this can only happen if something other than a DVD is inserted into the disc
|
||||||
|
// drive (for instance, an audio CD) and only after it attempts to read it. Otherwise, it will
|
||||||
|
// report the cover as opened.
|
||||||
|
SetLowError(ERROR_COVER);
|
||||||
|
}
|
||||||
|
else if (!spinup)
|
||||||
|
{
|
||||||
|
// Wii hardware tests indicate that this is used when ejecting and inserting a new disc, or
|
||||||
|
// performing a reset without spinup.
|
||||||
|
SetLowError(ERROR_CHANGE_DISK);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
SetLowError(ERROR_NO_DISKID_L);
|
||||||
|
}
|
||||||
|
|
||||||
|
SetHighError(ERROR_NONE);
|
||||||
|
|
||||||
// The buffer is empty at start
|
// The buffer is empty at start
|
||||||
s_read_buffer_start_offset = 0;
|
s_read_buffer_start_offset = 0;
|
||||||
s_read_buffer_end_offset = 0;
|
s_read_buffer_end_offset = 0;
|
||||||
s_read_buffer_start_time = 0;
|
s_read_buffer_start_time = 0;
|
||||||
s_read_buffer_end_time = 0;
|
s_read_buffer_end_time = 0;
|
||||||
|
|
||||||
s_disc_path_to_insert.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Shutdown()
|
void Shutdown()
|
||||||
@ -405,6 +425,8 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
|
|||||||
|
|
||||||
DVDThread::SetDisc(std::move(disc));
|
DVDThread::SetDisc(std::move(disc));
|
||||||
SetLidOpen();
|
SetLidOpen();
|
||||||
|
|
||||||
|
Reset(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsDiscInside()
|
bool IsDiscInside()
|
||||||
@ -658,15 +680,46 @@ void ClearInterrupt(DIInterruptType interrupt)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Checks the drive state to make sure a read-like command can be performed.
|
||||||
|
// If false is returned, SetHighError will have been called, and the caller
|
||||||
|
// should issue a DEINT interrupt.
|
||||||
|
static bool CheckReadPreconditions()
|
||||||
|
{
|
||||||
|
if (!IsDiscInside()) // Implies ERROR_COVER or ERROR_NO_DISK
|
||||||
|
{
|
||||||
|
ERROR_LOG(DVDINTERFACE, "No disc inside.");
|
||||||
|
SetHighError(ERROR_NO_DISK_H);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((s_error_code & LOW_ERROR_MASK) == ERROR_CHANGE_DISK)
|
||||||
|
{
|
||||||
|
ERROR_LOG(DVDINTERFACE, "Disc changed (motor stopped).");
|
||||||
|
SetHighError(ERROR_MEDIUM);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((s_error_code & LOW_ERROR_MASK) == ERROR_MOTOR_STOP_L)
|
||||||
|
{
|
||||||
|
ERROR_LOG(DVDINTERFACE, "Motor stopped.");
|
||||||
|
SetHighError(ERROR_MOTOR_STOP_H);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if ((s_error_code & LOW_ERROR_MASK) == ERROR_NO_DISKID_L)
|
||||||
|
{
|
||||||
|
ERROR_LOG(DVDINTERFACE, "Disc id not read.");
|
||||||
|
SetHighError(ERROR_NO_DISKID_H);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
// Iff false is returned, ScheduleEvent must be used to finish executing the command
|
// Iff false is returned, ScheduleEvent must be used to finish executing the command
|
||||||
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
|
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
|
||||||
const DiscIO::Partition& partition, ReplyType reply_type,
|
const DiscIO::Partition& partition, ReplyType reply_type,
|
||||||
DIInterruptType* interrupt_type)
|
DIInterruptType* interrupt_type)
|
||||||
{
|
{
|
||||||
if (!IsDiscInside())
|
if (!CheckReadPreconditions())
|
||||||
{
|
{
|
||||||
// Disc read fails
|
// Disc read fails
|
||||||
SetHighError(ERROR_NO_DISK_H);
|
|
||||||
*interrupt_type = DIInterruptType::DEINT;
|
*interrupt_type = DIInterruptType::DEINT;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
@ -747,6 +800,14 @@ void ExecuteCommand(ReplyType reply_type)
|
|||||||
|
|
||||||
case 0x40: // Read DiscID
|
case 0x40: // Read DiscID
|
||||||
INFO_LOG(DVDINTERFACE, "Read DiscID: buffer %08x", s_DIMAR);
|
INFO_LOG(DVDINTERFACE, "Read DiscID: buffer %08x", s_DIMAR);
|
||||||
|
// TODO: It doesn't make sense to include ERROR_CHANGE_DISK here, as it implies that the drive
|
||||||
|
// is not spinning and reading the disc ID shouldn't change it. However, the Wii Menu breaks
|
||||||
|
// without it.
|
||||||
|
if ((s_error_code & LOW_ERROR_MASK) == ERROR_NO_DISKID_L ||
|
||||||
|
(s_error_code & LOW_ERROR_MASK) == ERROR_CHANGE_DISK)
|
||||||
|
{
|
||||||
|
SetLowError(ERROR_READY);
|
||||||
|
}
|
||||||
command_handled_by_thread = ExecuteReadCommand(
|
command_handled_by_thread = ExecuteReadCommand(
|
||||||
0, s_DIMAR, 0x20, s_DILENGTH, DiscIO::PARTITION_NONE, reply_type, &interrupt_type);
|
0, s_DIMAR, 0x20, s_DILENGTH, DiscIO::PARTITION_NONE, reply_type, &interrupt_type);
|
||||||
break;
|
break;
|
||||||
@ -905,10 +966,12 @@ void ExecuteCommand(ReplyType reply_type)
|
|||||||
// Used by both GC and Wii
|
// Used by both GC and Wii
|
||||||
case DICommand::StopMotor:
|
case DICommand::StopMotor:
|
||||||
{
|
{
|
||||||
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", s_DICMDBUF[1] ? "eject" : "",
|
const bool eject = (s_DICMDBUF[0] & (1 << 17));
|
||||||
s_DICMDBUF[2] ? "kill!" : "");
|
const bool kill = (s_DICMDBUF[0] & (1 << 20));
|
||||||
|
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor%s%s", eject ? " eject" : "", kill ? " kill!" : "");
|
||||||
|
|
||||||
const bool force_eject = s_DICMDBUF[1] && !s_DICMDBUF[2];
|
SetLowError(ERROR_MOTOR_STOP_L);
|
||||||
|
const bool force_eject = eject && !kill;
|
||||||
|
|
||||||
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() &&
|
if (Config::Get(Config::MAIN_AUTO_DISC_CHANGE) && !Movie::IsPlayingInput() &&
|
||||||
DVDThread::IsInsertedDiscRunning() && !s_auto_disc_change_paths.empty())
|
DVDThread::IsInsertedDiscRunning() && !s_auto_disc_change_paths.empty())
|
||||||
|
@ -102,7 +102,7 @@ enum class EjectCause
|
|||||||
};
|
};
|
||||||
|
|
||||||
void Init();
|
void Init();
|
||||||
void Reset();
|
void Reset(bool spinup = true);
|
||||||
void Shutdown();
|
void Shutdown();
|
||||||
void DoState(PointerWrap& p);
|
void DoState(PointerWrap& p);
|
||||||
|
|
||||||
|
@ -249,7 +249,7 @@ std::optional<DI::DIResult> DI::StartIOCtl(const IOCtlRequest& request)
|
|||||||
{
|
{
|
||||||
const bool spinup = Memory::Read_U32(request.address + 4);
|
const bool spinup = Memory::Read_U32(request.address + 4);
|
||||||
INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without");
|
INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without");
|
||||||
DVDInterface::Reset();
|
DVDInterface::Reset(spinup);
|
||||||
ResetDIRegisters();
|
ResetDIRegisters();
|
||||||
// Should also reset current partition and such
|
// Should also reset current partition and such
|
||||||
return DIResult::Success;
|
return DIResult::Success;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user