874 changes: 351 additions & 523 deletions Source/Core/Core/HW/DVD/DVDInterface.cpp

Large diffs are not rendered by default.

238 changes: 185 additions & 53 deletions Source/Core/Core/HW/DVD/DVDInterface.h
Expand Up @@ -3,14 +3,26 @@

#pragma once

#include <array>
#include <memory>
#include <optional>
#include <string>
#include <vector>

#include "Common/BitField.h"
#include "Common/CommonTypes.h"

#include "Core/HW/StreamADPCM.h"

class PointerWrap;
namespace Core
{
class System;
}
namespace CoreTiming
{
struct EventType;
}
namespace DiscIO
{
class VolumeDisc;
Expand All @@ -21,25 +33,8 @@ namespace MMIO
class Mapping;
}

namespace DVDInterface
namespace DVD
{
class DVDInterfaceState
{
public:
DVDInterfaceState();
DVDInterfaceState(const DVDInterfaceState&) = delete;
DVDInterfaceState(DVDInterfaceState&&) = delete;
DVDInterfaceState& operator=(const DVDInterfaceState&) = delete;
DVDInterfaceState& operator=(DVDInterfaceState&&) = delete;
~DVDInterfaceState();

struct Data;
Data& GetData() { return *m_data; }

private:
std::unique_ptr<Data> m_data;
};

enum class DICommand : u8
{
Inquiry = 0x12,
Expand Down Expand Up @@ -125,48 +120,185 @@ enum class EjectCause
Software,
};

void Init();
void ResetDrive(bool spinup);
void Shutdown();
void DoState(PointerWrap& p);
class DVDInterface
{
public:
explicit DVDInterface(Core::System& system);
DVDInterface(const DVDInterface&) = delete;
DVDInterface(DVDInterface&&) = delete;
DVDInterface& operator=(const DVDInterface&) = delete;
DVDInterface& operator=(DVDInterface&&) = delete;
~DVDInterface();

void Init();
void ResetDrive(bool spinup);
void Shutdown();
void DoState(PointerWrap& p);

void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii);
void RegisterMMIO(MMIO::Mapping* mmio, u32 base, bool is_wii);

void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
std::optional<std::vector<std::string>> auto_disc_change_paths);
bool IsDiscInside();
void EjectDisc(EjectCause cause); // Must only be called on the CPU thread
void ChangeDisc(const std::vector<std::string>& paths); // Must only be called on the CPU thread
void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread
bool AutoChangeDisc(); // Must only be called on the CPU thread
void SetDisc(std::unique_ptr<DiscIO::VolumeDisc> disc,
std::optional<std::vector<std::string>> auto_disc_change_paths);
bool IsDiscInside() const;
void EjectDisc(EjectCause cause); // Must only be called on the CPU thread
void ChangeDisc(const std::vector<std::string>& paths); // Must only be called on the CPU thread
void ChangeDisc(const std::string& new_path); // Must only be called on the CPU thread
bool AutoChangeDisc(); // Must only be called on the CPU thread

// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
// if both of the following conditions are true:
// - A disc is inserted
// - The title_id argument doesn't contain a value, or its value matches the disc's title ID
bool UpdateRunningGameMetadata(std::optional<u64> title_id = {});
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
// if both of the following conditions are true:
// - A disc is inserted
// - The title_id argument doesn't contain a value, or its value matches the disc's title ID
bool UpdateRunningGameMetadata(std::optional<u64> title_id = {});

// Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI,
// and lets us skip encrypting/decrypting in some cases)
void ExecuteCommand(ReplyType reply_type);
void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
const DiscIO::Partition& partition, ReplyType reply_type);
// Direct access to DI for IOS HLE (simpler to implement than how real IOS accesses DI,
// and lets us skip encrypting/decrypting in some cases)
void ExecuteCommand(ReplyType reply_type);
void PerformDecryptingRead(u32 position, u32 length, u32 output_address,
const DiscIO::Partition& partition, ReplyType reply_type);

// For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being checked.
void ForceOutOfBoundsRead(ReplyType reply_type);
// For circumventing Error #001 in DirectoryBlobs, which may have data in the offsets being
// checked.
void ForceOutOfBoundsRead(ReplyType reply_type);

// Exposed for use by emulated BS2; does not perform any checks on drive state
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length);
// Exposed for use by emulated BS2; does not perform any checks on drive state
void AudioBufferConfig(bool enable_dtk, u8 dtk_buffer_length);

void SetDriveState(DriveState state);
void SetDriveError(DriveError error);

// Used by DVDThread
void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
const std::vector<u8>& data = std::vector<u8>());

// Used by IOS HLE
void SetInterruptEnabled(DIInterruptType interrupt, bool enabled);
void ClearInterrupt(DIInterruptType interrupt);

private:
void DTKStreamingCallback(DIInterruptType interrupt_type, const std::vector<u8>& audio_data,
s64 cycles_late);
size_t ProcessDTKSamples(std::vector<s16>* temp_pcm, const std::vector<u8>& audio_data);
u32 AdvanceDTK(u32 maximum_samples, u32* samples_to_process);

void SetDriveState(DriveState state);
void SetDriveError(DriveError error);
void SetLidOpen();
void UpdateInterrupts();
void GenerateDIInterrupt(DIInterruptType dvd_interrupt);

// Used by DVDThread
void FinishExecutingCommand(ReplyType reply_type, DIInterruptType interrupt_type, s64 cycles_late,
const std::vector<u8>& data = std::vector<u8>());
bool CheckReadPreconditions();
bool ExecuteReadCommand(u64 dvd_offset, u32 output_address, u32 dvd_length, u32 output_length,
const DiscIO::Partition& partition, ReplyType reply_type,
DIInterruptType* interrupt_type);
void ScheduleReads(u64 offset, u32 length, const DiscIO::Partition& partition, u32 output_address,
ReplyType reply_type);

// Used by IOS HLE
void SetInterruptEnabled(DIInterruptType interrupt, bool enabled);
void ClearInterrupt(DIInterruptType interrupt);
static void AutoChangeDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate);
static void EjectDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate);
static void InsertDiscCallback(Core::System& system, u64 userdata, s64 cyclesLate);
static void FinishExecutingCommandCallback(Core::System& system, u64 userdata, s64 cycles_late);

} // namespace DVDInterface
// DI Status Register
union UDISR
{
u32 Hex = 0;

BitField<0, 1, u32> BREAK; // Stop the Device + Interrupt
BitField<1, 1, u32> DEINTMASK; // Access Device Error Int Mask
BitField<2, 1, u32> DEINT; // Access Device Error Int
BitField<3, 1, u32> TCINTMASK; // Transfer Complete Int Mask
BitField<4, 1, u32> TCINT; // Transfer Complete Int
BitField<5, 1, u32> BRKINTMASK;
BitField<6, 1, u32> BRKINT; // w 1: clear brkint
BitField<7, 25, u32> reserved;

UDISR() = default;
explicit UDISR(u32 hex) : Hex{hex} {}
};

// DI Cover Register
union UDICVR
{
u32 Hex = 0;

BitField<0, 1, u32> CVR; // 0: Cover closed 1: Cover open
BitField<1, 1, u32> CVRINTMASK; // 1: Interrupt enabled
BitField<2, 1, u32> CVRINT; // r 1: Interrupt requested w 1: Interrupt clear
BitField<3, 29, u32> reserved;

UDICVR() = default;
explicit UDICVR(u32 hex) : Hex{hex} {}
};

// DI DMA Control Register
union UDICR
{
u32 Hex = 0;

BitField<0, 1, u32> TSTART; // w:1 start r:0 ready
BitField<1, 1, u32> DMA; // 1: DMA Mode
// 0: Immediate Mode (can only do Access Register Command)
BitField<2, 1, u32> RW; // 0: Read Command (DVD to Memory) 1: Write Command (Memory to DVD)
BitField<3, 29, u32> reserved;
};

// DI Config Register
union UDICFG
{
u32 Hex = 0;

BitField<0, 8, u32> CONFIG;
BitField<8, 24, u32> reserved;

UDICFG() = default;
explicit UDICFG(u32 hex) : Hex{hex} {}
};

// Hardware registers
UDISR m_DISR;
UDICVR m_DICVR;
std::array<u32, 3> m_DICMDBUF{};
u32 m_DIMAR = 0;
u32 m_DILENGTH = 0;
UDICR m_DICR;
u32 m_DIIMMBUF = 0;
UDICFG m_DICFG;

StreamADPCM::ADPCMDecoder m_adpcm_decoder;

// DTK
bool m_stream = false;
bool m_stop_at_track_end = false;
u64 m_audio_position = 0;
u64 m_current_start = 0;
u32 m_current_length = 0;
u64 m_next_start = 0;
u32 m_next_length = 0;
u32 m_pending_samples = 0;
bool m_enable_dtk = false;
u8 m_dtk_buffer_length = 0; // TODO: figure out how this affects the regular buffer

