My first commit :)

Fixed more memory leaks when doing state load. Now all file devices(handles) are stored in state, and this will fix some crash after loading state.

Warning: Do NOT Save/Load state before game title is shown and controllable, or else you will get a corrupt state.

If you encounter "Emu WiiMote Desync" frequently, please report the condition
(PS: To recover from wiimote desync, just load a saved state)

git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@4608 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
ayuanx 2009-11-24 17:10:38 +00:00
parent 6a46befc2a
commit 29774c35e8
9 changed files with 239 additions and 75 deletions

View File

@ -74,13 +74,48 @@ public:
(*ptr) += size; (*ptr) += size;
} }
// Store maps to file. Very useful.
template<class T> template<class T>
void Do(std::map<unsigned int, T> &x) { void Do(std::map<unsigned int, T> &x)
{
// TODO // TODO
PanicAlert("Do(map<>) does not yet work."); PanicAlert("Do(map<>) does not yet work.");
} }
void Do(std::map<unsigned int, std::string> &x)
{
unsigned int number = (unsigned int)x.size();
Do(number);
switch (mode) {
case MODE_READ:
{
x.clear();
while (number > 0)
{
unsigned int first;
Do(first);
std::string second;
Do(second);
x[first] = second;
--number;
}
}
break;
case MODE_WRITE:
case MODE_MEASURE:
{
std::map<unsigned int, std::string>::iterator itr = x.begin();
while (number > 0)
{
Do(itr->first);
Do(itr->second);
--number;
++itr;
}
}
break;
}
}
// Store vectors. // Store vectors.
template<class T> template<class T>
void Do(std::vector<T> &x) { void Do(std::vector<T> &x) {

View File

@ -74,6 +74,9 @@ typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
TDeviceMap g_DeviceMap; TDeviceMap g_DeviceMap;
// STATE_TO_SAVE // STATE_TO_SAVE
typedef std::map<u32, std::string> TFileNameMap;
TFileNameMap g_FileNameMap;
u32 g_LastDeviceID = 0x13370000; u32 g_LastDeviceID = 0x13370000;
std::string g_DefaultContentFile; std::string g_DefaultContentFile;
@ -85,8 +88,6 @@ void Init()
void Reset() void Reset()
{ {
// AyuanX: We really should save this to state or build the map and devices statically
// Mem dynamic allocation is too risky when doing state save/load
TDeviceMap::const_iterator itr = g_DeviceMap.begin(); TDeviceMap::const_iterator itr = g_DeviceMap.begin();
while (itr != g_DeviceMap.end()) while (itr != g_DeviceMap.end())
{ {
@ -95,6 +96,7 @@ void Reset()
++itr; ++itr;
} }
g_DeviceMap.clear(); g_DeviceMap.clear();
g_FileNameMap.clear();
} }
void Shutdown() void Shutdown()
@ -130,8 +132,6 @@ IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
return g_DeviceMap[_ID]; return g_DeviceMap[_ID];
// ID = 0 just means it hasn't been created yet // ID = 0 just means it hasn't been created yet
_dbg_assert_msg_(WII_IPC, _ID == 0, "IOP tries to access an unknown device 0x%x", _ID);
return NULL; return NULL;
} }
@ -231,7 +231,7 @@ IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName
// Let the game read the setting.txt file // Let the game read the setting.txt file
void CopySettingsFile(std::string DeviceName) void CopySettingsFile(std::string& DeviceName)
{ {
std::string Source = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP; std::string Source = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP;
if(Core::GetStartupParameter().bNTSC) if(Core::GetStartupParameter().bNTSC)
@ -259,14 +259,43 @@ void CopySettingsFile(std::string DeviceName)
void DoState(PointerWrap &p) void DoState(PointerWrap &p)
{ {
p.Do(g_LastDeviceID); p.Do(g_LastDeviceID);
//p.Do(g_DefaultContentFile); p.Do(g_DefaultContentFile);
// AyuanX: I think maybe we really should create devices statically at initilization // AyuanX: I think we should seperate hardware from file handle
// and create hardware at initilization instead of runtime allocation when first accessed
IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("/dev/usb/oh1/57e/305"))); IWII_IPC_HLE_Device* pDevice = AccessDeviceByID(GetDeviceIDByName(std::string("/dev/usb/oh1/57e/305")));
if (pDevice) if (pDevice)
pDevice->DoState(p); pDevice->DoState(p);
else else
PanicAlert("WII_IPC_HLE: Save/Load State failed, /dev/usb/oh1/57e/305 doesn't exist!"); PanicAlert("WII_IPC_HLE: Save/Load State failed, Device /dev/usb/oh1/57e/305 doesn't exist!");
// Let's just hope hardware device IDs are constant throughout the game
// If there is any ID overlapping between hardware IDs and file IDs, we are dead
if (p.GetMode() == PointerWrap::MODE_READ)
{
// Delete file Handles
TFileNameMap::const_iterator itr = g_FileNameMap.begin();
while (itr != g_FileNameMap.end())
{
delete g_DeviceMap[itr->first];
g_DeviceMap.erase(itr->first);
++itr;
}
// Load file names
p.Do(g_FileNameMap);
// Rebuild file handles
itr = g_FileNameMap.begin();
while (itr != g_FileNameMap.end())
{
g_DeviceMap[itr->first] = new CWII_IPC_HLE_Device_FileIO(itr->first, itr->second);
++itr;
}
}
else
{
p.Do(g_FileNameMap);
}
} }
void ExecuteCommand(u32 _Address) void ExecuteCommand(u32 _Address)
@ -307,15 +336,16 @@ void ExecuteCommand(u32 _Address)
g_LastDeviceID++; g_LastDeviceID++;
CmdSuccess = pDevice->Open(_Address, Mode); CmdSuccess = pDevice->Open(_Address, Mode);
if(pDevice->GetDeviceName().find("/dev/") == std::string::npos if(pDevice->GetDeviceName().find("/dev/") == std::string::npos)
|| pDevice->GetDeviceName().c_str() == std::string("/dev/fs")) // || pDevice->GetDeviceName().c_str() == std::string("/dev/fs"))
{ {
INFO_LOG(WII_IPC_FILEIO, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i, CmdSuccess=%i)", g_FileNameMap[CurrentDeviceID] = DeviceName;
INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, DeviceID=%08x, Mode=%i, CmdSuccess=%i)",
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode, (int)CmdSuccess); pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode, (int)CmdSuccess);
} }
else else
{ {
INFO_LOG(WII_IPC_HLE, "IOP: Open (Device=%s, DeviceID=%08x, Mode=%i)", INFO_LOG(WII_IPC_HLE, "IOP: Open Device (Device=%s, DeviceID=%08x, Mode=%i)",
pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode); pDevice->GetDeviceName().c_str(), CurrentDeviceID, Mode);
} }
} }
@ -438,7 +468,10 @@ void ExecuteCommand(u32 _Address)
ERROR_LOG(WII_IPC_HLE, "IOP: Reply to unknown device ID (DeviceID=%i)", DeviceID); ERROR_LOG(WII_IPC_HLE, "IOP: Reply to unknown device ID (DeviceID=%i)", DeviceID);
if (ClosedDeviceID > 0 && (ClosedDeviceID == DeviceID)) if (ClosedDeviceID > 0 && (ClosedDeviceID == DeviceID))
{
DeleteDeviceByID(DeviceID); DeleteDeviceByID(DeviceID);
g_FileNameMap.erase(DeviceID);
}
} }
} }
else else

