Merge pull request #3759 from JosJuice/dvd-callback-savestates

DVDInterface/DVDThread: Don't store CoreTiming event IDs in savestates
This commit is contained in:
Pierre Bourdon 2016-04-14 17:55:52 +02:00
commit 4d864ece27
6 changed files with 74 additions and 65 deletions

View File

@ -25,6 +25,8 @@
#include "Core/HW/ProcessorInterface.h" #include "Core/HW/ProcessorInterface.h"
#include "Core/HW/StreamADPCM.h" #include "Core/HW/StreamADPCM.h"
#include "Core/HW/SystemTimers.h" #include "Core/HW/SystemTimers.h"
#include "Core/IPC_HLE/WII_IPC_HLE.h"
#include "Core/IPC_HLE/WII_IPC_HLE_Device_DI.h"
#include "DiscIO/Volume.h" #include "DiscIO/Volume.h"
#include "DiscIO/VolumeCreator.h" #include "DiscIO/VolumeCreator.h"
@ -244,7 +246,7 @@ static u32 s_error_code = 0;
static bool s_disc_inside = false; static bool s_disc_inside = false;
static bool s_stream = false; static bool s_stream = false;
static bool s_stop_at_track_end = false; static bool s_stop_at_track_end = false;
static int s_finish_execute_command = 0; static int s_finish_executing_command = 0;
static int s_dtk = 0; static int s_dtk = 0;
static u64 s_last_read_offset; static u64 s_last_read_offset;
@ -258,15 +260,16 @@ static int s_insert_disc;
static void EjectDiscCallback(u64 userdata, s64 cyclesLate); static void EjectDiscCallback(u64 userdata, s64 cyclesLate);
static void InsertDiscCallback(u64 userdata, s64 cyclesLate); static void InsertDiscCallback(u64 userdata, s64 cyclesLate);
static void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late);
void SetLidOpen(bool _bOpen); void SetLidOpen(bool _bOpen);
void UpdateInterrupts(); void UpdateInterrupts();
void GenerateDIInterrupt(DIInterruptType _DVDInterrupt); void GenerateDIInterrupt(DIInterruptType _DVDInterrupt);
void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF); void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios);
bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt, bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt,
int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion); bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion);
u64 SimulateDiscReadTime(u64 offset, u32 length); u64 SimulateDiscReadTime(u64 offset, u32 length);
s64 CalculateRawDiscReadTime(u64 offset, s64 length); s64 CalculateRawDiscReadTime(u64 offset, s64 length);
@ -301,16 +304,6 @@ void DoState(PointerWrap &p)
DVDThread::DoState(p); DVDThread::DoState(p);
} }
static void FinishExecuteCommand(u64 userdata, s64 cyclesLate)
{
if (s_DICR.TSTART)
{
s_DICR.TSTART = 0;
s_DILENGTH.Length = 0;
GenerateDIInterrupt((DIInterruptType)userdata);
}
}
static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples) static u32 ProcessDTKSamples(short *tempPCM, u32 num_samples)
{ {
// TODO: Read audio data using the DVD thread instead of blocking on it? // TODO: Read audio data using the DVD thread instead of blocking on it?
@ -408,7 +401,7 @@ void Init()
s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback); s_eject_disc = CoreTiming::RegisterEvent("EjectDisc", EjectDiscCallback);
s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback); s_insert_disc = CoreTiming::RegisterEvent("InsertDisc", InsertDiscCallback);
s_finish_execute_command = CoreTiming::RegisterEvent("FinishExecuteCommand", FinishExecuteCommand); s_finish_executing_command = CoreTiming::RegisterEvent("FinishExecutingCommand", FinishExecutingCommandCallback);
s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback); s_dtk = CoreTiming::RegisterEvent("StreamingTimer", DTKStreamingCallback);
CoreTiming::ScheduleEvent(0, s_dtk); CoreTiming::ScheduleEvent(0, s_dtk);
@ -589,7 +582,7 @@ void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
if (s_DICR.TSTART) if (s_DICR.TSTART)
{ {
ExecuteCommand(s_DICMDBUF[0].Hex, s_DICMDBUF[1].Hex, s_DICMDBUF[2].Hex, ExecuteCommand(s_DICMDBUF[0].Hex, s_DICMDBUF[1].Hex, s_DICMDBUF[2].Hex,
s_DIMAR.Hex, s_DILENGTH.Hex, true, s_finish_execute_command); s_DIMAR.Hex, s_DILENGTH.Hex, false);
} }
}) })
); );
@ -637,17 +630,17 @@ void GenerateDIInterrupt(DIInterruptType dvd_interrupt)
UpdateInterrupts(); UpdateInterrupts();
} }
void WriteImmediate(u32 value, u32 output_address, bool write_to_DIIMMBUF) void WriteImmediate(u32 value, u32 output_address, bool reply_to_ios)
{ {
if (write_to_DIIMMBUF) if (reply_to_ios)
s_DIIMMBUF.Hex = value;
else
Memory::Write_U32(value, output_address); Memory::Write_U32(value, output_address);
else
s_DIIMMBUF.Hex = value;
} }
// 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 decrypt, bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32 output_length, bool decrypt,
int callback_event_type, DIInterruptType* interrupt_type, u64* ticks_until_completion) bool reply_to_ios, DIInterruptType* interrupt_type, u64* ticks_until_completion)
{ {
if (!s_disc_inside) if (!s_disc_inside)
{ {
@ -675,15 +668,15 @@ bool ExecuteReadCommand(u64 DVD_offset, u32 output_address, u32 DVD_length, u32
*ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length); *ticks_until_completion = SimulateDiscReadTime(DVD_offset, DVD_length);
DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt, DVDThread::StartRead(DVD_offset, output_address, DVD_length, decrypt,
callback_event_type, (int)*ticks_until_completion); reply_to_ios, (int)*ticks_until_completion);
return true; return true;
} }
// When the command has finished executing, callback_event_type // When the command has finished executing, callback_event_type
// will be called using CoreTiming::ScheduleEvent, // will be called using CoreTiming::ScheduleEvent,
// with the userdata set to the interrupt type. // with the userdata set to the interrupt type.
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length, void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
bool write_to_DIIMMBUF, int callback_event_type) u32 output_length, bool reply_to_ios)
{ {
DIInterruptType interrupt_type = INT_TCINT; DIInterruptType interrupt_type = INT_TCINT;
u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000; u64 ticks_until_completion = SystemTimers::GetTicksPerSecond() / 15000;
@ -713,7 +706,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
{ {
// 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.
WriteImmediate(0x21000000, output_address, write_to_DIIMMBUF); WriteImmediate(0x21000000, output_address, reply_to_ios);
} }
else else
{ {
@ -733,14 +726,14 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
case DVDLowReadDiskID: case DVDLowReadDiskID:
INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID"); INFO_LOG(DVDINTERFACE, "DVDLowReadDiskID");
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
callback_event_type, &interrupt_type, &ticks_until_completion); reply_to_ios, &interrupt_type, &ticks_until_completion);
break; break;
// Only used from WII_IPC. This is the only read command that decrypts data // Only used from WII_IPC. This is the only read command that decrypts data
case DVDLowRead: case DVDLowRead:
INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1); INFO_LOG(DVDINTERFACE, "DVDLowRead: DVDAddr: 0x%09" PRIx64 ", Size: 0x%x", (u64)command_2 << 2, command_1);
command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true, command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, true,
callback_event_type, &interrupt_type, &ticks_until_completion); reply_to_ios, &interrupt_type, &ticks_until_completion);
break; break;
// Probably only used by Wii // Probably only used by Wii
@ -756,7 +749,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
// Probably only used though WII_IPC // Probably only used though WII_IPC
case DVDLowGetCoverReg: case DVDLowGetCoverReg:
WriteImmediate(s_DICVR.Hex, output_address, write_to_DIIMMBUF); WriteImmediate(s_DICVR.Hex, output_address, reply_to_ios);
INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", s_DICVR.Hex); INFO_LOG(DVDINTERFACE, "DVDLowGetCoverReg 0x%08x", s_DICVR.Hex);
break; break;
@ -789,7 +782,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
// Probably only used by Wii // Probably only used by Wii
case DVDLowGetCoverStatus: case DVDLowGetCoverStatus:
WriteImmediate(s_disc_inside ? 2 : 1, output_address, write_to_DIIMMBUF); WriteImmediate(s_disc_inside ? 2 : 1, output_address, reply_to_ios);
INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", s_disc_inside ? "" : "Not "); INFO_LOG(DVDINTERFACE, "DVDLowGetCoverStatus: Disc %sInserted", s_disc_inside ? "" : "Not ");
break; break;
@ -820,7 +813,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
(((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008))) (((command_2 + command_1) > 0x7ed40000) && (command_2 + command_1) < 0x7ed40008)))
{ {
command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false, command_handled_by_thread = ExecuteReadCommand((u64)command_2 << 2, output_address, command_1, output_length, false,
callback_event_type, &interrupt_type, &ticks_until_completion); reply_to_ios, &interrupt_type, &ticks_until_completion);
} }
else else
{ {
@ -917,14 +910,14 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
} }
command_handled_by_thread = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false, command_handled_by_thread = ExecuteReadCommand(iDVDOffset, output_address, command_2, output_length, false,
callback_event_type, &interrupt_type, &ticks_until_completion); reply_to_ios, &interrupt_type, &ticks_until_completion);
} }
break; break;
case 0x40: // Read DiscID case 0x40: // Read DiscID
INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address)); INFO_LOG(DVDINTERFACE, "Read DiscID %08x", Memory::Read_U32(output_address));
command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false, command_handled_by_thread = ExecuteReadCommand(0, output_address, 0x20, output_length, false,
callback_event_type, &interrupt_type, &ticks_until_completion); reply_to_ios, &interrupt_type, &ticks_until_completion);
break; break;
default: default:
@ -1060,7 +1053,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
break; break;
} }
memset(s_media_buffer + 0x20, 0, 0x20); memset(s_media_buffer + 0x20, 0, 0x20);
WriteImmediate(0x66556677, output_address, write_to_DIIMMBUF); // just a random value that works. WriteImmediate(0x66556677, output_address, reply_to_ios); // just a random value that works.
} }
break; break;
@ -1105,7 +1098,7 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
// Used by both GC and Wii // Used by both GC and Wii
case DVDLowRequestError: case DVDLowRequestError:
INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", s_error_code); INFO_LOG(DVDINTERFACE, "Requesting error... (0x%08x)", s_error_code);
WriteImmediate(s_error_code, output_address, write_to_DIIMMBUF); WriteImmediate(s_error_code, output_address, reply_to_ios);
s_error_code = 0; s_error_code = 0;
break; break;
@ -1162,19 +1155,19 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
case 0x00: // Returns streaming status case 0x00: // Returns streaming status
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x", INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x/%08x CurrentStart:%08x CurrentLength:%08x",
s_audio_position, s_current_start + s_current_length, s_current_start, s_current_length); s_audio_position, s_current_start + s_current_length, s_current_start, s_current_length);
WriteImmediate(s_stream ? 1 : 0, output_address, write_to_DIIMMBUF); WriteImmediate(s_stream ? 1 : 0, output_address, reply_to_ios);
break; break;
case 0x01: // Returns the current offset case 0x01: // Returns the current offset
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", s_audio_position); INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status AudioPos:%08x", s_audio_position);
WriteImmediate(s_audio_position >> 2, output_address, write_to_DIIMMBUF); WriteImmediate(s_audio_position >> 2, output_address, reply_to_ios);
break; break;
case 0x02: // Returns the start offset case 0x02: // Returns the start offset
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", s_current_start); INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentStart:%08x", s_current_start);
WriteImmediate(s_current_start >> 2, output_address, write_to_DIIMMBUF); WriteImmediate(s_current_start >> 2, output_address, reply_to_ios);
break; break;
case 0x03: // Returns the total length case 0x03: // Returns the total length
INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", s_current_length); INFO_LOG(DVDINTERFACE, "(Audio): Stream Status: Request Audio status CurrentLength:%08x", s_current_length);
WriteImmediate(s_current_length >> 2, output_address, write_to_DIIMMBUF); WriteImmediate(s_current_length >> 2, output_address, reply_to_ios);
break; break;
default: default:
WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", command_0 >> 16 & 0xFF, s_stream ? "on" : "off"); WARN_LOG(DVDINTERFACE, "(Audio): Subcommand: %02x Request Audio status %s", command_0 >> 16 & 0xFF, s_stream ? "on" : "off");
@ -1263,7 +1256,35 @@ void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_addr
// The command will finish executing after a delay // The command will finish executing after a delay
// to simulate the speed of a real disc drive // to simulate the speed of a real disc drive
if (!command_handled_by_thread) if (!command_handled_by_thread)
CoreTiming::ScheduleEvent((int)ticks_until_completion, callback_event_type, interrupt_type); {
u64 userdata = (static_cast<u64>(reply_to_ios) << 32) + static_cast<u32>(interrupt_type);
CoreTiming::ScheduleEvent((int)ticks_until_completion, s_finish_executing_command, userdata);
}
}
void FinishExecutingCommandCallback(u64 userdata, s64 cycles_late)
{
bool reply_to_ios = userdata >> 32 != 0;
DIInterruptType interrupt_type = static_cast<DIInterruptType>(userdata & 0xFFFFFFFF);
FinishExecutingCommand(reply_to_ios, interrupt_type);
}
void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type)
{
if (reply_to_ios)
{
std::shared_ptr<IWII_IPC_HLE_Device> di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di");
if (di)
std::static_pointer_cast<CWII_IPC_HLE_Device_di>(di)->FinishIOCtl(interrupt_type);
// If di == nullptr, IOS was probably shut down, so the command shouldn't be completed
}
else if (s_DICR.TSTART)
{
s_DICR.TSTART = 0;
s_DILENGTH.Length = 0;
GenerateDIInterrupt(interrupt_type);
}
} }
// Simulates the timing aspects of reading data from a disc. // Simulates the timing aspects of reading data from a disc.