// Disc drive state
DriveState m_drive_state = DriveState::Ready;
DriveError m_error_code = DriveError::None;
u64 m_disc_end_offset = 0;

// Disc drive timing
u64 m_read_buffer_start_time = 0;
u64 m_read_buffer_end_time = 0;
u64 m_read_buffer_start_offset = 0;
u64 m_read_buffer_end_offset = 0;

// Disc changing
std::string m_disc_path_to_insert;
std::vector<std::string> m_auto_disc_change_paths;
size_t m_auto_disc_change_index = 0;

// Events
CoreTiming::EventType* m_finish_executing_command = nullptr;
CoreTiming::EventType* m_auto_change_disc = nullptr;
CoreTiming::EventType* m_eject_disc = nullptr;
CoreTiming::EventType* m_insert_disc = nullptr;

Core::System& m_system;
};
} // namespace DVD
275 changes: 99 additions & 176 deletions Source/Core/Core/HW/DVD/DVDThread.cpp

Large diffs are not rendered by default.

155 changes: 112 additions & 43 deletions Source/Core/Core/HW/DVD/DVDThread.h
Expand Up @@ -3,21 +3,35 @@

#pragma once

#include <map>
#include <memory>
#include <optional>
#include <thread>
#include <utility>
#include <vector>

#include "Common/CommonTypes.h"
#include "Common/Event.h"
#include "Common/Flag.h"
#include "Common/SPSCQueue.h"

#include "Core/HW/DVD/DVDInterface.h"
#include "Core/HW/DVD/FileMonitor.h"

#include "DiscIO/Volume.h"

class PointerWrap;
namespace DiscIO
namespace Core
{
struct Partition;
class System;
}

namespace DVDInterface
namespace CoreTiming
{
enum class ReplyType : u32;
struct EventType;
}
namespace DiscIO
{
struct Partition;
}

namespace DiscIO
Expand All @@ -32,48 +46,103 @@ class TMDReader;
class TicketReader;
} // namespace IOS::ES

namespace DVDThread
namespace DVD
{
class DVDThreadState
enum class ReplyType : u32;

class DVDThread
{
public:
DVDThreadState();
DVDThreadState(const DVDThreadState&) = delete;
DVDThreadState(DVDThreadState&&) = delete;
DVDThreadState& operator=(const DVDThreadState&) = delete;
DVDThreadState& operator=(DVDThreadState&&) = delete;
~DVDThreadState();
explicit DVDThread(Core::System& system);
DVDThread(const DVDThread&) = delete;
DVDThread(DVDThread&&) = delete;
DVDThread& operator=(const DVDThread&) = delete;
DVDThread& operator=(DVDThread&&) = delete;
~DVDThread();

struct Data;
Data& GetData() { return *m_data; }
void Start();
void Stop();
void DoState(PointerWrap& p);

void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
bool HasDisc() const;

bool HasWiiHashes() const;
DiscIO::Platform GetDiscType() const;
u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
bool IsInsertedDiscRunning();
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
// if both of the following conditions are true:
// - A disc is inserted
// - The title_id argument doesn't contain a value, or its value matches the disc's title ID
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition,
std::optional<u64> title_id = {});

void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
DVD::ReplyType reply_type, s64 ticks_until_completion);
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
const DiscIO::Partition& partition, DVD::ReplyType reply_type,
s64 ticks_until_completion);

private:
std::unique_ptr<Data> m_data;
};
void StartDVDThread();
void StopDVDThread();
void WaitUntilIdle();

void Start();
void Stop();
void DoState(PointerWrap& p);

void SetDisc(std::unique_ptr<DiscIO::Volume> disc);
bool HasDisc();

bool HasWiiHashes();
DiscIO::Platform GetDiscType();
u64 PartitionOffsetToRawOffset(u64 offset, const DiscIO::Partition& partition);
IOS::ES::TMDReader GetTMD(const DiscIO::Partition& partition);
IOS::ES::TicketReader GetTicket(const DiscIO::Partition& partition);
bool IsInsertedDiscRunning();
// This function returns true and calls SConfig::SetRunningGameMetadata(Volume&, Partition&)
// if both of the following conditions are true:
// - A disc is inserted
// - The title_id argument doesn't contain a value, or its value matches the disc's title ID
bool UpdateRunningGameMetadata(const DiscIO::Partition& partition,
std::optional<u64> title_id = {});

