diff --git a/Source/Core/Core/HW/ProcessorInterface.cpp b/Source/Core/Core/HW/ProcessorInterface.cpp index d9a0cd82d4..a4b476f00a 100644 --- a/Source/Core/Core/HW/ProcessorInterface.cpp +++ b/Source/Core/Core/HW/ProcessorInterface.cpp @@ -10,6 +10,8 @@ #include "Core/CoreTiming.h" #include "Core/HW/MMIO.h" #include "Core/HW/ProcessorInterface.h" +#include "Core/IPC_HLE/WII_IPC_HLE.h" +#include "Core/IPC_HLE/WII_IPC_HLE_Device_stm.h" #include "Core/PowerPC/PowerPC.h" namespace ProcessorInterface @@ -31,6 +33,9 @@ static u32 m_Unknown; static int toggleResetButton; static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate); +static int iosNotifyResetButton; +static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate); + // Let the PPC know that an external exception is set/cleared void UpdateException(); @@ -67,6 +72,8 @@ void Init() m_InterruptCause = INT_CAUSE_RST_BUTTON | INT_CAUSE_VI; toggleResetButton = CoreTiming::RegisterEvent("ToggleResetButton", ToggleResetButtonCallback); + iosNotifyResetButton = + CoreTiming::RegisterEvent("IOSNotifyResetButton", IOSNotifyResetButtonCallback); } void RegisterMMIO(MMIO::Mapping* mmio, u32 base) @@ -195,9 +202,21 @@ static void ToggleResetButtonCallback(u64 userdata, s64 cyclesLate) SetResetButton(!!userdata); } +static void IOSNotifyResetButtonCallback(u64 userdata, s64 cyclesLate) +{ + if (SConfig::GetInstance().bWii) + { + std::shared_ptr stm = + WII_IPC_HLE_Interface::GetDeviceByName("/dev/stm/eventhook"); + if (stm) + std::static_pointer_cast(stm)->ResetButton(); + } +} + void ResetButton_Tap() { CoreTiming::ScheduleEvent_AnyThread(0, toggleResetButton, true); + CoreTiming::ScheduleEvent_AnyThread(0, iosNotifyResetButton, 0); CoreTiming::ScheduleEvent_AnyThread(243000000, toggleResetButton, false); } diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h index 1d7982db0b..d150cc71fa 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_stm.h @@ -25,6 +25,12 @@ enum IOCTL_STM_READDDRREG2 = 0x4002, }; +enum +{ + STM_EVENT_RESET = 0x00020000, + STM_EVENT_POWER = 0x00000800 +}; + // The /dev/stm/immediate class CWII_IPC_HLE_Device_stm_immediate : public IWII_IPC_HLE_Device { @@ -141,42 +147,38 @@ public: 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 zeros as a safety precaution - // to avoid returning bad values - Memory::Memset(BufferOut, 0, BufferOutSize); - u32 ReturnValue = 0; - - // write return value - switch (Parameter) + if (Parameter != IOCTL_STM_EVENTHOOK) { - case IOCTL_STM_EVENTHOOK: - { - m_EventHookAddress = _CommandAddress; - - INFO_LOG(WII_IPC_STM, "%s registers event hook:", GetDeviceName().c_str()); - DEBUG_LOG(WII_IPC_STM, "%x - IOCTL_STM_EVENTHOOK", Parameter); - DEBUG_LOG(WII_IPC_STM, "BufferIn: 0x%08x", BufferIn); - DEBUG_LOG(WII_IPC_STM, "BufferInSize: 0x%08x", BufferInSize); - DEBUG_LOG(WII_IPC_STM, "BufferOut: 0x%08x", BufferOut); - DEBUG_LOG(WII_IPC_STM, "BufferOutSize: 0x%08x", BufferOutSize); - - DumpCommands(BufferIn, BufferInSize / 4, LogTypes::WII_IPC_STM); - } - break; - - default: - _dbg_assert_msg_(WII_IPC_STM, 0, "unknown %s ioctl %x", GetDeviceName().c_str(), Parameter); - break; + ERROR_LOG(WII_IPC_STM, "Bad IOCtl in CWII_IPC_HLE_Device_stm_eventhook"); + Memory::Write_U32(FS_EINVAL, _CommandAddress + 4); + return GetDefaultReply(); } - // Write return value to the IPC call, 0 means success - Memory::Write_U32(ReturnValue, _CommandAddress + 0x4); - 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_Immediate(m_EventHookAddress); } // STATE_TO_SAVE