View File

@ -106,7 +106,8 @@ void ChangeDisc(const std::string& fileName);
// DVD Access Functions // DVD Access Functions
bool ChangePartition(u64 offset); bool ChangePartition(u64 offset);
void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address, u32 output_length, void ExecuteCommand(u32 command_0, u32 command_1, u32 command_2, u32 output_address,
bool write_to_DIIMMBUF, int callback_event_type); u32 output_length, bool reply_to_ios);
void FinishExecutingCommand(bool reply_to_ios, DIInterruptType interrupt_type);
} // end of namespace DVDInterface } // end of namespace DVDInterface

View File

@ -30,7 +30,7 @@ namespace DVDThread
static void DVDThread(); static void DVDThread();
static void FinishRead(u64 userdata, s64 cyclesLate); static void FinishRead(u64 userdata, s64 cycles_late);
static int s_finish_read; static int s_finish_read;
static std::thread s_dvd_thread; static std::thread s_dvd_thread;
@ -47,9 +47,9 @@ static u32 s_output_address;
static u32 s_length; static u32 s_length;
static bool s_decrypt; static bool s_decrypt;
// Used to notify emulated software after executing command. // This determines which function will be used as a callback.
// Pointers don't work with savestates, so CoreTiming events are used instead // We can't have a function pointer here, because they can't be in savestates.
static int s_callback_event_type; static bool s_reply_to_ios;
// The following time variables are only used for logging // The following time variables are only used for logging
static u64 s_realtime_started_us; static u64 s_realtime_started_us;
@ -89,7 +89,7 @@ void DoState(PointerWrap &p)
p.Do(s_output_address); p.Do(s_output_address);
p.Do(s_length); p.Do(s_length);
p.Do(s_decrypt); p.Do(s_decrypt);
p.Do(s_callback_event_type); p.Do(s_reply_to_ios);
// s_realtime_started_us and s_realtime_done_us aren't savestated // s_realtime_started_us and s_realtime_done_us aren't savestated
// because they rely on the current system's time. // because they rely on the current system's time.
@ -109,7 +109,7 @@ void WaitUntilIdle()
} }
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
int callback_event_type, int ticks_until_completion) bool reply_to_ios, int ticks_until_completion)
{ {
_assert_(Core::IsCPUThread()); _assert_(Core::IsCPUThread());
@ -119,7 +119,7 @@ void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
s_output_address = output_address; s_output_address = output_address;
s_length = length; s_length = length;
s_decrypt = decrypt; s_decrypt = decrypt;
s_callback_event_type = callback_event_type; s_reply_to_ios = reply_to_ios;
s_time_read_started = CoreTiming::GetTicks(); s_time_read_started = CoreTiming::GetTicks();
s_realtime_started_us = Common::Timer::GetTimeUs(); s_realtime_started_us = Common::Timer::GetTimeUs();
@ -129,7 +129,7 @@ void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read); CoreTiming::ScheduleEvent(ticks_until_completion, s_finish_read);
} }
static void FinishRead(u64 userdata, s64 cyclesLate) static void FinishRead(u64 userdata, s64 cycles_late)
{ {
WaitUntilIdle(); WaitUntilIdle();
@ -151,7 +151,7 @@ static void FinishRead(u64 userdata, s64 cyclesLate)
s_dvd_buffer.resize(0); s_dvd_buffer.resize(0);
// Notify the emulated software that the command has been executed // Notify the emulated software that the command has been executed
CoreTiming::ScheduleEvent_Immediate(s_callback_event_type, DVDInterface::INT_TCINT); DVDInterface::FinishExecutingCommand(s_reply_to_ios, DVDInterface::INT_TCINT);
} }
static void DVDThread() static void DVDThread()

