diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h index 2b7b230e1c..dee774905b 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_base.h @@ -28,6 +28,11 @@ public: virtual void TriggerSyncButtonPressedEvent() {} virtual void TriggerSyncButtonHeldEvent() {} protected: + static constexpr int ACL_PKT_SIZE = 339; + static constexpr int ACL_PKT_NUM = 10; + static constexpr int SCO_PKT_SIZE = 64; + static constexpr int SCO_PKT_NUM = 0; + enum USBIOCtl { USBV0_IOCTL_CTRLMSG = 0, diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp index 46a3669f54..58772cde85 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.cpp @@ -521,7 +521,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::ACLPool::Store(const u8* data, con return; } - _dbg_assert_msg_(WII_IPC_WIIMOTE, size < m_acl_pkt_size, "ACL packet too large for pool"); + _dbg_assert_msg_(WII_IPC_WIIMOTE, size < ACL_PKT_SIZE, "ACL packet too large for pool"); m_queue.push_back(Packet()); auto& packet = m_queue.back(); @@ -1824,13 +1824,13 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_emu::CommandReadBufferSize(const u8* in { hci_read_buffer_size_rp reply; reply.status = 0x00; - reply.max_acl_size = m_acl_pkt_size; + reply.max_acl_size = ACL_PKT_SIZE; // Due to how the widcomm stack which Nintendo uses is coded, we must never // let the stack think the controller is buffering more than 10 data packets // - it will cause a u8 underflow and royally screw things up. - reply.num_acl_pkts = m_acl_pkts_num; - reply.max_sco_size = 64; - reply.num_sco_pkts = 0; + reply.num_acl_pkts = ACL_PKT_NUM; + reply.max_sco_size = SCO_PKT_SIZE; + reply.num_sco_pkts = SCO_PKT_NUM; INFO_LOG(WII_IPC_WIIMOTE, "Command: HCI_CMD_READ_BUFFER_SIZE:"); DEBUG_LOG(WII_IPC_WIIMOTE, "return:"); diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h index bdf5404d74..48b56820c5 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_emu.h @@ -95,14 +95,11 @@ private: u32 m_ACLSetup; CtrlBuffer m_ACLEndpoint; - static const int m_acl_pkt_size = 339; - static const int m_acl_pkts_num = 10; - class ACLPool { struct Packet { - u8 data[m_acl_pkt_size]; + u8 data[ACL_PKT_SIZE]; u16 size; u16 conn_handle; }; diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp index ff5dcf0af4..7f9a4c7542 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.cpp @@ -140,6 +140,12 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad case USBV0_IOCTL_CTRLMSG: { auto cmd = std::make_unique(cmd_buffer); + const u16 opcode = *reinterpret_cast(Memory::GetPointer(cmd->payload_addr)); + if (opcode == HCI_CMD_READ_BUFFER_SIZE) + { + m_fake_read_buffer_size_reply.Set(); + return GetNoReply(); + } auto buffer = std::vector(cmd->length + LIBUSB_CONTROL_SETUP_SIZE); libusb_fill_control_setup(buffer.data(), cmd->request_type, cmd->request, cmd->value, cmd->index, cmd->length); @@ -156,6 +162,11 @@ IPCCommandResult CWII_IPC_HLE_Device_usb_oh1_57e_305_real::IOCtlV(u32 command_ad case USBV0_IOCTL_INTRMSG: { auto buffer = std::make_unique(cmd_buffer, command_address); + if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_fake_read_buffer_size_reply.TestAndClear()) + { + FakeReadBufferSizeReply(*buffer); + return GetNoReply(); + } if (cmd_buffer.Parameter == USBV0_IOCTL_INTRMSG && m_sync_button_state == SyncButtonState::Pressed) { @@ -241,6 +252,32 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::SendHCIResetCommand() INFO_LOG(WII_IPC_WIIMOTE, "Sent a reset command to adapter"); } +// Due to how the widcomm stack which Nintendo uses is coded, we must never +// let the stack think the controller is buffering more than 10 data packets +// - it will cause a u8 underflow and royally screw things up. +// Therefore, the reply to this command has to be faked to avoid random, weird issues +// (including Wiimote disconnects and "event mismatch" warning messages). +void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeReadBufferSizeReply(const CtrlBuffer& ctrl) +{ + u8* packet = Memory::GetPointer(ctrl.m_payload_addr); + auto* hci_event = reinterpret_cast(packet); + hci_event->EventType = HCI_EVENT_COMMAND_COMPL; + hci_event->PayloadLength = sizeof(SHCIEventCommand) - 2 + sizeof(hci_read_buffer_size_rp); + hci_event->PacketIndicator = 0x01; + hci_event->Opcode = HCI_CMD_READ_BUFFER_SIZE; + + hci_read_buffer_size_rp reply; + reply.status = 0x00; + reply.max_acl_size = ACL_PKT_SIZE; + reply.num_acl_pkts = ACL_PKT_NUM; + reply.max_sco_size = SCO_PKT_SIZE; + reply.num_sco_pkts = SCO_PKT_NUM; + + memcpy(packet + sizeof(SHCIEventCommand), &reply, sizeof(hci_read_buffer_size_rp)); + ctrl.SetRetVal(sizeof(SHCIEventCommand) + sizeof(hci_read_buffer_size_rp)); + EnqueueReply(ctrl.m_cmd_address); +} + void CWII_IPC_HLE_Device_usb_oh1_57e_305_real::FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, const u8 size) { diff --git a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h index 87a005a2be..2981896a39 100644 --- a/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h +++ b/Source/Core/Core/IPC_HLE/WII_IPC_HLE_Device_usb_bt_real.h @@ -64,7 +64,11 @@ private: Common::Flag m_thread_running; std::thread m_thread; + // Set when we received a command to read the buffer size, and we need to fake a reply + Common::Flag m_fake_read_buffer_size_reply; + void SendHCIResetCommand(); + void FakeReadBufferSizeReply(const CtrlBuffer& ctrl); void FakeSyncButtonEvent(const CtrlBuffer& ctrl, const u8* payload, u8 size); void FakeSyncButtonPressedEvent(const CtrlBuffer& ctrl); void FakeSyncButtonHeldEvent(const CtrlBuffer& ctrl);