View File

@ -20,6 +20,8 @@
#include "ChunkFile.h" #include "ChunkFile.h"
class IWII_IPC_HLE_Device;
namespace WII_IPC_HLE_Interface namespace WII_IPC_HLE_Interface
{ {
// Init // Init
@ -31,12 +33,24 @@ void Shutdown();
// Reset // Reset
void Reset(); void Reset();
void DeleteDeviceByID(u32 ID);
u32 GetDeviceIDByName(const std::string& _rDeviceName);
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID);
void DeleteDeviceByID(u32 _ID);
IWII_IPC_HLE_Device* CreateDevice(u32 _DeviceID, const std::string& _rDeviceName);
// Do State // Do State
void DoState(PointerWrap &p); void DoState(PointerWrap &p);
// Set default content file // Set default content file
void SetDefaultContentFile(const std::string& _rFilename); void SetDefaultContentFile(const std::string& _rFilename);
void CopySettingsFile(std::string& DeviceName);
// Update // Update
void Update(); void Update();

View File

@ -411,6 +411,14 @@ u32 CWII_IPC_HLE_Device_di::ExecuteCommand(u32 _BufferIn, u32 _BufferInSize, u32
ERROR_LOG(WII_IPC_DVD, "DVDLowAudioBufferConfig"); ERROR_LOG(WII_IPC_DVD, "DVDLowAudioBufferConfig");
break; break;
// New Super Mario Bros.Wii sends these cmds
// but it seems we don't need to implement anything
case 0x95:
case 0x96:
WARN_LOG(WII_IPC_DVD, "unimplemented cmd 0x%08x (Buffer 0x%08x, 0x%x)",
Command, _BufferOut, _BufferOutSize);
break;
default: default:
ERROR_LOG(WII_IPC_DVD, "unknown cmd 0x%08x (Buffer 0x%08x, 0x%x)", ERROR_LOG(WII_IPC_DVD, "unknown cmd 0x%08x (Buffer 0x%08x, 0x%x)",
Command, _BufferOut, _BufferOutSize); Command, _BufferOut, _BufferOutSize);

View File

@ -38,8 +38,9 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De
, m_HostNumACLPackets(0) , m_HostNumACLPackets(0)
, m_HostNumSCOPackets(0) , m_HostNumSCOPackets(0)
, m_HCIBuffer(NULL) , m_HCIBuffer(NULL)
, m_HCIPool(0)
, m_ACLBuffer(NULL) , m_ACLBuffer(NULL)
, m_ACLFrame(0) , m_ACLPool(0)
, m_LastCmd(NULL) , m_LastCmd(NULL)
, m_PacketCount(0) , m_PacketCount(0)
{ {
@ -63,7 +64,9 @@ CWII_IPC_HLE_Device_usb_oh1_57e_305::CWII_IPC_HLE_Device_usb_oh1_57e_305(u32 _De
} }
CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305() CWII_IPC_HLE_Device_usb_oh1_57e_305::~CWII_IPC_HLE_Device_usb_oh1_57e_305()
{} {
m_WiiMotes.clear();
}
void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p) void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
{ {
@ -71,8 +74,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::DoState(PointerWrap &p)
p.Do(m_PacketCount); p.Do(m_PacketCount);
p.Do(m_CtrlSetup); p.Do(m_CtrlSetup);
p.Do(m_HCIBuffer); p.Do(m_HCIBuffer);
p.Do(m_HCIPool);
p.Do(m_ACLBuffer); p.Do(m_ACLBuffer);
p.Do(m_ACLFrame); p.Do(m_ACLPool);
} }
// =================================================== // ===================================================
@ -138,7 +142,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress)
// check termination // check termination
_dbg_assert_msg_(WII_IPC_WIIMOTE, *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[5].m_Address) == 0, _dbg_assert_msg_(WII_IPC_WIIMOTE, *(u8*)Memory::GetPointer(CommandBuffer.InBuffer[5].m_Address) == 0,
"WIIMOTE: Termination != 0"); "WIIMOTE: Termination != 0");
#if defined(_DEBUG) || defined(DEBUGFAST)
DEBUG_LOG(WII_IPC_WIIMOTE, "USB_IOCTL_CTRLMSG (0x%08x) - execute command", _CommandAddress); DEBUG_LOG(WII_IPC_WIIMOTE, "USB_IOCTL_CTRLMSG (0x%08x) - execute command", _CommandAddress);
DEBUG_LOG(WII_IPC_WIIMOTE, " bRequestType: 0x%x", m_CtrlSetup.bRequestType); DEBUG_LOG(WII_IPC_WIIMOTE, " bRequestType: 0x%x", m_CtrlSetup.bRequestType);
DEBUG_LOG(WII_IPC_WIIMOTE, " bRequest: 0x%x", m_CtrlSetup.bRequest); DEBUG_LOG(WII_IPC_WIIMOTE, " bRequest: 0x%x", m_CtrlSetup.bRequest);
@ -147,6 +151,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress)
DEBUG_LOG(WII_IPC_WIIMOTE, " wLength: 0x%x", m_CtrlSetup.wLength); DEBUG_LOG(WII_IPC_WIIMOTE, " wLength: 0x%x", m_CtrlSetup.wLength);
DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadAddr: 0x%x", m_CtrlSetup.m_PayLoadAddr); DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadAddr: 0x%x", m_CtrlSetup.m_PayLoadAddr);
DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadSize: 0x%x", m_CtrlSetup.m_PayLoadSize); DEBUG_LOG(WII_IPC_WIIMOTE, " m_PayLoadSize: 0x%x", m_CtrlSetup.m_PayLoadSize);
#endif
ExecuteHCICommandMessage(m_CtrlSetup); ExecuteHCICommandMessage(m_CtrlSetup);
// Replies are generated inside // Replies are generated inside
@ -177,9 +182,9 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress)
SendToDevice(pACLHeader->ConnectionHandle, Memory::GetPointer(BulkBuffer.m_buffer + 4), pACLHeader->Size); SendToDevice(pACLHeader->ConnectionHandle, Memory::GetPointer(BulkBuffer.m_buffer + 4), pACLHeader->Size);
m_PacketCount++; m_PacketCount++;
// If ACLFrame is not used, we can send a reply immediately // If ACLPool is not used, we can send a reply immediately
// or else we have to delay this reply // or else we have to delay this reply
if (m_ACLFrame.m_number == 0) if (m_ACLPool.m_number == 0)
_SendReply = true; _SendReply = true;
} }
break; break;
@ -279,10 +284,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
// The header is for example 07 00 41 00 which means size 0x0007 and channel 0x0041. // 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 // AyuanX: Basically, our WII_IPC_HLE is efficient enough to send the packet immediately
// rather than enqueue it to some other memory // rather than enqueue it to some other memory
// But...the only exception is the Wiimote_Plugin // But...the only exception comes from the Wiimote_Plugin
// //
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)
{ {
@ -308,48 +312,49 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u
// Invalidate ACL buffer // Invalidate ACL buffer
m_ACLBuffer.m_address = NULL; m_ACLBuffer.m_address = NULL;
m_ACLBuffer.m_buffer = NULL; m_ACLBuffer.m_buffer = NULL;
m_ACLFrame.m_number = 0; }
else if ((sizeof(UACLHeader) + _Size) > 64 )
{
ERROR_LOG(WII_IPC_HLE, "ACL Packet size is too big! (>64B)");
PanicAlert("WII_IPC_HLE: ACL Packet size is too big! (>64B)");
}
else if (m_ACLPool.m_number >= 16)
{
ERROR_LOG(WII_IPC_HLE, "ACL Pool is full, something must be wrong!");
PanicAlert("WII_IPC_HLE: ACL Pool is full, something must be wrong!");
} }
else else
{ {
// Actually this temp storage is not quite necessary UACLHeader* pHeader = (UACLHeader*)(m_ACLPool.m_data + m_ACLPool.m_number * 64); // I belive 64B is enough
// the whole WII_IPC (HLE+USB+BT) won't need it
// but current implementation of WiiMote_Plugin has ruined everything
// although I can fix the Eme_WiiMote but that requires a little change of the plugin spec
// so unless somebody who works on the Real_WiiMote agrees, I won't do that
//
UACLHeader* pHeader = (UACLHeader*)(m_ACLFrame.m_data + m_ACLFrame.m_number * 64); // I belive 64B is enough
pHeader->ConnectionHandle = _ConnectionHandle; pHeader->ConnectionHandle = _ConnectionHandle;
pHeader->BCFlag = 0; pHeader->BCFlag = 0;
pHeader->PBFlag = 2; pHeader->PBFlag = 2;
pHeader->Size = _Size; pHeader->Size = _Size;
memcpy((u8*)pHeader + sizeof(UACLHeader), _pData, _Size); memcpy((u8*)pHeader + sizeof(UACLHeader), _pData, _Size);
m_ACLFrame.m_number++; m_ACLPool.m_number++;
if (m_ACLFrame.m_number > 16)
{
ERROR_LOG(WII_IPC_WIIMOTE, "ACL Frame is full, something must be wrong!");
PanicAlert("WII_IPC_WIIMOTE: ACL Frame is full, something must be wrong!");
}
} }
} }
// AyuanX: this ugly function is only useful when there are // The normal hardware behavior is like this:
// multiple L2CAP packets come from WiiMote_Plugin in one cycle // e.g. if you have 3 packets to send you have to send them one by one in 3 cycles
// and this is the mechanism how our IPC works
// but current implementation of WiiMote_Plugin doesn't comply with this rule
// It acts like sending all the 3 packets in one cycle and idling around in the other two cycles
// that's why we need this contingent ACL pool
// //
void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeACLFrame() void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeACLPool()
{ {
if(m_ACLBuffer.m_address == NULL) if(m_ACLBuffer.m_address == NULL)
return; return;
INFO_LOG(WII_IPC_WIIMOTE, "Purging ACL Frame: 0x%08x ....", m_ACLBuffer.m_address); INFO_LOG(WII_IPC_WIIMOTE, "Purging ACL Pool: 0x%08x ....", m_ACLBuffer.m_address);
if(m_ACLFrame.m_number > 0) if(m_ACLPool.m_number > 0)
{ {
m_ACLFrame.m_number--; m_ACLPool.m_number--;
// Fill the buffer // Fill the buffer
u8* _Address = m_ACLFrame.m_data + m_ACLFrame.m_number * 64; u8* _Address = m_ACLPool.m_data + m_ACLPool.m_number * 64;
memcpy(Memory::GetPointer(m_ACLBuffer.m_buffer), _Address, 64); memcpy(Memory::GetPointer(m_ACLBuffer.m_buffer), _Address, 64);
// Write the packet size as return value // Write the packet size as return value
Memory::Write_U32(sizeof(UACLHeader) + ((UACLHeader*)_Address)->Size, m_ACLBuffer.m_address + 0x4); Memory::Write_U32(sizeof(UACLHeader) + ((UACLHeader*)_Address)->Size, m_ACLBuffer.m_address + 0x4);
@ -366,6 +371,15 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeACLFrame()
// ---------------- // ----------------
u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update() u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
{ {
// Check if HCI Pool is not purged
if (m_HCIPool.m_number > 0)
{
PurgeHCIPool();
if (m_HCIPool.m_number == 0)
WII_IPCInterface::EnqReply(m_CtrlSetup.m_Address);
return true;
}
// Check if last command needs more work // Check if last command needs more work
if (m_HCIBuffer.m_address && m_LastCmd) if (m_HCIBuffer.m_address && m_LastCmd)
{ {
@ -373,11 +387,11 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
return true; return true;
} }
// Check if temp ACL frame is not purged // Check if ACL Pool is not purged
if (m_ACLFrame.m_number > 0) if (m_ACLPool.m_number > 0)
{ {
PurgeACLFrame(); PurgeACLPool();
if (m_ACLFrame.m_number == 0) if (m_ACLPool.m_number == 0)
WII_IPCInterface::EnqReply(m_CtrlSetup.m_Address); WII_IPCInterface::EnqReply(m_CtrlSetup.m_Address);
return true; return true;
} }
@ -427,14 +441,15 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
} }
} }
// AyuanX: This event should be sent periodically or WiiMote will desync automatically // AyuanX: This event should be sent periodically after ACL connection is accepted
// but not too many or it will jam the bus and cost extra CPU time // or CPU will disconnect WiiMote automatically
// but don't send too many or it will jam the bus and cost extra CPU time
// //
static u32 FreqDividerSync = 0; static u32 FreqDividerSync = 0;
if (m_HCIBuffer.m_address && !WII_IPCInterface::GetAddress() && m_WiiMotes[0].IsLinked()) if (m_HCIBuffer.m_address && !WII_IPCInterface::GetAddress() && m_WiiMotes[0].IsConnected())
{ {
FreqDividerSync++; FreqDividerSync++;
if ((m_PacketCount >0) || (FreqDividerSync > 15)) // Feel free to tweak it if ((m_PacketCount > 0) || (FreqDividerSync > 30)) // Feel free to tweak it
{ {
FreqDividerSync = 0; FreqDividerSync = 0;
SendEventNumberOfCompletedPackets(m_WiiMotes[0].GetConnectionHandle(), m_PacketCount); SendEventNumberOfCompletedPackets(m_WiiMotes[0].GetConnectionHandle(), m_PacketCount);
@ -453,7 +468,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
if (m_ACLBuffer.m_address && !WII_IPCInterface::GetAddress() && !m_LastCmd && m_WiiMotes[0].IsLinked()) if (m_ACLBuffer.m_address && !WII_IPCInterface::GetAddress() && !m_LastCmd && m_WiiMotes[0].IsLinked())
{ {
FreqDividerMote++; FreqDividerMote++;
if(FreqDividerMote > 100) // Feel free to tweak it if(FreqDividerMote > 99) // Feel free to tweak it
{ {
FreqDividerMote = 0; FreqDividerMote = 0;
CPluginManager::GetInstance().GetWiimote(0)->Wiimote_Update(); CPluginManager::GetInstance().GetWiimote(0)->Wiimote_Update();
@ -474,6 +489,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
// Our WII_IPC_HLE is so efficient that we could fill the buffer immediately // Our WII_IPC_HLE is so efficient that we could fill the buffer immediately
// rather than enqueue it to some other memory and this will do good for StateSave // rather than enqueue it to some other memory and this will do good for StateSave
//
void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _event) void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _event)
{ {
if (m_HCIBuffer.m_address != NULL) if (m_HCIBuffer.m_address != NULL)
@ -491,16 +507,54 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
// Invalidate HCI buffer // Invalidate HCI buffer
m_HCIBuffer.m_address = NULL; m_HCIBuffer.m_address = NULL;
m_HCIBuffer.m_buffer = NULL; m_HCIBuffer.m_buffer = NULL;
}
return; else if (_event.m_size > 64)
{
ERROR_LOG(WII_IPC_HLE, "HCI Packet size too big! (>64B)");
PanicAlert("WII_IPC_HLE: HCI Packet size too big! (>64B)");
}
else if (m_HCIPool.m_number >= 16)
{
ERROR_LOG(WII_IPC_HLE, "HCI Pool is full, something must be wrong!");
PanicAlert("WII_IPC_HLE: HCI Pool is full, something must be wrong!");
} }
else else
{ {
ERROR_LOG(WII_IPC_WIIMOTE, "Sending HCI Packet failed, HCI Buffer is invald!"); memcpy(m_HCIPool.m_data + m_HCIPool.m_number * 64, _event.m_buffer, _event.m_size);
PanicAlert("WII_IPC_HLE_DEVICE_USB: Sending HCI Packet failed, HCI Buffer is invald!"); // HCI Packet doesn't contain size info inside, so we have to store it somewhere
m_HCIPool.m_size[m_HCIPool.m_number] = _event.m_size;
m_HCIPool.m_number++;
} }
} }
// Generally, CPU should send us a valid HCI buffer before issuing any HCI command
// but since we don't know the exact frequency at which IPC should be running
// so when IPC is running too fast that CPU can't catch up
// then CPU(actually it is the usb driver) sometimes throws out a command before sending us a HCI buffer
// So I put this contingent HCI Pool here until we figure out the true reason
//
void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeHCIPool()
{
if(m_HCIBuffer.m_address == NULL)
return;
INFO_LOG(WII_IPC_WIIMOTE, "Purging HCI Pool: 0x%08x ....", m_HCIBuffer.m_address);
if(m_HCIPool.m_number > 0)
{
m_HCIPool.m_number--;
// Fill the buffer
u8* _Address = m_HCIPool.m_data + m_HCIPool.m_number * 64;
memcpy(Memory::GetPointer(m_HCIBuffer.m_buffer), _Address, 64);
// Write the packet size as return value
Memory::Write_U32(m_HCIPool.m_size[m_HCIPool.m_number], m_HCIBuffer.m_address + 0x4);
// Send a reply to indicate ACL buffer is sent
WII_IPCInterface::EnqReply(m_HCIBuffer.m_address);
// Invalidate ACL buffer
m_HCIBuffer.m_address = NULL;
m_HCIBuffer.m_buffer = NULL;
}
}
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandStatus(u16 _Opcode) bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventCommandStatus(u16 _Opcode)
{ {
@ -744,7 +798,10 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventLinkKeyNotification(const CWI
DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x", DEBUG_LOG(WII_IPC_WIIMOTE, " bd: %02x:%02x:%02x:%02x:%02x:%02x",
pEventLinkKey->bdaddr.b[0], pEventLinkKey->bdaddr.b[1], pEventLinkKey->bdaddr.b[2], pEventLinkKey->bdaddr.b[0], pEventLinkKey->bdaddr.b[1], pEventLinkKey->bdaddr.b[2],
pEventLinkKey->bdaddr.b[3], pEventLinkKey->bdaddr.b[4], pEventLinkKey->bdaddr.b[5]); pEventLinkKey->bdaddr.b[3], pEventLinkKey->bdaddr.b[4], pEventLinkKey->bdaddr.b[5]);
#if MAX_LOGLEVEL >= DEBUG_LEVEL
LOG_LinkKey(pEventLinkKey->LinkKey); LOG_LinkKey(pEventLinkKey->LinkKey);
#endif
return true; return true;
}; };
@ -1247,9 +1304,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom
break; break;
} }
if (m_LastCmd == NULL) if ((m_LastCmd == NULL) && (m_HCIPool.m_number == 0))
{ {
// HCI command finished, send a reply to command // If HCI command is finished and HCI pool is empty, send a reply to command
WII_IPCInterface::EnqReply(_rHCICommandMessage.m_Address); WII_IPCInterface::EnqReply(_rHCICommandMessage.m_Address);
} }
} }
@ -1900,6 +1957,9 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::CommandDisconnect(u8* _Input)
CWII_IPC_HLE_WiiMote* pWiimote = AccessWiiMote(pDiscon->con_handle); CWII_IPC_HLE_WiiMote* pWiimote = AccessWiiMote(pDiscon->con_handle);
if (pWiimote) if (pWiimote)
pWiimote->EventDisconnect(); pWiimote->EventDisconnect();
// Here we should enable scan so reconnect is possible
m_ScanEnable = 0x2;
*/ */
static bool OneShotMessage = true; static bool OneShotMessage = true;

View File

@ -73,7 +73,8 @@ public:
virtual u32 Update(); virtual u32 Update();
void SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size); void SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size);
void PurgeACLFrame(); void PurgeACLPool();
void PurgeHCIPool();
//hack for wiimote plugin //hack for wiimote plugin
@ -120,12 +121,24 @@ private:
u32 m_Address; u32 m_Address;
}; };
struct ACLFrame struct ACLPool
{ {
u32 m_number; u32 m_number;
u8 m_data[1024]; u8 m_data[1024]; // Capacity: 64B x 16
ACLFrame(int num) ACLPool(int num)
: m_number(num)
{
}
};
struct HCIPool
{
u32 m_number;
u8 m_data[1024]; // Capacity: 64B x 16
u8 m_size[16];
HCIPool(int num)
: m_number(num) : m_number(num)
{ {
} }
@ -171,8 +184,9 @@ private:
// STATE_TO_SAVE // STATE_TO_SAVE
SHCICommandMessage m_CtrlSetup; SHCICommandMessage m_CtrlSetup;
CtrlBuffer m_HCIBuffer; CtrlBuffer m_HCIBuffer;
HCIPool m_HCIPool;
CtrlBuffer m_ACLBuffer; CtrlBuffer m_ACLBuffer;
ACLFrame m_ACLFrame; ACLPool m_ACLPool;
u32 m_LastCmd; u32 m_LastCmd;
int m_PacketCount; int m_PacketCount;

View File

@ -323,7 +323,7 @@ u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
0x00, // Minus 0x00, // Minus
0x36, // Period 0x36, // Period
0x37, // '/' 0x37, // '/'
0x34, // 'љ' 0x34, // ' '
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@ -331,7 +331,7 @@ u8 CWII_IPC_HLE_Device_usb_kbd::m_KeyCodesAZERTY[256] = {
0x2D, // ')' 0x2D, // ')'
0x32, // '\' 0x32, // '\'
0x2F, // '^' 0x2F, // '^'
0x00, // 'В' 0x00, // ' '
0x38, // '!' 0x38, // '!'
0x00, // Nothing interesting past this point. 0x00, // Nothing interesting past this point.

View File

@ -64,7 +64,7 @@ void TiltTest(u8 x, u8 y, u8 z)
/* Angles adjustment for the upside down state when both roll and pitch is /* Angles adjustment for the upside down state when both roll and pitch is
used. When the absolute values of the angles go over 90° the Wiimote is used. When the absolute values of the angles go over 90 the Wiimote is
upside down and these adjustments are needed. */ upside down and these adjustments are needed. */
void AdjustAngles(float &Roll, float &Pitch) void AdjustAngles(float &Roll, float &Pitch)
{ {

View File

@ -432,7 +432,7 @@ void SingleShake(u8 &_y, u8 &_z, int i)
/* Tilting Wiimote with gamepad. We can guess that the game will calculate a /* Tilting Wiimote with gamepad. We can guess that the game will calculate a
Wiimote pitch and use it as a measure of the tilting of the Wiimote. We are Wiimote pitch and use it as a measure of the tilting of the Wiimote. We are
interested in this tilting range 90?to -90?*/ interested in this tilting range 90 to -90*/
void TiltWiimoteGamepad(float &Roll, float &Pitch) void TiltWiimoteGamepad(float &Roll, float &Pitch)
{ {
// Return if we have no pads // Return if we have no pads
@ -456,7 +456,7 @@ void TiltWiimoteGamepad(float &Roll, float &Pitch)
float Tl = (float)_Tl; float Tl = (float)_Tl;
float Tr = (float)_Tr; float Tr = (float)_Tr;
// Save the Range in degrees, 45?and 90?are good values in some games // Save the Range in degrees, 45 and 90 are good values in some games
float RollRange = (float)g_Config.Trigger.Range.Roll; float RollRange = (float)g_Config.Trigger.Range.Roll;
float PitchRange = (float)g_Config.Trigger.Range.Pitch; float PitchRange = (float)g_Config.Trigger.Range.Pitch;