View File

@ -16,6 +16,6 @@ void DoState(PointerWrap &p);
void WaitUntilIdle(); void WaitUntilIdle();
void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt, void StartRead(u64 dvd_offset, u32 output_address, u32 length, bool decrypt,
int callback_event_type, int ticks_until_completion); bool reply_to_ios, int ticks_until_completion);
} }

View File

@ -16,21 +16,9 @@
#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"
static int ioctl_callback;
static void IOCtlCallback(u64 userdata, s64 cycles_late)
{
std::shared_ptr<IWII_IPC_HLE_Device> di = WII_IPC_HLE_Interface::GetDeviceByName("/dev/di");
if (di)
std::static_pointer_cast<CWII_IPC_HLE_Device_di>(di)->FinishIOCtl((DVDInterface::DIInterruptType)userdata);
// If di == nullptr, IOS was probably shut down, so the command shouldn't be completed
}
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)
{ {
ioctl_callback = CoreTiming::RegisterEvent("IOCtlCallbackDI", IOCtlCallback);
} }
CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di() CWII_IPC_HLE_Device_di::~CWII_IPC_HLE_Device_di()
@ -101,8 +89,7 @@ void CWII_IPC_HLE_Device_di::StartIOCtl(u32 command_address)
// DVDInterface's ExecuteCommand handles most of the work. // DVDInterface's ExecuteCommand handles most of the work.
// The IOCtl callback is used to generate a reply afterwards. // The IOCtl callback is used to generate a reply afterwards.
DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, DVDInterface::ExecuteCommand(command_0, command_1, command_2, BufferOut, BufferOutSize, true);
false, ioctl_callback);
} }
void CWII_IPC_HLE_Device_di::FinishIOCtl(DVDInterface::DIInterruptType interrupt_type) void CWII_IPC_HLE_Device_di::FinishIOCtl(DVDInterface::DIInterruptType interrupt_type)

View File

@ -71,7 +71,7 @@ static Common::Event g_compressAndDumpStateSyncEvent;
static std::thread g_save_thread; static std::thread g_save_thread;
// Don't forget to increase this after doing changes on the savestate system // Don't forget to increase this after doing changes on the savestate system
static const u32 STATE_VERSION = 52; // Last changed in PR 3667 static const u32 STATE_VERSION = 53; // Last changed in PR 3759
// Maps savestate versions to Dolphin versions. // Maps savestate versions to Dolphin versions.
// Versions after 42 don't need to be added to this list, // Versions after 42 don't need to be added to this list,