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;
|
||||
}
|
||||
|
||||
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()
|
||||
{
|
||||
Host_NotifyMapLoaded();
|
||||
|
|
|
@ -104,6 +104,7 @@ public:
|
|||
private:
|
||||
static bool DVDRead(const DiscIO::VolumeDisc& disc, u64 dvd_offset, u32 output_address,
|
||||
u32 length, const DiscIO::Partition& partition);
|
||||
static bool DVDReadDiscID(const DiscIO::VolumeDisc& disc, u32 output_address);
|
||||
static void RunFunction(u32 address);
|
||||
|
||||
static void UpdateDebugger_MapLoaded();
|
||||
|
|
|
@ -210,7 +210,7 @@ bool CBoot::EmulatedBS2_GC(const DiscIO::VolumeDisc& volume)
|
|||
|
||||
SetupGCMemory();
|
||||
|
||||
DVDRead(volume, /*offset*/ 0x00000000, /*address*/ 0x00000000, 0x20, DiscIO::PARTITION_NONE);
|
||||
DVDReadDiscID(volume, 0x00000000);
|
||||
|
||||
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()))
|
||||
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
|
||||
// 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.
|
||||
void Reset()
|
||||
void Reset(bool spinup)
|
||||
{
|
||||
INFO_LOG(DVDINTERFACE, "Reset %s spinup", spinup ? "with" : "without");
|
||||
|
||||
s_DISR.Hex = 0;
|
||||
s_DICMDBUF[0] = 0;
|
||||
s_DICMDBUF[1] = 0;
|
||||
|
@ -366,15 +368,33 @@ void Reset()
|
|||
s_current_length = 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
|
||||
s_read_buffer_start_offset = 0;
|
||||
s_read_buffer_end_offset = 0;
|
||||
s_read_buffer_start_time = 0;
|
||||
s_read_buffer_end_time = 0;
|
||||
|
||||
s_disc_path_to_insert.clear();
|
||||
}
|
||||
|
||||
void Shutdown()
|
||||
|
@ -405,6 +425,8 @@ void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
|
|||
|
||||
DVDThread::SetDisc(std::move(disc));
|
||||
SetLidOpen();
|
||||
|
||||
Reset(false);
|
||||
}
|
||||
|
||||
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
|
||||
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
|
||||
const DiscIO::Partition& partition, ReplyType reply_type,
|
||||
DIInterruptType* interrupt_type)
|
||||
{
|
||||
if (!IsDiscInside())
|
||||
if (!CheckReadPreconditions())
|
||||
{
|
||||
// Disc read fails
|
||||
SetHighError(ERROR_NO_DISK_H);
|
||||
*interrupt_type = DIInterruptType::DEINT;
|
||||
return false;
|
||||
}
|
||||
|
@ -747,6 +800,14 @@ void ExecuteCommand(ReplyType reply_type)
|
|||
|
||||
case 0x40: // Read DiscID
|
||||
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(
|
||||
0, s_DIMAR, 0x20, s_DILENGTH, DiscIO::PARTITION_NONE, reply_type, &interrupt_type);
|
||||
break;
|
||||
|
@ -905,10 +966,12 @@ void ExecuteCommand(ReplyType reply_type)
|
|||
// Used by both GC and Wii
|
||||
case DICommand::StopMotor:
|
||||
{
|
||||
INFO_LOG(DVDINTERFACE, "DVDLowStopMotor %s %s", s_DICMDBUF[1] ? "eject" : "",
|
||||
s_DICMDBUF[2] ? "kill!" : "");
|
||||
const bool eject = (s_DICMDBUF[0] & (1 << 17));
|
||||
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() &&
|
||||
DVDThread::IsInsertedDiscRunning() && !s_auto_disc_change_paths.empty())
|
||||
|
|
|
@ -102,7 +102,7 @@ enum class EjectCause
|
|||
};
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Reset(bool spinup = true);
|
||||
void Shutdown();
|
||||
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);
|
||||
INFO_LOG(IOS_DI, "DVDLowReset %s spinup", spinup ? "with" : "without");
|
||||
DVDInterface::Reset();
|
||||
DVDInterface::Reset(spinup);
|
||||
ResetDIRegisters();
|
||||
// Should also reset current partition and such
|
||||
return DIResult::Success;
|
||||
|
|
Loading…
Reference in New Issue