Workaround ACL overflow issues by not dropping packets until buffer reaches size of 100.
It seems to work without causing input delays or anything bad.
This commit is contained in:
parent
e199d21513
commit
e4588e2dfc
|
@ -336,23 +336,23 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
|
||||||
pWiiMote->ExecuteL2capCmd(_pData, _Size);
|
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)
|
void CWII_IPC_HLE_Device_usb_oh1_57e_305::IncDataPacket(u16 _ConnectionHandle)
|
||||||
{
|
{
|
||||||
m_PacketCount[_ConnectionHandle & 0xff]++;
|
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)
|
if (m_PacketCount[_ConnectionHandle & 0xff] > (unsigned int)m_acl_pkts_num)
|
||||||
{
|
{
|
||||||
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow");
|
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL buffer overflow");
|
||||||
m_PacketCount[_ConnectionHandle & 0xff] = m_acl_pkts_num;
|
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)
|
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);
|
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
|
else
|
||||||
{
|
{
|
||||||
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, "
|
DEBUG_LOG(WII_IPC_WIIMOTE, "ACL endpoint not currently valid, queueing...");
|
||||||
"queueing(%d)...", m_acl_pool.GetWritePos());
|
|
||||||
m_acl_pool.Store(_pData, _Size, _ConnectionHandle);
|
m_acl_pool.Store(_pData, _Size, _ConnectionHandle);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -518,25 +517,51 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
||||||
return packet_transferred;
|
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)
|
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;
|
auto& packet = m_queue.front();
|
||||||
const u16 size = m_info[m_read_ptr].size;
|
|
||||||
const u16 conn_handle = m_info[m_read_ptr].conn_handle;
|
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 "
|
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);
|
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->con_handle = HCI_MK_CON_HANDLE(conn_handle, HCI_PACKET_START, HCI_POINT2POINT);
|
||||||
pHeader->length = size;
|
pHeader->length = size;
|
||||||
|
|
||||||
// Write the packet to the buffer
|
// 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);
|
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);
|
WII_IPC_HLE_Interface::EnqReply(endpoint.m_address);
|
||||||
endpoint.Invalidate();
|
endpoint.Invalidate();
|
||||||
|
|
|
@ -17,9 +17,11 @@
|
||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "hci.h"
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <queue>
|
#include <queue>
|
||||||
|
|
||||||
|
#include "hci.h"
|
||||||
#include "WII_IPC_HLE.h"
|
#include "WII_IPC_HLE.h"
|
||||||
#include "WII_IPC_HLE_Device.h"
|
#include "WII_IPC_HLE_Device.h"
|
||||||
#include "WII_IPC_HLE_WiiMote.h"
|
#include "WII_IPC_HLE_WiiMote.h"
|
||||||
|
@ -168,70 +170,33 @@ private:
|
||||||
|
|
||||||
class ACLPool
|
class ACLPool
|
||||||
{
|
{
|
||||||
u8 m_pool[m_acl_pkt_size * m_acl_pkts_num];
|
struct Packet
|
||||||
int m_read_ptr;
|
|
||||||
int m_write_ptr;
|
|
||||||
|
|
||||||
struct
|
|
||||||
{
|
{
|
||||||
|
u8 data[m_acl_pkt_size];
|
||||||
u16 size;
|
u16 size;
|
||||||
u16 conn_handle;
|
u16 conn_handle;
|
||||||
} m_info[m_acl_pkts_num];
|
};
|
||||||
|
|
||||||
|
std::deque<Packet> m_queue;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
ACLPool()
|
ACLPool()
|
||||||
: m_read_ptr(0)
|
: m_queue()
|
||||||
, m_write_ptr(0)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
void Store(const u8* data, const u16 size, const u16 conn_handle)
|
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 WriteToEndpoint(CtrlBuffer& endpoint);
|
void WriteToEndpoint(CtrlBuffer& endpoint);
|
||||||
|
|
||||||
bool IsEmpty() const
|
bool IsEmpty() const
|
||||||
{
|
{
|
||||||
return m_write_ptr == m_read_ptr;
|
return m_queue.empty();
|
||||||
}
|
|
||||||
|
|
||||||
int GetWritePos() const
|
|
||||||
{
|
|
||||||
return m_write_ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
int GetReadPos() const
|
|
||||||
{
|
|
||||||
return m_read_ptr;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// For SaveStates
|
// For SaveStates
|
||||||
void DoState(PointerWrap &p)
|
void DoState(PointerWrap &p)
|
||||||
{
|
{
|
||||||
p.Do(m_write_ptr);
|
p.Do(m_queue);
|
||||||
p.Do(m_read_ptr);
|
|
||||||
p.DoArray((u8 *)m_pool, sizeof(m_pool));
|
|
||||||
p.DoArray((u8 *)m_info, sizeof(m_info));
|
|
||||||
}
|
}
|
||||||
} m_acl_pool;
|
} m_acl_pool;
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue