summaryrefslogtreecommitdiff
path: root/Source/Core
diff options
context:
space:
mode:
authorPokechu22 <Pokechu022@gmail.com>2019-10-05 14:55:14 -0700
committerPokechu22 <Pokechu022@gmail.com>2020-01-04 11:43:31 -0800
commit55a88ba2ed61cfa68a6fde705f4a5af6138fcd88 (patch)
tree8b25322bc501e7485b42888b693dd88344c51aaa /Source/Core
parent7d6b9bcb40b6ace3cbc82324e5f9bb194406d00a (diff)
Track drive state better, reporting errors if the state is wrong
Also, fix DVDLowStopMotor logging (which was based on the ioctl parameters)
Diffstat (limited to 'Source/Core')
-rw-r--r--Source/Core/Core/Boot/Boot.cpp11
-rw-r--r--Source/Core/Core/Boot/Boot.h1
-rw-r--r--Source/Core/Core/Boot/Boot_BS2Emu.cpp4
-rw-r--r--Source/Core/Core/HW/DVD/DVDInterface.cpp81
-rw-r--r--Source/Core/Core/HW/DVD/DVDInterface.h2
-rw-r--r--Source/Core/Core/IOS/DI/DI.cpp2
6 files changed, 88 insertions, 13 deletions
diff --git a/Source/Core/Core/Boot/Boot.cpp b/Source/Core/Core/Boot/Boot.cpp
index 179afdaa92..a4f85208e3 100644
--- a/Source/Core/Core/Boot/Boot.cpp
+++ b/Source/Core/Core/Boot/Boot.cpp
@@ -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();
diff --git a/Source/Core/Core/Boot/Boot.h b/Source/Core/Core/Boot/Boot.h
index c34e1738fe..48462c768d 100644
--- a/Source/Core/Core/Boot/Boot.h
+++ b/Source/Core/Core/Boot/Boot.h
@@ -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();
diff --git a/Source/Core/Core/Boot/Boot_BS2Emu.cpp b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
index b265473dd7..25efebb12b 100644
--- a/Source/Core/Core/Boot/Boot_BS2Emu.cpp
+++ b/Source/Core/Core/Boot/Boot_BS2Emu.cpp
@@ -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
diff --git a/Source/Core/Core/HW/DVD/DVDInterface.cpp b/Source/Core/Core/HW/DVD/DVDInterface.cpp
index 5c6ab9c9c8..9f54563fb7 100644
--- a/Source/Core/Core/HW/DVD/DVDInterface.cpp
+++ b/Source/Core/Core/HW/DVD/DVDInterface.cpp
@@ -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())
diff --git a/Source/Core/Core/HW/DVD/DVDInterface.h b/Source/Core/Core/HW/DVD/DVDInterface.h
index 6007359e83..37a7bbf8d8 100644
--- a/Source/Core/Core/HW/DVD/DVDInterface.h
+++ b/Source/Core/Core/HW/DVD/DVDInterface.h
@@ -102,7 +102,7 @@ enum class EjectCause
};
void Init();
-void Reset();
+void Reset(bool spinup = true);
void Shutdown();
void DoState(PointerWrap& p);
diff --git a/Source/Core/Core/IOS/DI/DI.cpp b/Source/Core/Core/IOS/DI/DI.cpp
index f8e6514992..e4eeff686a 100644
--- a/Source/Core/Core/IOS/DI/DI.cpp
+++ b/Source/Core/Core/IOS/DI/DI.cpp
@@ -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;