void StartRead(u64 dvd_offset, u32 length, const DiscIO::Partition& partition,
DVDInterface::ReplyType reply_type, s64 ticks_until_completion);
void StartReadToEmulatedRAM(u32 output_address, u64 dvd_offset, u32 length,
const DiscIO::Partition& partition, DVDInterface::ReplyType reply_type,
s64 ticks_until_completion);
} // namespace DVDThread
void StartReadInternal(bool copy_to_ram, u32 output_address, u64 dvd_offset, u32 length,
const DiscIO::Partition& partition, DVD::ReplyType reply_type,
s64 ticks_until_completion);

static void GlobalFinishRead(Core::System& system, u64 id, s64 cycles_late);
void FinishRead(u64 id, s64 cycles_late);

void DVDThreadMain();

struct ReadRequest
{
bool copy_to_ram = false;
u32 output_address = 0;
u64 dvd_offset = 0;
u32 length = 0;
DiscIO::Partition partition{};

// This determines which code DVDInterface will run to reply
// to the emulated software. We can't use callbacks,
// because function pointers can't be stored in savestates.
DVD::ReplyType reply_type = DVD::ReplyType::NoReply;

// IDs are used to uniquely identify a request. They must not be
// identical to IDs of any other requests that currently exist, but
// it's fine to re-use IDs of requests that have existed in the past.
u64 id = 0;

// Only used for logging
u64 time_started_ticks = 0;
u64 realtime_started_us = 0;
u64 realtime_done_us = 0;
};

using ReadResult = std::pair<ReadRequest, std::vector<u8>>;

CoreTiming::EventType* m_finish_read = nullptr;

u64 m_next_id = 0;

std::thread m_dvd_thread;
Common::Event m_request_queue_expanded; // Is set by CPU thread
Common::Event m_result_queue_expanded; // Is set by DVD thread
Common::Flag m_dvd_thread_exiting = Common::Flag(false); // Is set by CPU thread

Common::SPSCQueue<ReadRequest, false> m_request_queue;
Common::SPSCQueue<ReadResult, false> m_result_queue;
std::map<u64, ReadResult> m_result_map;

std::unique_ptr<DiscIO::Volume> m_disc;

FileMonitor::FileLogger m_file_logger;

Core::System& m_system;
};
} // namespace DVD
6 changes: 3 additions & 3 deletions Source/Core/Core/HW/HW.cpp
Expand Up @@ -50,7 +50,7 @@ void Init(const Sram* override_sram)
AddressSpace::Init();
MemoryInterface::Init();
system.GetDSP().Init(Config::Get(Config::MAIN_DSP_HLE));
DVDInterface::Init();
system.GetDVDInterface().Init();
system.GetGPFifo().Init();
system.GetCPU().Init(Config::Get(Config::MAIN_CPU_CORE));
SystemTimers::Init();
Expand All @@ -72,7 +72,7 @@ void Shutdown()

SystemTimers::Shutdown();
system.GetCPU().Shutdown();
DVDInterface::Shutdown();
system.GetDVDInterface().Shutdown();
system.GetDSP().Shutdown();
MemoryInterface::Shutdown();
AddressSpace::Shutdown();
Expand Down Expand Up @@ -101,7 +101,7 @@ void DoState(PointerWrap& p)
p.DoMarker("ProcessorInterface");
system.GetDSP().DoState(p);
p.DoMarker("DSP");
DVDInterface::DoState(p);
system.GetDVDInterface().DoState(p);
p.DoMarker("DVDInterface");
system.GetGPFifo().DoState(p);
p.DoMarker("GPFifo");
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/HW/Memmap.cpp
Expand Up @@ -55,14 +55,14 @@ void MemoryManager::InitMMIO(bool is_wii)
system.GetProcessorInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C003000);
MemoryInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C004000);
system.GetDSP().RegisterMMIO(m_mmio_mapping.get(), 0x0C005000);
DVDInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false);
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006000, false);
SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006400);
ExpansionInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0C006800);
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0C006C00);
if (is_wii)
{
IOS::RegisterMMIO(m_mmio_mapping.get(), 0x0D000000);
DVDInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
system.GetDVDInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006000, true);
SerialInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006400);
ExpansionInterface::RegisterMMIO(m_mmio_mapping.get(), 0x0D006800);
system.GetAudioInterface().RegisterMMIO(m_mmio_mapping.get(), 0x0D006C00);
Expand Down
2 changes: 1 addition & 1 deletion Source/Core/Core/HW/ProcessorInterface.cpp
Expand Up @@ -120,7 +120,7 @@ void ProcessorInterfaceManager::RegisterMMIO(MMIO::Mapping* mmio, u32 base)
processor_interface.m_reset_code);
if (!SConfig::GetInstance().bWii && ~processor_interface.m_reset_code & 0x4)
{
DVDInterface::ResetDrive(true);
system.GetDVDInterface().ResetDrive(true);
}
}));

