Merge pull request #4244 from leoetlino/stm-shutdown
Shut down Wii software gracefully
This commit is contained in:
commit
5e8bc4aa1d
|
@ -314,7 +314,7 @@ void SysConf::GenerateSysConf()
|
|||
|
||||
// IPL.IDL
|
||||
current_offset += create_item(items[23], Type_SmallArray, "IPL.IDL", 1, current_offset);
|
||||
items[23].data[0] = 0x01;
|
||||
items[23].data[0] = 0x00;
|
||||
|
||||
// IPL.EULA
|
||||
current_offset += create_item(items[24], Type_Bool, "IPL.EULA", 1, current_offset);
|
||||
|
|
|
@ -392,6 +392,15 @@ bool BootCore(const std::string& _rFilename)
|
|||
SConfig::GetInstance().m_SYSCONF->SetData("IPL.PGS", StartUp.bProgressive);
|
||||
SConfig::GetInstance().m_SYSCONF->SetData("IPL.E60", StartUp.bPAL60);
|
||||
|
||||
if (StartUp.bWii)
|
||||
{
|
||||
// Disable WiiConnect24's standby mode. If it is enabled, it prevents us from receiving
|
||||
// shutdown commands in the State Transition Manager (STM).
|
||||
// TODO: remove this if and once Dolphin supports WC24 standby mode.
|
||||
SConfig::GetInstance().m_SYSCONF->SetData("IPL.IDL", 0x00);
|
||||
NOTICE_LOG(BOOT, "Disabling WC24 'standby' (shutdown to idle) to avoid hanging on shutdown");
|
||||
}
|
||||
|
||||
// Run the game
|
||||
// Init the core
|
||||
if (!Core::Init())
|
||||
|
|
|
@ -143,6 +143,7 @@ set(SRCS ActionReplay.cpp
|
|||
IPC_HLE/WII_Socket.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_net.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_net_ssl.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_stm.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_sdio_slot0.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_usb.cpp
|
||||
IPC_HLE/WII_IPC_HLE_Device_usb_kbd.cpp
|
||||
|
|
|
@ -183,6 +183,7 @@
|
|||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_net.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_net_ssl.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_stm.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb.cpp" />
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_usb_kbd.cpp" />
|
||||
|
@ -386,8 +387,8 @@
|
|||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_hid.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_net.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_net_ssl.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_stm.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_kbd.h" />
|
||||
<ClInclude Include="IPC_HLE\WII_IPC_HLE_Device_usb_ven.h" />
|
||||
|
@ -480,4 +481,4 @@
|
|||
<Import Project="$(VCTargetsPath)\Microsoft.Cpp.targets" />
|
||||
<ImportGroup Label="ExtensionTargets">
|
||||
</ImportGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -585,6 +585,9 @@
|
|||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_sdio_slot0.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\SDIO - SD Card</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_stm.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="IPC_HLE\WII_IPC_HLE_Device_hid.cpp">
|
||||
<Filter>IPC HLE %28IOS/Starlet%29\USB</Filter>
|
||||
</ClCompile>
|
||||
|
@ -1247,4 +1250,4 @@
|
|||
<ItemGroup>
|
||||
<Text Include="CMakeLists.txt" />
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
</Project>
|
||||
|
|
|
@ -37,6 +37,9 @@ static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate);
|
|||
static CoreTiming::EventType* iosNotifyResetButton;
|
||||
static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate);
|
||||
|
||||
static CoreTiming::EventType* iosNotifyPowerButton;
|
||||
static void IOSNotifyPowerButtonCallback(u64 userdata, s64 cyclesLate);
|
||||
|
||||
// Let the PPC know that an external exception is set/cleared
|
||||
void UpdateException();
|
||||
|
||||
|
@ -75,6 +78,8 @@ void Init()
|
|||
toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback);
|
||||
iosNotifyResetButton =
|
||||
CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback);
|
||||
iosNotifyPowerButton =
|
||||
CoreTiming::RegisterEvent("IOSNotifyPowerButton", IOSNotifyPowerButtonCallback);
|
||||
}
|
||||
|
||||
void RegisterMMIO(MMIO::Mapping* mmio, u32 base)
|
||||
|
@ -214,6 +219,17 @@ static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate)
|
|||
}
|
||||
}
|
||||
|
||||
static void IOSNotifyPowerButtonCallback(u64 userdata, s64 cyclesLate)
|
||||
{
|
||||
if (SConfig::GetInstance().bWii)
|
||||
{
|
||||
std::shared_ptr<IWII_IPC_HLE_Device> stm =
|
||||
WII_IPC_HLE_Interface::GetDeviceByName("/dev/stm/eventhook");
|
||||
if (stm)
|
||||
std::static_pointer_cast<CWII_IPC_HLE_Device_stm_eventhook>(stm)->PowerButton();
|
||||
}
|
||||
}
|
||||
|
||||
void ResetButton_Tap()
|
||||
{
|
||||
CoreTiming::ScheduleEvent(0, toggleResetButton, true, CoreTiming::FromThread::ANY);
|
||||
|
@ -222,4 +238,9 @@ void ResetButton_Tap()
|
|||
CoreTiming::FromThread::ANY);
|
||||
}
|
||||
|
||||
void PowerButton_Tap()
|
||||
{
|
||||
CoreTiming::ScheduleEvent(0, iosNotifyPowerButton, 0, CoreTiming::FromThread::ANY);
|
||||
}
|
||||
|
||||
} // namespace ProcessorInterface
|
||||
|
|
|
@ -76,5 +76,6 @@ void SetInterrupt(u32 _causemask, bool _bSet = true);
|
|||
|
||||
// Thread-safe func which sets and clears reset button state automagically
|
||||
void ResetButton_Tap();
|
||||
void PowerButton_Tap();
|
||||
|
||||
} // namespace ProcessorInterface
|
||||
|
|
|
@ -0,0 +1,169 @@
|
|||
// Copyright 2016 Dolphin Emulator Project
|
||||
// Licensed under GPLv2+
|
||||
// Refer to the license.txt file included.
|
||||
|
||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h"
|
||||
|
||||
namespace Core
|
||||
{
|
||||
void QueueHostJob(std::function<void()> job, bool run_during_stop);
|
||||
void Stop();
|
||||
}
|
||||
|
||||
static u32 s_event_hook_address = 0;
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::Open(u32 command_address, u32 mode)
|
||||
{
|
||||
INFO_LOG(WII_IPC_STM, "STM immediate: Open");
|
||||
Memory::Write_U32(GetDeviceID(), command_address + 4);
|
||||
m_Active = true;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::Close(u32 command_address, bool force)
|
||||
{
|
||||
INFO_LOG(WII_IPC_STM, "STM immediate: Close");
|
||||
if (!force)
|
||||
Memory::Write_U32(0, command_address + 4);
|
||||
m_Active = false;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_immediate::IOCtl(u32 command_address)
|
||||
{
|
||||
u32 parameter = Memory::Read_U32(command_address + 0x0C);
|
||||
u32 buffer_in = Memory::Read_U32(command_address + 0x10);
|
||||
u32 buffer_in_size = Memory::Read_U32(command_address + 0x14);
|
||||
u32 buffer_out = Memory::Read_U32(command_address + 0x18);
|
||||
u32 buffer_out_size = Memory::Read_U32(command_address + 0x1C);
|
||||
|
||||
// Prepare the out buffer(s) with zeroes as a safety precaution
|
||||
// to avoid returning bad values
|
||||
Memory::Memset(buffer_out, 0, buffer_out_size);
|
||||
u32 return_value = 0;
|
||||
|
||||
switch (parameter)
|
||||
{
|
||||
case IOCTL_STM_IDLE:
|
||||
case IOCTL_STM_SHUTDOWN:
|
||||
NOTICE_LOG(WII_IPC_STM, "IOCTL_STM_IDLE or IOCTL_STM_SHUTDOWN received, shutting down");
|
||||
Core::QueueHostJob(&Core::Stop, false);
|
||||
break;
|
||||
|
||||
case IOCTL_STM_RELEASE_EH:
|
||||
if (s_event_hook_address == 0)
|
||||
{
|
||||
return_value = FS_ENOENT;
|
||||
break;
|
||||
}
|
||||
Memory::Write_U32(0, Memory::Read_U32(s_event_hook_address + 0x18));
|
||||
Memory::Write_U32(FS_SUCCESS, s_event_hook_address + 4);
|
||||
Memory::Write_U32(IPC_REP_ASYNC, s_event_hook_address);
|
||||
Memory::Write_U32(IPC_CMD_IOCTL, s_event_hook_address + 8);
|
||||
WII_IPC_HLE_Interface::EnqueueReply(s_event_hook_address);
|
||||
s_event_hook_address = 0;
|
||||
break;
|
||||
|
||||
case IOCTL_STM_HOTRESET:
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET");
|
||||
break;
|
||||
|
||||
case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes)
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING");
|
||||
// DumpCommands(buffer_in, buffer_in_size / 4, LogTypes::WII_IPC_STM);
|
||||
// Memory::Write_U32(1, buffer_out);
|
||||
// return_value = 1;
|
||||
break;
|
||||
|
||||
case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes)
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE");
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", parameter);
|
||||
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
DEBUG_LOG(WII_IPC_STM, " parameter: 0x%x", parameter);
|
||||
DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", buffer_in);
|
||||
DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", buffer_in_size);
|
||||
DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", buffer_out);
|
||||
DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", buffer_out_size);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Write return value to the IPC call
|
||||
Memory::Write_U32(return_value, command_address + 0x4);
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::Open(u32 command_address, u32 mode)
|
||||
{
|
||||
Memory::Write_U32(GetDeviceID(), command_address + 4);
|
||||
m_Active = true;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::Close(u32 command_address, bool force)
|
||||
{
|
||||
s_event_hook_address = 0;
|
||||
|
||||
INFO_LOG(WII_IPC_STM, "STM eventhook: Close");
|
||||
if (!force)
|
||||
Memory::Write_U32(0, command_address + 4);
|
||||
m_Active = false;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult CWII_IPC_HLE_Device_stm_eventhook::IOCtl(u32 command_address)
|
||||
{
|
||||
u32 parameter = Memory::Read_U32(command_address + 0x0C);
|
||||
if (parameter != IOCTL_STM_EVENTHOOK)
|
||||
{
|
||||
ERROR_LOG(WII_IPC_STM, "Bad IOCtl in CWII_IPC_HLE_Device_stm_eventhook");
|
||||
Memory::Write_U32(FS_EINVAL, command_address + 4);
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
// IOCTL_STM_EVENTHOOK waits until the reset button or power button
|
||||
// is pressed.
|
||||
s_event_hook_address = command_address;
|
||||
return GetNoReply();
|
||||
}
|
||||
|
||||
void CWII_IPC_HLE_Device_stm_eventhook::TriggerEvent(const u32 event) const
|
||||
{
|
||||
if (!m_Active || s_event_hook_address == 0)
|
||||
{
|
||||
// If the device isn't open, ignore the button press.
|
||||
return;
|
||||
}
|
||||
|
||||
// The reset button returns STM_EVENT_RESET.
|
||||
u32 buffer_out = Memory::Read_U32(s_event_hook_address + 0x18);
|
||||
Memory::Write_U32(event, buffer_out);
|
||||
|
||||
// Fill in command buffer.
|
||||
Memory::Write_U32(FS_SUCCESS, s_event_hook_address + 4);
|
||||
Memory::Write_U32(IPC_REP_ASYNC, s_event_hook_address);
|
||||
Memory::Write_U32(IPC_CMD_IOCTL, s_event_hook_address + 8);
|
||||
|
||||
// Generate a reply to the IPC command.
|
||||
WII_IPC_HLE_Interface::EnqueueReply(s_event_hook_address);
|
||||
s_event_hook_address = 0;
|
||||
}
|
||||
|
||||
void CWII_IPC_HLE_Device_stm_eventhook::ResetButton() const
|
||||
{
|
||||
// The reset button returns STM_EVENT_RESET.
|
||||
TriggerEvent(STM_EVENT_RESET);
|
||||
}
|
||||
|
||||
void CWII_IPC_HLE_Device_stm_eventhook::PowerButton() const
|
||||
{
|
||||
TriggerEvent(STM_EVENT_POWER);
|
||||
}
|
|
@ -4,7 +4,6 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include "Core/IPC_HLE/WII_IPC_HLE_Device.h"
|
||||
|
||||
enum
|
||||
|
@ -32,155 +31,37 @@ enum
|
|||
};
|
||||
|
||||
// The /dev/stm/immediate
|
||||
class CWII_IPC_HLE_Device_stm_immediate : public IWII_IPC_HLE_Device
|
||||
class CWII_IPC_HLE_Device_stm_immediate final : public IWII_IPC_HLE_Device
|
||||
{
|
||||
public:
|
||||
CWII_IPC_HLE_Device_stm_immediate(u32 _DeviceID, const std::string& _rDeviceName)
|
||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName)
|
||||
CWII_IPC_HLE_Device_stm_immediate(u32 device_id, const std::string& device_name)
|
||||
: IWII_IPC_HLE_Device(device_id, device_name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CWII_IPC_HLE_Device_stm_immediate() {}
|
||||
IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override
|
||||
{
|
||||
INFO_LOG(WII_IPC_STM, "STM immediate: Open");
|
||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
||||
m_Active = true;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override
|
||||
{
|
||||
INFO_LOG(WII_IPC_STM, "STM immediate: Close");
|
||||
if (!_bForce)
|
||||
Memory::Write_U32(0, _CommandAddress + 4);
|
||||
m_Active = false;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult IOCtl(u32 _CommandAddress) override
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
|
||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||
|
||||
// Prepare the out buffer(s) with zeroes as a safety precaution
|
||||
// to avoid returning bad values
|
||||
Memory::Memset(BufferOut, 0, BufferOutSize);
|
||||
u32 ReturnValue = 0;
|
||||
|
||||
switch (Parameter)
|
||||
{
|
||||
case IOCTL_STM_RELEASE_EH:
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_RELEASE_EH");
|
||||
break;
|
||||
|
||||
case IOCTL_STM_HOTRESET:
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_HOTRESET");
|
||||
break;
|
||||
|
||||
case IOCTL_STM_VIDIMMING: // (Input: 20 bytes, Output: 20 bytes)
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_VIDIMMING");
|
||||
// DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM);
|
||||
// Memory::Write_U32(1, BufferOut);
|
||||
// ReturnValue = 1;
|
||||
break;
|
||||
|
||||
case IOCTL_STM_LEDMODE: // (Input: 20 bytes, Output: 20 bytes)
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
INFO_LOG(WII_IPC_STM, " IOCTL_STM_LEDMODE");
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_immediate: 0x%x", Parameter);
|
||||
|
||||
INFO_LOG(WII_IPC_STM, "%s - IOCtl:", GetDeviceName().c_str());
|
||||
DEBUG_LOG(WII_IPC_STM, " Parameter: 0x%x", Parameter);
|
||||
DEBUG_LOG(WII_IPC_STM, " InBuffer: 0x%08x", BufferIn);
|
||||
DEBUG_LOG(WII_IPC_STM, " InBufferSize: 0x%08x", BufferInSize);
|
||||
DEBUG_LOG(WII_IPC_STM, " OutBuffer: 0x%08x", BufferOut);
|
||||
DEBUG_LOG(WII_IPC_STM, " OutBufferSize: 0x%08x", BufferOutSize);
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
// Write return value to the IPC call
|
||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||
return GetDefaultReply();
|
||||
}
|
||||
~CWII_IPC_HLE_Device_stm_immediate() override = default;
|
||||
IPCCommandResult Open(u32 command_address, u32 mode) override;
|
||||
IPCCommandResult Close(u32 command_address, bool force) override;
|
||||
IPCCommandResult IOCtl(u32 command_address) override;
|
||||
};
|
||||
|
||||
// The /dev/stm/eventhook
|
||||
class CWII_IPC_HLE_Device_stm_eventhook : public IWII_IPC_HLE_Device
|
||||
class CWII_IPC_HLE_Device_stm_eventhook final : public IWII_IPC_HLE_Device
|
||||
{
|
||||
public:
|
||||
CWII_IPC_HLE_Device_stm_eventhook(u32 _DeviceID, const std::string& _rDeviceName)
|
||||
: IWII_IPC_HLE_Device(_DeviceID, _rDeviceName), m_EventHookAddress(0)
|
||||
CWII_IPC_HLE_Device_stm_eventhook(u32 device_id, const std::string& device_name)
|
||||
: IWII_IPC_HLE_Device(device_id, device_name)
|
||||
{
|
||||
}
|
||||
|
||||
virtual ~CWII_IPC_HLE_Device_stm_eventhook() {}
|
||||
IPCCommandResult Open(u32 _CommandAddress, u32 _Mode) override
|
||||
{
|
||||
Memory::Write_U32(GetDeviceID(), _CommandAddress + 4);
|
||||
m_Active = true;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
~CWII_IPC_HLE_Device_stm_eventhook() override = default;
|
||||
IPCCommandResult Open(u32 command_address, u32 mode) override;
|
||||
IPCCommandResult Close(u32 command_address, bool force) override;
|
||||
IPCCommandResult IOCtl(u32 command_address) override;
|
||||
|
||||
IPCCommandResult Close(u32 _CommandAddress, bool _bForce) override
|
||||
{
|
||||
m_EventHookAddress = 0;
|
||||
void ResetButton() const;
|
||||
void PowerButton() const;
|
||||
|
||||
INFO_LOG(WII_IPC_STM, "STM eventhook: Close");
|
||||
if (!_bForce)
|
||||
Memory::Write_U32(0, _CommandAddress + 4);
|
||||
m_Active = false;
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
IPCCommandResult IOCtl(u32 _CommandAddress) override
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
|
||||
if (Parameter != IOCTL_STM_EVENTHOOK)
|
||||
{
|
||||
ERROR_LOG(WII_IPC_STM, "Bad IOCtl in CWII_IPC_HLE_Device_stm_eventhook");
|
||||
Memory::Write_U32(FS_EINVAL, _CommandAddress + 4);
|
||||
return GetDefaultReply();
|
||||
}
|
||||
|
||||
// IOCTL_STM_EVENTHOOK waits until the reset button or power button
|
||||
// is pressed.
|
||||
m_EventHookAddress = _CommandAddress;
|
||||
return GetNoReply();
|
||||
}
|
||||
|
||||
void ResetButton()
|
||||
{
|
||||
if (!m_Active || m_EventHookAddress == 0)
|
||||
{
|
||||
// If the device isn't open, ignore the button press.
|
||||
return;
|
||||
}
|
||||
|
||||
// The reset button returns STM_EVENT_RESET.
|
||||
u32 BufferOut = Memory::Read_U32(m_EventHookAddress + 0x18);
|
||||
Memory::Write_U32(STM_EVENT_RESET, BufferOut);
|
||||
|
||||
// Fill in command buffer.
|
||||
Memory::Write_U32(FS_SUCCESS, m_EventHookAddress + 4);
|
||||
Memory::Write_U32(IPC_REP_ASYNC, m_EventHookAddress);
|
||||
Memory::Write_U32(IPC_CMD_IOCTL, m_EventHookAddress + 8);
|
||||
|
||||
// Generate a reply to the IPC command.
|
||||
WII_IPC_HLE_Interface::EnqueueReply(m_EventHookAddress);
|
||||
}
|
||||
|
||||
// STATE_TO_SAVE
|
||||
u32 m_EventHookAddress;
|
||||
private:
|
||||
void TriggerEvent(u32 event) const;
|
||||
};
|
||||
|
|
|
@ -158,6 +158,7 @@ private:
|
|||
bool m_bGameLoading = false;
|
||||
bool m_bClosing = false;
|
||||
bool m_confirmStop = false;
|
||||
bool m_tried_graceful_shutdown = false;
|
||||
int m_saveSlot = 1;
|
||||
|
||||
std::vector<std::string> drives;
|
||||
|
|
|
@ -1148,9 +1148,12 @@ void CFrame::DoStop()
|
|||
Core::SetState(Core::CORE_PAUSE);
|
||||
}
|
||||
|
||||
wxMessageDialog m_StopDlg(this, _("Do you want to stop the current emulation?"),
|
||||
_("Please confirm..."),
|
||||
wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition);
|
||||
wxMessageDialog m_StopDlg(
|
||||
this, !m_tried_graceful_shutdown ? _("Do you want to stop the current emulation?") :
|
||||
_("A shutdown is already in progress. Unsaved data "
|
||||
"may be lost if you stop the current emulation "
|
||||
"before it completes. Force stop?"),
|
||||
_("Please confirm..."), wxYES_NO | wxSTAY_ON_TOP | wxICON_EXCLAMATION, wxDefaultPosition);
|
||||
|
||||
HotkeyManagerEmu::Enable(false);
|
||||
int Ret = m_StopDlg.ShowModal();
|
||||
|
@ -1165,6 +1168,16 @@ void CFrame::DoStop()
|
|||
}
|
||||
}
|
||||
|
||||
if (SConfig::GetInstance().bWii && !m_tried_graceful_shutdown)
|
||||
{
|
||||
Core::DisplayMessage("Shutting down", 30000);
|
||||
Core::SetState(Core::CORE_RUN);
|
||||
ProcessorInterface::PowerButton_Tap();
|
||||
m_confirmStop = false;
|
||||
m_tried_graceful_shutdown = true;
|
||||
return;
|
||||
}
|
||||
|
||||
if (UseDebugger && g_pCodeWindow)
|
||||
{
|
||||
if (g_pCodeWindow->m_WatchWindow)
|
||||
|
@ -1200,6 +1213,7 @@ void CFrame::DoStop()
|
|||
void CFrame::OnStopped()
|
||||
{
|
||||
m_confirmStop = false;
|
||||
m_tried_graceful_shutdown = false;
|
||||
|
||||
#if defined(HAVE_X11) && HAVE_X11
|
||||
if (SConfig::GetInstance().bDisableScreenSaver)
|
||||
|
|
|
@ -34,6 +34,8 @@
|
|||
static bool rendererHasFocus = true;
|
||||
static bool rendererIsFullscreen = false;
|
||||
static Common::Flag s_running{true};
|
||||
static Common::Flag s_shutdown_requested{false};
|
||||
static Common::Flag s_tried_graceful_shutdown{false};
|
||||
|
||||
static void signal_handler(int)
|
||||
{
|
||||
|
@ -41,7 +43,12 @@ static void signal_handler(int)
|
|||
if (write(STDERR_FILENO, message, sizeof(message)) < 0)
|
||||
{
|
||||
}
|
||||
s_running.Clear();
|
||||
s_shutdown_requested.Set();
|
||||
}
|
||||
|
||||
namespace ProcessorInterface
|
||||
{
|
||||
void PowerButton_Tap();
|
||||
}
|
||||
|
||||
class Platform
|
||||
|
@ -222,6 +229,19 @@ class PlatformX11 : public Platform
|
|||
// The actual loop
|
||||
while (s_running.IsSet())
|
||||
{
|
||||
if (s_shutdown_requested.TestAndClear())
|
||||
{
|
||||
if (!s_tried_graceful_shutdown.IsSet() && SConfig::GetInstance().bWii)
|
||||
{
|
||||
ProcessorInterface::PowerButton_Tap();
|
||||
s_tried_graceful_shutdown.Set();
|
||||
}
|
||||
else
|
||||
{
|
||||
s_running.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
XEvent event;
|
||||
KeySym key;
|
||||
for (int num_events = XPending(dpy); num_events > 0; num_events--)
|
||||
|
@ -286,7 +306,7 @@ class PlatformX11 : public Platform
|
|||
break;
|
||||
case ClientMessage:
|
||||
if ((unsigned long)event.xclient.data.l[0] == XInternAtom(dpy, "WM_DELETE_WINDOW", False))
|
||||
s_running.Clear();
|
||||
s_shutdown_requested.Set();
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
@ -375,6 +395,7 @@ int main(int argc, char* argv[])
|
|||
UICommon::SetUserDirectory(""); // Auto-detect user folder
|
||||
UICommon::Init();
|
||||
|
||||
Core::SetOnStoppedCallback([]() { s_running.Clear(); });
|
||||
platform->Init();
|
||||
|
||||
// Shut down cleanly on SIGINT and SIGTERM
|
||||
|
|
Loading…
Reference in New Issue