WII_IPC_HLE/57e_305: Fake CommandReadBufferSize replies
Apparently, Nintendo's Bluetooth stack expects the ACL packet buffer size to be limited to 10. Reporting anything higher than that could cause memory corruption, which can result in warning messages in the logs ("event mismatch"), and more annoyingly, random disconnects. Thanks to shuffle2 for the fix!
This commit is contained in:
parent
4b47997cf8
commit
419a9c55e4
|
@ -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,
|
||||
|
|
|
@ -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:");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<CtrlMessage>(cmd_buffer);
|
||||
const u16 opcode = *reinterpret_cast<u16*>(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<u8>(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<CtrlBuffer>(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<SHCIEventCommand*>(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)
|
||||
{
|
||||
|
|
|
@ -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);
|
||||
|
|
Loading…
Reference in New Issue