Expand Down
20 changes: 10 additions & 10 deletions Source/Core/Core/HW/WII_IPC.cpp
Expand Up @@ -208,13 +208,13 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
}));

mmio->Register(base | GPIOB_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
g_gpio_out.m_hex =
(val & gpio_owner.m_hex) | (g_gpio_out.m_hex & ~gpio_owner.m_hex);
if (g_gpio_out[GPIO::DO_EJECT])
{
INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write");
DVDInterface::EjectDisc(DVDInterface::EjectCause::Software);
system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software);
}
// SENSOR_BAR is checked by WiimoteEmu::CameraLogic
// TODO: AVE, SLOT_LED
Expand All @@ -223,9 +223,9 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
gpio_dir.m_hex = (val & gpio_owner.m_hex) | (gpio_dir.m_hex & ~gpio_owner.m_hex);
}));
mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](Core::System&, u32) {
mmio->Register(base | GPIOB_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in;
gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside();
return gpio_in.m_hex;
}),
MMIO::Nop<u32>());
Expand All @@ -241,13 +241,13 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// go through the HW_GPIOB registers if the corresponding bit is set in the HW_GPIO_OWNER
// register.
mmio->Register(base | GPIO_OUT, MMIO::DirectRead<u32>(&g_gpio_out.m_hex),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
g_gpio_out.m_hex =
(g_gpio_out.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex);
if (g_gpio_out[GPIO::DO_EJECT])
{
INFO_LOG_FMT(WII_IPC, "Ejecting disc due to GPIO write");
DVDInterface::EjectDisc(DVDInterface::EjectCause::Software);
system.GetDVDInterface().EjectDisc(DVD::EjectCause::Software);
}
// SENSOR_BAR is checked by WiimoteEmu::CameraLogic
// TODO: AVE, SLOT_LED
Expand All @@ -256,15 +256,15 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
gpio_dir.m_hex = (gpio_dir.m_hex & gpio_owner.m_hex) | (val & ~gpio_owner.m_hex);
}));
mmio->Register(base | GPIO_IN, MMIO::ComplexRead<u32>([](Core::System&, u32) {
mmio->Register(base | GPIO_IN, MMIO::ComplexRead<u32>([](Core::System& system, u32) {
Common::Flags<GPIO> gpio_in;
gpio_in[GPIO::SLOT_IN] = DVDInterface::IsDiscInside();
gpio_in[GPIO::SLOT_IN] = system.GetDVDInterface().IsDiscInside();
return gpio_in.m_hex;
}),
MMIO::Nop<u32>());

mmio->Register(base | HW_RESETS, MMIO::DirectRead<u32>(&resets),
MMIO::ComplexWrite<u32>([](Core::System&, u32, u32 val) {
MMIO::ComplexWrite<u32>([](Core::System& system, u32, u32 val) {
// A reset occurs when the corresponding bit is cleared
const bool di_reset_triggered = (resets & 0x400) && !(val & 0x400);
resets = val;
Expand All @@ -273,7 +273,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
// The GPIO *disables* spinning up the drive
const bool spinup = !g_gpio_out[GPIO::DI_SPIN];
INFO_LOG_FMT(WII_IPC, "Resetting DI {} spinup", spinup ? "with" : "without");
DVDInterface::ResetDrive(spinup);
system.GetDVDInterface().ResetDrive(spinup);
}
}));

Expand Down
46 changes: 25 additions & 21 deletions Source/Core/Core/IOS/DI/DI.cpp
Expand Up @@ -214,8 +214,8 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
return DIResult::SecurityError;
}
m_last_length = position; // An actual mistake in IOS
DVDInterface::PerformDecryptingRead(position, length, request.buffer_out, m_current_partition,
DVDInterface::ReplyType::IOS);
system.GetDVDInterface().PerformDecryptingRead(position, length, request.buffer_out,
m_current_partition, DVD::ReplyType::IOS);
return {};
}
case DIIoctl::DVDLowWaitForCoverClose:
Expand Down Expand Up @@ -274,26 +274,28 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
}
case DIIoctl::DVDLowMaskCoverInterrupt:
INFO_LOG_FMT(IOS_DI, "DVDLowMaskCoverInterrupt");
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false);
system.GetDVDInterface().SetInterruptEnabled(DVD::DIInterruptType::CVRINT, false);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DI_INTERRUPT_MASK_COMMAND);
return DIResult::Success;
case DIIoctl::DVDLowClearCoverInterrupt:
DEBUG_LOG_FMT(IOS_DI, "DVDLowClearCoverInterrupt");
DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::CVRINT);
system.GetDVDInterface().ClearInterrupt(DVD::DIInterruptType::CVRINT);
return DIResult::Success;
case DIIoctl::DVDLowUnmaskStatusInterrupts:
INFO_LOG_FMT(IOS_DI, "DVDLowUnmaskStatusInterrupts");
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DI_INTERRUPT_MASK_COMMAND);
// Dummied out
return DIResult::Success;
case DIIoctl::DVDLowGetCoverStatus:
{
// TODO: handle resetting case
INFO_LOG_FMT(IOS_DI, "DVDLowGetCoverStatus: Disc {}Inserted",
DVDInterface::IsDiscInside() ? "" : "Not ");
return WriteIfFits(request, DVDInterface::IsDiscInside() ? 2 : 1);
const bool is_disc_inside = system.GetDVDInterface().IsDiscInside();
INFO_LOG_FMT(IOS_DI, "DVDLowGetCoverStatus: Disc {}Inserted", is_disc_inside ? "" : "Not ");
return WriteIfFits(request, is_disc_inside ? 2 : 1);
}
case DIIoctl::DVDLowUnmaskCoverInterrupt:
INFO_LOG_FMT(IOS_DI, "DVDLowUnmaskCoverInterrupt");
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, true);
system.GetDVDInterface().SetInterruptEnabled(DVD::DIInterruptType::CVRINT, true);
DolphinAnalytics::Instance().ReportGameQuirk(GameQuirk::USES_DI_INTERRUPT_MASK_COMMAND);
return DIResult::Success;
case DIIoctl::DVDLowReset:
Expand Down Expand Up @@ -362,7 +364,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartIOCtl(const IOCtlRequest& reque
DIMAR = request.buffer_out;
m_last_length = length;
DILENGTH = length;
DVDInterface::ForceOutOfBoundsRead(DVDInterface::ReplyType::IOS);
system.GetDVDInterface().ForceOutOfBoundsRead(DVD::ReplyType::IOS);
return {};
}
else
Expand Down Expand Up @@ -579,7 +581,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartDMATransfer(u32 command_length,
m_last_length = command_length;
DILENGTH = command_length;

DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS);
Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl.
return {};
}
Expand All @@ -597,7 +599,7 @@ std::optional<DIDevice::DIResult> DIDevice::StartImmediateTransfer(const IOCtlRe

m_executing_command->m_copy_diimmbuf = write_to_buf;

DVDInterface::ExecuteCommand(DVDInterface::ReplyType::IOS);
Core::System::GetInstance().GetDVDInterface().ExecuteCommand(DVD::ReplyType::IOS);
// Reply will be posted when done by FinishIOCtl.
return {};
}
Expand All @@ -612,15 +614,15 @@ static std::shared_ptr<DIDevice> GetDevice()
return std::static_pointer_cast<DIDevice>(di);
}

void DIDevice::InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type)
void DIDevice::InterruptFromDVDInterface(DVD::DIInterruptType interrupt_type)
{
DIResult result;
switch (interrupt_type)
{
case DVDInterface::DIInterruptType::TCINT:
case DVD::DIInterruptType::TCINT:
result = DIResult::Success;
break;
case DVDInterface::DIInterruptType::DEINT:
case DVD::DIInterruptType::DEINT:
result = DIResult::DriveError;
break;
default:
Expand Down Expand Up @@ -739,11 +741,12 @@ std::optional<IPCReply> DIDevice::IOCtlV(const IOCtlVRequest& request)
INFO_LOG_FMT(IOS_DI, "DVDLowOpenPartition: partition_offset {:#011x}", partition_offset);

// Read TMD to the buffer
const ES::TMDReader tmd = DVDThread::GetTMD(m_current_partition);
auto& dvd_thread = system.GetDVDThread();
const ES::TMDReader tmd = dvd_thread.GetTMD(m_current_partition);
const std::vector<u8>& raw_tmd = tmd.GetBytes();
memory.CopyToEmu(request.io_vectors[0].address, raw_tmd.data(), raw_tmd.size());

ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, DVDThread::GetTicket(m_current_partition));
ReturnCode es_result = m_ios.GetES()->DIVerify(tmd, dvd_thread.GetTicket(m_current_partition));
memory.Write_U32(es_result, request.io_vectors[1].address);

return_value = DIResult::Success;
Expand Down Expand Up @@ -814,12 +817,13 @@ void DIDevice::ResetDIRegisters()
{
// Clear transfer complete and error interrupts (normally r/z, but here we just directly write
// zero)
DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::TCINT);
DVDInterface::ClearInterrupt(DVDInterface::DIInterruptType::DEINT);
auto& di = Core::System::GetInstance().GetDVDInterface();
di.ClearInterrupt(DVD::DIInterruptType::TCINT);
di.ClearInterrupt(DVD::DIInterruptType::DEINT);
// Enable transfer complete and error interrupts, and disable cover interrupt
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::TCINT, true);
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::DEINT, true);
DVDInterface::SetInterruptEnabled(DVDInterface::DIInterruptType::CVRINT, false);
di.SetInterruptEnabled(DVD::DIInterruptType::TCINT, true);
di.SetInterruptEnabled(DVD::DIInterruptType::DEINT, true);
di.SetInterruptEnabled(DVD::DIInterruptType::CVRINT, false);
// Close the current partition, if there is one
ChangePartition(DiscIO::PARTITION_NONE);
}
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/IOS/DI/DI.h
Expand Up @@ -15,7 +15,7 @@
class CBoot;
class PointerWrap;

