diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp index 33474af8c7..050cfe66eb 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.cpp @@ -336,23 +336,23 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8 pWiiMote->ExecuteL2capCmd(_pData, _Size); } -// Here we send ACL packets to CPU. They will consist of header + data. -// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041. -// --------------------------------------------------- -// AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately -// rather than enqueue it to some other memory -// But...the only exception comes from the Wiimote_Plugin void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle) { m_PacketCount[_ConnectionHandle & 0xff]++; + // I don't think this makes sense or should be necessary + // m_PacketCount refers to "completed" packets and is not related to some buffer size, yes? +#if 0 if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num) { DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow"); m_PacketCount[_ConnectionHandle & 0xff] = m_acl_pkts_num; } +#endif } +// Here we send ACL packets to CPU. They will consist of header + data. +// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041. void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size) { DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet from %x ready to send to stack...", _ConnectionHandle); @@ -374,8 +374,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u } else { - DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, " - "queueing(%d)...", m_acl_pool.GetWritePos()); + DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queueing..."); m_acl_pool.Store(_pData, _Size, _ConnectionHandle); } } @@ -518,25 +517,51 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() return packet_transferred; } +void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::Store(const u8* data, const u16 size, const u16 conn_handle) +{ + if (m_queue.size() >= 100) + { + // Many simultaneous exchanges of ACL packets tend to cause the + // queue to fill up. Typically, this occurs when + // many emulated Wiimotes are requesting connections at once. + // See issue 4608 for more info. + ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue size reached 100 - current packet will be " + "dropped! (Hopefully you never see this.)"); + return; + } + + _dbg_assert_msg_(WII_IPC_WIIMOTE, + size < m_acl_pkt_size, "acl packet too large for pool"); + + m_queue.push_back(Packet()); + auto& packet = m_queue.back(); + + std::copy_n(data, size, packet.data); + packet.size = size; + packet.conn_handle = conn_handle; +} + void CWII_IPC_HLE_Device_usb_oh1_57e_305::ACLPool::WriteToEndpoint(CtrlBuffer& endpoint) { - const u8 *data = m_pool + m_acl_pkt_size * m_read_ptr; - const u16 size = m_info[m_read_ptr].size; - const u16 conn_handle = m_info[m_read_ptr].conn_handle; + auto& packet = m_queue.front(); + + const u8* const data = packet.data; + const u16 size = packet.size; + const u16 conn_handle = packet.conn_handle; DEBUG_LOG(WII_IPC_WIIMOTE, "ACL packet being written from " - "queue(%d) to %08x", GetReadPos(), endpoint.m_address); + "queue to %08x", endpoint.m_address); hci_acldata_hdr_t* pHeader = (hci_acldata_hdr_t*)Memory::GetPointer(endpoint.m_buffer); pHeader->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT); pHeader->length = size; // Write the packet to the buffer - memcpy((u8*)pHeader + sizeof(hci_acldata_hdr_t), data, pHeader->length); + std::copy_n(data, pHeader->length, (u8*)pHeader + sizeof(hci_acldata_hdr_t)); endpoint.SetRetVal(sizeof(hci_acldata_hdr_t) + size); - m_read_ptr = (m_read_ptr + 1) % m_acl_pkts_num; + m_queue.pop_front(); WII_IPC_HLE_Interface::EnqReply(endpoint.m_address); endpoint.Invalidate(); diff --git a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h index 61c439a7ec..eb091b1ff9 100644 --- a/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h +++ b/Source/Core/Core/Src/IPC_HLE/WII_IPC_HLE_Device_usb.h @@ -17,9 +17,11 @@ #pragma once -#include "hci.h" +#include #include #include + +#include "hci.h" #include "WII_IPC_HLE.h" #include "WII_IPC_HLE_Device.h" #include "WII_IPC_HLE_WiiMote.h" @@ -168,70 +170,33 @@ private: class ACLPool { - u8 m_pool[m_acl_pkt_size * m_acl_pkts_num]; - int m_read_ptr; - int m_write_ptr; - - struct + struct Packet { + u8 data[m_acl_pkt_size]; u16 size; u16 conn_handle; - } m_info[m_acl_pkts_num]; + }; + + std::deque m_queue; public: ACLPool() - : m_read_ptr(0) - , m_write_ptr(0) + : m_queue() {} - void Store(const u8* data, const u16 size, const u16 conn_handle) - { - _dbg_assert_msg_(WII_IPC_WIIMOTE, - size < m_acl_pkt_size, "acl packet too large for pool"); - - const int next_write_ptr = (m_write_ptr + 1) % m_acl_pkts_num; - if (next_write_ptr == m_read_ptr) - { - // Many simultaneous exchanges of ACL packets tend to cause the - // 10-packet limit to be exceeded. Typically, this occurs when - // many emulated Wiimotes are requesting connections at once. - // See issue 4608 for more info. - ERROR_LOG(WII_IPC_WIIMOTE, "ACL queue is full - current packet will be " - "dropped! (m_write_ptr(%d) was about to overlap m_read_ptr(%d))", - m_write_ptr, m_read_ptr); - return; - } - - memcpy(m_pool + m_acl_pkt_size * m_write_ptr, data, size); - m_info[m_write_ptr].size = size; - m_info[m_write_ptr].conn_handle = conn_handle; - m_write_ptr = next_write_ptr; - } + void Store(const u8* data, const u16 size, const u16 conn_handle); void WriteToEndpoint(CtrlBuffer& endpoint); bool IsEmpty() const { - return m_write_ptr == m_read_ptr; - } - - int GetWritePos() const - { - return m_write_ptr; - } - - int GetReadPos() const - { - return m_read_ptr; + return m_queue.empty(); } // For SaveStates void DoState(PointerWrap &p) { - p.Do(m_write_ptr); - p.Do(m_read_ptr); - p.DoArray((u8 *)m_pool, sizeof(m_pool)); - p.DoArray((u8 *)m_info, sizeof(m_info)); + p.Do(m_queue); } } m_acl_pool;