namespace DVDInterface
namespace DVD
{
enum class DIInterruptType : int;
}
Expand All @@ -40,7 +40,7 @@ class DIDevice : public Device
public:
DIDevice(Kernel& ios, const std::string& device_name);

static void InterruptFromDVDInterface(DVDInterface::DIInterruptType interrupt_type);
static void InterruptFromDVDInterface(DVD::DIInterruptType interrupt_type);
static DiscIO::Partition GetCurrentPartition();

void DoState(PointerWrap& p) override;
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/IOS/MIOS.cpp
Expand Up @@ -42,7 +42,7 @@ static void ReinitHardware()
// HACK However, resetting DI will reset the DTK config, which is set by the system menu
// (and not by MIOS), causing games that use DTK to break. Perhaps MIOS doesn't actually
// reset DI fully, in such a way that the DTK config isn't cleared?
// DVDInterface::ResetDrive(true);
// system.GetDVDInterface().ResetDrive(true);
PowerPC::Reset();
Wiimote::ResetAllWiimotes();
// Note: this is specific to Dolphin and is required because we initialised it in Wii mode.
Expand Down Expand Up @@ -99,7 +99,7 @@ bool Load()
memory.Write_U32(0x00000000, ADDRESS_INIT_SEMAPHORE);
NOTICE_LOG_FMT(IOS, "IPL ready.");
SConfig::GetInstance().m_is_mios = true;
DVDInterface::UpdateRunningGameMetadata();
system.GetDVDInterface().UpdateRunningGameMetadata();
SConfig::OnNewTitleLoad(guard);
return true;
}
Expand Down
4 changes: 2 additions & 2 deletions Source/Core/Core/Movie.cpp
Expand Up @@ -1274,9 +1274,9 @@ void PlayController(GCPadStatus* PadStatus, int controllerID)
if (s_padState.disc)
{
Core::RunAsCPUThread([] {
if (!DVDInterface::AutoChangeDisc())
auto& system = Core::System::GetInstance();
if (!system.GetDVDInterface().AutoChangeDisc())
{
auto& system = Core::System::GetInstance();
system.GetCPU().Break();
PanicAlertFmtT("Change the disc to {0}", s_discChange);
}
Expand Down
16 changes: 8 additions & 8 deletions Source/Core/Core/System.cpp
Expand Up @@ -36,8 +36,8 @@ namespace Core
struct System::Impl
{
explicit Impl(System& system)
: m_audio_interface(system), m_core_timing(system), m_dsp(system), m_gp_fifo(system),
m_ppc_state(PowerPC::ppcState)
: m_audio_interface(system), m_core_timing(system), m_dsp(system), m_dvd_interface(system),
m_dvd_thread(system), m_gp_fifo(system), m_ppc_state(PowerPC::ppcState)
{
}

Expand All @@ -50,8 +50,8 @@ struct System::Impl
CommandProcessor::CommandProcessorManager m_command_processor;
CPU::CPUManager m_cpu;
DSP::DSPManager m_dsp;
DVDInterface::DVDInterfaceState m_dvd_interface_state;
DVDThread::DVDThreadState m_dvd_thread_state;
DVD::DVDInterface m_dvd_interface;
DVD::DVDThread m_dvd_thread;
ExpansionInterface::ExpansionInterfaceState m_expansion_interface_state;
Fifo::FifoManager m_fifo;
GeometryShaderManager m_geometry_shader_manager;
Expand Down Expand Up @@ -138,14 +138,14 @@ DSP::DSPManager& System::GetDSP() const
return m_impl->m_dsp;
}

DVDInterface::DVDInterfaceState& System::GetDVDInterfaceState() const
DVD::DVDInterface& System::GetDVDInterface() const
{
return m_impl->m_dvd_interface_state;
return m_impl->m_dvd_interface;
}

DVDThread::DVDThreadState& System::GetDVDThreadState() const
DVD::DVDThread& System::GetDVDThread() const
{
return m_impl->m_dvd_thread_state;
return m_impl->m_dvd_thread;
}

ExpansionInterface::ExpansionInterfaceState& System::GetExpansionInterfaceState() const
Expand Down
15 changes: 6 additions & 9 deletions Source/Core/Core/System.h
Expand Up @@ -31,14 +31,11 @@ namespace DSP
{
class DSPManager;
}
namespace DVDInterface
namespace DVD
{
class DVDInterfaceState;
}
namespace DVDThread
{
class DVDThreadState;
}
class DVDInterface;
class DVDThread;
} // namespace DVD
namespace ExpansionInterface
{
class ExpansionInterfaceState;
Expand Down Expand Up @@ -127,8 +124,8 @@ class System
CoreTiming::CoreTimingManager& GetCoreTiming() const;
CommandProcessor::CommandProcessorManager& GetCommandProcessor() const;
DSP::DSPManager& GetDSP() const;
DVDInterface::DVDInterfaceState& GetDVDInterfaceState() const;
DVDThread::DVDThreadState& GetDVDThreadState() const;
DVD::DVDInterface& GetDVDInterface() const;
DVD::DVDThread& GetDVDThread() const;
ExpansionInterface::ExpansionInterfaceState& GetExpansionInterfaceState() const;
Fifo::FifoManager& GetFifo() const;
GeometryShaderManager& GetGeometryShaderManager() const;
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/DolphinQt/GameList/GameList.cpp
Expand Up @@ -52,6 +52,7 @@
#include "Core/HW/EXI/EXI.h"
#include "Core/HW/EXI/EXI_Device.h"
#include "Core/HW/WiiSave.h"
#include "Core/System.h"
#include "Core/WiiUtils.h"

#include "DiscIO/Blob.h"
Expand Down Expand Up @@ -852,7 +853,9 @@ void GameList::ChangeDisc()
if (!game)
return;

Core::RunAsCPUThread([file_path = game->GetFilePath()] { DVDInterface::ChangeDisc(file_path); });
Core::RunAsCPUThread([file_path = game->GetFilePath()] {
Core::System::GetInstance().GetDVDInterface().ChangeDisc(file_path);
});
}

QAbstractItemView* GameList::GetActiveView() const
Expand Down
6 changes: 4 additions & 2 deletions Source/Core/DolphinQt/MainWindow.cpp
Expand Up @@ -746,12 +746,14 @@ void MainWindow::ChangeDisc()
std::vector<std::string> paths = StringListToStdVector(PromptFileNames());

if (!paths.empty())
Core::RunAsCPUThread([&paths] { DVDInterface::ChangeDisc(paths); });
Core::RunAsCPUThread(
[&paths] { Core::System::GetInstance().GetDVDInterface().ChangeDisc(paths); });
}

void MainWindow::EjectDisc()
{
Core::RunAsCPUThread([] { DVDInterface::EjectDisc(DVDInterface::EjectCause::User); });
Core::RunAsCPUThread(
[] { Core::System::GetInstance().GetDVDInterface().EjectDisc(DVD::EjectCause::User); });
}

void MainWindow::OpenUserFolder()
Expand Down