make WII_IPC_HLEInterface manage the IPC message queue instead of the "lle" portion.
git-svn-id: https://dolphin-emu.googlecode.com/svn/trunk@5224 8ced0084-cf51-0410-be5f-012b33b47a6e
This commit is contained in:
parent
cf7101ef08
commit
f6db5b7d8d
|
@ -16,6 +16,8 @@
|
|||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
#include <map>
|
||||
#include <queue>
|
||||
#include <vector>
|
||||
|
||||
#include "Common.h"
|
||||
#include "ChunkFile.h"
|
||||
|
@ -91,23 +93,16 @@ struct CtrlRegister
|
|||
};
|
||||
|
||||
// STATE_TO_SAVE
|
||||
u32 ppc_msg;
|
||||
u32 arm_msg;
|
||||
CtrlRegister ctrl;
|
||||
static u32 ppc_msg;
|
||||
static u32 arm_msg;
|
||||
static CtrlRegister ctrl;
|
||||
|
||||
u32 ppc_irq_flags;
|
||||
u32 ppc_irq_masks;
|
||||
u32 arm_irq_flags;
|
||||
u32 arm_irq_masks;
|
||||
static u32 ppc_irq_flags;
|
||||
static u32 ppc_irq_masks;
|
||||
static u32 arm_irq_flags;
|
||||
static u32 arm_irq_masks;
|
||||
|
||||
u32 sensorbar_power; // do we need to care about this?
|
||||
|
||||
// not actual registers:
|
||||
bool cmd_active;
|
||||
u32 g_ReplyHead;
|
||||
u32 g_ReplyTail;
|
||||
u32 g_ReplyNum;
|
||||
u32 g_ReplyFifo[REPLY_FIFO_DEPTH];
|
||||
static u32 sensorbar_power; // do we need to care about this?
|
||||
|
||||
void DoState(PointerWrap &p)
|
||||
{
|
||||
|
@ -119,17 +114,10 @@ void DoState(PointerWrap &p)
|
|||
p.Do(arm_irq_flags);
|
||||
p.Do(arm_irq_masks);
|
||||
p.Do(sensorbar_power);
|
||||
p.Do(cmd_active);
|
||||
p.Do(g_ReplyHead);
|
||||
p.Do(g_ReplyTail);
|
||||
p.Do(g_ReplyNum);
|
||||
p.DoArray(g_ReplyFifo, REPLY_FIFO_DEPTH);
|
||||
}
|
||||
|
||||
// Init
|
||||
void Init()
|
||||
{
|
||||
cmd_active = false;
|
||||
ctrl = CtrlRegister();
|
||||
ppc_msg =
|
||||
arm_msg =
|
||||
|
@ -139,12 +127,7 @@ void Init()
|
|||
arm_irq_flags =
|
||||
arm_irq_masks =
|
||||
|
||||
sensorbar_power =
|
||||
|
||||
g_ReplyHead =
|
||||
g_ReplyTail =
|
||||
g_ReplyNum = 0;
|
||||
memset(g_ReplyFifo, 0, REPLY_FIFO_DEPTH);
|
||||
sensorbar_power = 0;
|
||||
|
||||
ppc_irq_masks |= INT_CAUSE_IPC_BROADWAY;
|
||||
}
|
||||
|
@ -166,7 +149,7 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
|||
{
|
||||
case IPC_PPCCTRL:
|
||||
_rReturnValue = ctrl.ppc();
|
||||
INFO_LOG(WII_IPC, "r32 IPC_PPCCTRL %03x [R:%i A:%i E:%i]",
|
||||
DEBUG_LOG(WII_IPC, "r32 IPC_PPCCTRL %03x [R:%i A:%i E:%i]",
|
||||
ctrl.ppc(), ctrl.Y1, ctrl.Y2, ctrl.X1);
|
||||
|
||||
// if ((REASON_REG & 0x14) == 0x14) CALL IPCReplayHandler
|
||||
|
@ -175,7 +158,7 @@ void Read32(u32& _rReturnValue, const u32 _Address)
|
|||
|
||||
case IPC_ARMMSG: // looks a little bit like a callback function
|
||||
_rReturnValue = arm_msg;
|
||||
INFO_LOG(WII_IPC, "r32 IPC_ARMMSG %08x ", _rReturnValue);
|
||||
DEBUG_LOG(WII_IPC, "r32 IPC_ARMMSG %08x ", _rReturnValue);
|
||||
break;
|
||||
|
||||
case GPIOB_OUT:
|
||||
|
@ -195,24 +178,28 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
case IPC_PPCMSG: // __ios_Ipc2 ... a value from __responses is loaded
|
||||
{
|
||||
ppc_msg = _Value;
|
||||
INFO_LOG(WII_IPC, "IPC_PPCMSG = %08x", ppc_msg);
|
||||
DEBUG_LOG(WII_IPC, "IPC_PPCMSG = %08x", ppc_msg);
|
||||
}
|
||||
break;
|
||||
|
||||
case IPC_PPCCTRL:
|
||||
{
|
||||
ctrl.ppc(_Value);
|
||||
INFO_LOG(WII_IPC, "w32 %08x IPC_PPCCTRL = %03x [R:%i A:%i E:%i]",
|
||||
DEBUG_LOG(WII_IPC, "w32 %08x IPC_PPCCTRL = %03x [R:%i A:%i E:%i]",
|
||||
_Value, ctrl.ppc(), ctrl.Y1, ctrl.Y2, ctrl.X1);
|
||||
if (ctrl.X1) // seems like we should just be able to use X1 directly, but it doesn't work...why?!
|
||||
cmd_active = true;
|
||||
if (ctrl.X1)
|
||||
{
|
||||
INFO_LOG(WII_IPC, "new pointer available: %08x", ppc_msg);
|
||||
// Let the HLE handle the request on it's own time
|
||||
WII_IPC_HLE_Interface::EnqRequest(ppc_msg);
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case PPC_IRQFLAG: // ACR REGISTER IT IS CALLED IN DEBUG
|
||||
{
|
||||
ppc_irq_flags &= ~_Value;
|
||||
INFO_LOG(WII_IPC, "w32 PPC_IRQFLAG %08x (%08x)", _Value, ppc_irq_flags);
|
||||
DEBUG_LOG(WII_IPC, "w32 PPC_IRQFLAG %08x (%08x)", _Value, ppc_irq_flags);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -221,7 +208,7 @@ void Write32(const u32 _Value, const u32 _Address)
|
|||
ppc_irq_masks = _Value;
|
||||
if (ppc_irq_masks & INT_CAUSE_IPC_BROADWAY) // wtf?
|
||||
Reset();
|
||||
INFO_LOG(WII_IPC, "w32 PPC_IRQMASK %08x", ppc_irq_masks);
|
||||
DEBUG_LOG(WII_IPC, "w32 PPC_IRQMASK %08x", ppc_irq_masks);
|
||||
}
|
||||
break;
|
||||
|
||||
|
@ -253,21 +240,12 @@ void UpdateInterrupts()
|
|||
ProcessorInterface::SetInterrupt(ProcessorInterface::INT_CAUSE_WII_IPC, !!(ppc_irq_flags & ppc_irq_masks));
|
||||
}
|
||||
|
||||
// The rest is for IOS HLE
|
||||
bool IsReady()
|
||||
void GenerateAck(u32 _Address)
|
||||
{
|
||||
return ((ctrl.Y1 == 0) && (ctrl.Y2 == 0) && ((ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0));
|
||||
}
|
||||
|
||||
u32 GetAddress()
|
||||
{
|
||||
return (cmd_active ? ppc_msg : 0);
|
||||
}
|
||||
|
||||
void GenerateAck()
|
||||
{
|
||||
cmd_active = false;
|
||||
arm_msg = _Address; // dunno if it's really set here, but HLE needs to stay in context
|
||||
ctrl.Y2 = 1;
|
||||
INFO_LOG(WII_IPC, "GenerateAck: %08x | %08x [R:%i A:%i E:%i]",
|
||||
ppc_msg,_Address, ctrl.Y1, ctrl.Y2, ctrl.X1);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
|
@ -275,40 +253,14 @@ void GenerateReply(u32 _Address)
|
|||
{
|
||||
arm_msg = _Address;
|
||||
ctrl.Y1 = 1;
|
||||
INFO_LOG(WII_IPC, "GenerateReply: %08x | %08x [R:%i A:%i E:%i]",
|
||||
ppc_msg,_Address, ctrl.Y1, ctrl.Y2, ctrl.X1);
|
||||
UpdateInterrupts();
|
||||
}
|
||||
|
||||
void EnqReply(u32 _Address)
|
||||
bool IsReady()
|
||||
{
|
||||
if (g_ReplyNum < REPLY_FIFO_DEPTH)
|
||||
{
|
||||
g_ReplyFifo[g_ReplyTail++] = _Address;
|
||||
g_ReplyTail &= REPLY_FIFO_MASK;
|
||||
g_ReplyNum++;
|
||||
}
|
||||
else
|
||||
{
|
||||
ERROR_LOG(WII_IPC, "Reply FIFO is full, something must be wrong!");
|
||||
PanicAlert("WII_IPC: Reply FIFO is full, something must be wrong!");
|
||||
}
|
||||
}
|
||||
|
||||
u32 DeqReply()
|
||||
{
|
||||
u32 _Address;
|
||||
|
||||
if (g_ReplyNum)
|
||||
{
|
||||
_Address = g_ReplyFifo[g_ReplyHead++];
|
||||
g_ReplyHead &= REPLY_FIFO_MASK;
|
||||
g_ReplyNum--;
|
||||
}
|
||||
else
|
||||
{
|
||||
_Address = NULL;
|
||||
}
|
||||
|
||||
return _Address;
|
||||
return ((ctrl.Y1 == 0) && (ctrl.Y2 == 0) && ((ppc_irq_flags & INT_CAUSE_IPC_BROADWAY) == 0));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
|
@ -44,9 +44,6 @@ enum StarletInterruptCause
|
|||
INT_CAUSE_IPC_STARLET = 0x80000000
|
||||
};
|
||||
|
||||
#define REPLY_FIFO_DEPTH (unsigned)8
|
||||
#define REPLY_FIFO_MASK (REPLY_FIFO_DEPTH - 1)
|
||||
|
||||
void Init();
|
||||
void Reset();
|
||||
void Shutdown();
|
||||
|
@ -55,14 +52,10 @@ void DoState(PointerWrap &p);
|
|||
void Read32(u32& _rReturnValue, const u32 _Address);
|
||||
void Write32(const u32 _Value, const u32 _Address);
|
||||
|
||||
u32 GetAddress();
|
||||
void GenerateAck();
|
||||
void GenerateReply(u32 _Address);
|
||||
void InsertReply(u32 _Address);
|
||||
void EnqReply(u32 _Address);
|
||||
u32 DeqReply();
|
||||
|
||||
void UpdateInterrupts();
|
||||
void GenerateAck(u32 _Address);
|
||||
void GenerateReply(u32 _Address);
|
||||
|
||||
bool IsReady();
|
||||
|
||||
}
|
||||
|
|
|
@ -15,30 +15,23 @@
|
|||
// Official SVN repository and contact information can be found at
|
||||
// http://code.google.com/p/dolphin-emu/
|
||||
|
||||
/*
|
||||
This is the main Wii IPC file that handles all incoming IPC calls and directs them
|
||||
to the right function.
|
||||
|
||||
IPC basics (IOS' usage):
|
||||
|
||||
// =======================================================
|
||||
// File description
|
||||
// -------------
|
||||
/* This is the main Wii IPC file that handles all incoming IPC calls and directs them
|
||||
to the right function.
|
||||
|
||||
IPC basics:
|
||||
|
||||
Return values for file handles: All IPC calls will generate a return value to 0x04,
|
||||
in case of success they are
|
||||
Open: DeviceID
|
||||
Close: 0
|
||||
Read: Bytes read
|
||||
Write: Bytes written
|
||||
Seek: Seek position
|
||||
Ioctl: 0 (in addition to that there may be messages to the out buffers)
|
||||
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
|
||||
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp. */
|
||||
// =============
|
||||
|
||||
|
||||
|
||||
Return values for file handles: All IPC calls will generate a return value to 0x04,
|
||||
in case of success they are
|
||||
Open: DeviceID
|
||||
Close: 0
|
||||
Read: Bytes read
|
||||
Write: Bytes written
|
||||
Seek: Seek position
|
||||
Ioctl: 0 (in addition to that there may be messages to the out buffers)
|
||||
Ioctlv: 0 (in addition to that there may be messages to the out buffers)
|
||||
They will also generate a true or false return for UpdateInterrupts() in WII_IPC.cpp.
|
||||
*/
|
||||
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
@ -78,6 +71,10 @@ typedef std::map<u32, std::string> TFileNameMap;
|
|||
TFileNameMap g_FileNameMap;
|
||||
u32 g_LastDeviceID;
|
||||
|
||||
typedef std::queue<u32> ipc_msg_queue;
|
||||
static ipc_msg_queue request_queue; // ppc -> arm
|
||||
static ipc_msg_queue reply_queue; // arm -> ppc
|
||||
|
||||
// General IPC functions
|
||||
void Init()
|
||||
{
|
||||
|
@ -125,6 +122,9 @@ void Reset(bool _bHard)
|
|||
g_DeviceMap.erase(itr, g_DeviceMap.end());
|
||||
g_FileNameMap.clear();
|
||||
|
||||
request_queue = std::queue<u32>();
|
||||
reply_queue = std::queue<u32>();
|
||||
|
||||
g_LastDeviceID = IPC_FIRST_FILEIO_ID;
|
||||
}
|
||||
|
||||
|
@ -133,7 +133,6 @@ void Shutdown()
|
|||
Reset(true);
|
||||
}
|
||||
|
||||
// Set default content file
|
||||
void SetDefaultContentFile(const std::string& _rFilename)
|
||||
{
|
||||
CWII_IPC_HLE_Device_es* pDevice = (CWII_IPC_HLE_Device_es*)AccessDeviceByID(GetDeviceIDByName(std::string("/dev/es")));
|
||||
|
@ -172,7 +171,7 @@ void DeleteDeviceByID(u32 ID)
|
|||
g_FileNameMap.erase(ID);
|
||||
}
|
||||
|
||||
// This is called from COMMAND_OPEN_DEVICE. Here we either create a new file handle
|
||||
// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
|
||||
IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
|
||||
{
|
||||
// scan device name and create the right one
|
||||
|
@ -184,7 +183,7 @@ IWII_IPC_HLE_Device* CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName
|
|||
return pDevice;
|
||||
}
|
||||
|
||||
// Let the game read the setting.txt file
|
||||
// Try to make sure the game is always reading the setting.txt file we provide
|
||||
void CopySettingsFile(std::string& DeviceName)
|
||||
{
|
||||
std::string Source = File::GetSysDirectory() + WII_SYS_DIR + DIR_SEP;
|
||||
|
@ -197,7 +196,8 @@ void CopySettingsFile(std::string& DeviceName)
|
|||
|
||||
// Check if the target dir exists, otherwise create it
|
||||
std::string TargetDir = Target.substr(0, Target.find_last_of(DIR_SEP));
|
||||
if(!File::IsDirectory(TargetDir.c_str())) File::CreateFullPath(Target.c_str());
|
||||
if (!File::IsDirectory(TargetDir.c_str()))
|
||||
File::CreateFullPath(Target.c_str());
|
||||
|
||||
if (File::Copy(Source.c_str(), Target.c_str()))
|
||||
{
|
||||
|
@ -256,14 +256,6 @@ void DoState(PointerWrap &p)
|
|||
}
|
||||
}
|
||||
|
||||
// ===================================================
|
||||
/* This generates an acknowledgment to IPC calls. This function is called from
|
||||
IPC_CONTROL_REGISTER requests in WII_IPC.cpp. The acknowledgment _Address will
|
||||
start with 0x033e...., it will be for the _CommandAddress 0x133e...., from
|
||||
debugging I also noticed that the Ioctl arguments are stored temporarily in
|
||||
0x933e.... with the same .... as in the _CommandAddress. */
|
||||
// ----------------
|
||||
|
||||
void ExecuteCommand(u32 _Address)
|
||||
{
|
||||
bool CmdSuccess = false;
|
||||
|
@ -284,7 +276,8 @@ void ExecuteCommand(u32 _Address)
|
|||
Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));
|
||||
|
||||
// The game may try to read setting.txt here, in that case copy it so it can read it
|
||||
if(DeviceName.find("setting.txt") != std::string::npos) CopySettingsFile(DeviceName);
|
||||
if (DeviceName.find("setting.txt") != std::string::npos)
|
||||
CopySettingsFile(DeviceName);
|
||||
|
||||
u32 Mode = Memory::Read_U32(_Address + 0x10);
|
||||
DeviceID = GetDeviceIDByName(DeviceName);
|
||||
|
@ -332,9 +325,9 @@ void ExecuteCommand(u32 _Address)
|
|||
INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
|
||||
pDevice->GetDeviceName().c_str(), DeviceID, Mode);
|
||||
|
||||
if(pDevice->IsHardware())
|
||||
if (pDevice->IsHardware())
|
||||
{
|
||||
if(pDevice->IsOpened())
|
||||
if (pDevice->IsOpened())
|
||||
{
|
||||
if (pDevice->GetDeviceName().find("/dev/net/kd/request") != std::string::npos)
|
||||
// AyuanX: /dev/net/kd/request is more like event which doesn't need close so it can be reopened
|
||||
|
@ -358,7 +351,7 @@ void ExecuteCommand(u32 _Address)
|
|||
// Open > Failed > ... other stuff > ReOpen call sequence, in that case
|
||||
// we have no file and no file handle, so we call Open again to basically
|
||||
// get a -106 error so that the game call CreateFile and then ReOpen again.
|
||||
if(pDevice->ReturnFileHandle())
|
||||
if (pDevice->ReturnFileHandle())
|
||||
Memory::Write_U32(DeviceID, _Address + 4);
|
||||
else
|
||||
pDevice->Open(_Address, Mode);
|
||||
|
@ -368,110 +361,102 @@ void ExecuteCommand(u32 _Address)
|
|||
break;
|
||||
|
||||
case COMMAND_CLOSE_DEVICE:
|
||||
{
|
||||
if (pDevice)
|
||||
{
|
||||
pDevice->Close(_Address);
|
||||
// Don't delete hardware
|
||||
if (!pDevice->IsHardware())
|
||||
DeleteDeviceByID(DeviceID);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
}
|
||||
if (pDevice)
|
||||
{
|
||||
pDevice->Close(_Address);
|
||||
// Don't delete hardware
|
||||
if (!pDevice->IsHardware())
|
||||
DeleteDeviceByID(DeviceID);
|
||||
CmdSuccess = true;
|
||||
}
|
||||
break;
|
||||
|
||||
case COMMAND_READ:
|
||||
{
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Read(_Address);
|
||||
}
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Read(_Address);
|
||||
break;
|
||||
|
||||
case COMMAND_WRITE:
|
||||
{
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Write(_Address);
|
||||
}
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Write(_Address);
|
||||
break;
|
||||
|
||||
case COMMAND_SEEK:
|
||||
{
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Seek(_Address);
|
||||
}
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->Seek(_Address);
|
||||
break;
|
||||
|
||||
case COMMAND_IOCTL:
|
||||
{
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->IOCtl(_Address);
|
||||
}
|
||||
if (pDevice != NULL)
|
||||
CmdSuccess = pDevice->IOCtl(_Address);
|
||||
break;
|
||||
|
||||
case COMMAND_IOCTLV:
|
||||
{
|
||||
if (pDevice)
|
||||
CmdSuccess = pDevice->IOCtlV(_Address);
|
||||
}
|
||||
if (pDevice)
|
||||
CmdSuccess = pDevice->IOCtlV(_Address);
|
||||
break;
|
||||
|
||||
default:
|
||||
_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
|
||||
// Break on the same terms as the _dbg_assert_msg_, if LOGGING was defined
|
||||
break;
|
||||
}
|
||||
|
||||
|
||||
// It seems that the original hardware overwrites the command after it has been
|
||||
// executed. We write 8 which is not any valid command.
|
||||
//
|
||||
// AyuanX: Is this really necessary?
|
||||
// My experiment says no, so I'm just commenting this out
|
||||
//
|
||||
//Memory::Write_U32(8, _Address);
|
||||
// executed. We write 8 which is not any valid command, and what IOS does
|
||||
Memory::Write_U32(8, _Address);
|
||||
// IOS seems to write back the command that was responded to
|
||||
Memory::Write_U32(Command, _Address + 8);
|
||||
|
||||
if (CmdSuccess)
|
||||
{
|
||||
// Generate a reply to the IPC command
|
||||
WII_IPCInterface::EnqReply(_Address);
|
||||
EnqReply(_Address);
|
||||
}
|
||||
else
|
||||
{
|
||||
//INFO_LOG(WII_IPC_HLE, "<<-- Failed or Not Ready to Reply to Command Address: 0x%08x ", _Address);
|
||||
ERROR_LOG(WII_IPC_HLE, "<<-- Failed or Not Ready to Reply to IPC Request @ 0x%08x ", _Address);
|
||||
}
|
||||
}
|
||||
|
||||
// Happens AS SOON AS IPC gets a new pointer!
|
||||
void EnqRequest(u32 _Address)
|
||||
{
|
||||
request_queue.push(_Address);
|
||||
}
|
||||
|
||||
// ===================================================
|
||||
// This is called continuously from SystemTimers.cpp
|
||||
// ---------------------------------------------------
|
||||
// Called when IOS module has some reply
|
||||
void EnqReply(u32 _Address)
|
||||
{
|
||||
reply_queue.push(_Address);
|
||||
}
|
||||
|
||||
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
|
||||
// Takes care of routing ipc <-> ipc HLE
|
||||
void Update()
|
||||
{
|
||||
if (WII_IPCInterface::IsReady() == false)
|
||||
if (!WII_IPCInterface::IsReady())
|
||||
return;
|
||||
|
||||
UpdateDevices();
|
||||
|
||||
// if we have a reply to send
|
||||
u32 _Reply = WII_IPCInterface::DeqReply();
|
||||
if (_Reply)
|
||||
if (reply_queue.size())
|
||||
{
|
||||
WII_IPCInterface::GenerateReply(_Reply);
|
||||
INFO_LOG(WII_IPC_HLE, "<<-- Reply to Command Address: 0x%08x", _Reply);
|
||||
WII_IPCInterface::GenerateReply(reply_queue.front());
|
||||
INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
|
||||
reply_queue.pop();
|
||||
return;
|
||||
}
|
||||
|
||||
// If there is a a new command
|
||||
u32 _Address = WII_IPCInterface::GetAddress();
|
||||
if (_Address)
|
||||
if (request_queue.size())
|
||||
{
|
||||
WII_IPCInterface::GenerateAck();
|
||||
INFO_LOG(WII_IPC_HLE, "||-- Acknowledge Command Address: 0x%08x", _Address);
|
||||
WII_IPCInterface::GenerateAck(request_queue.front());
|
||||
INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
|
||||
|
||||
ExecuteCommand(_Address);
|
||||
ExecuteCommand(request_queue.front());
|
||||
request_queue.pop();
|
||||
|
||||
#if MAX_LOG_LEVEL >= DEBUG_LEVEL
|
||||
Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
|
||||
#if MAX_LOGLEVEL >= DEBUG_LEVEL
|
||||
Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -488,4 +473,4 @@ void UpdateDevices()
|
|||
}
|
||||
|
||||
|
||||
} // end of namespace IPC
|
||||
} // end of namespace WII_IPC_HLE_Interface
|
||||
|
|
|
@ -61,6 +61,9 @@ void UpdateDevices();
|
|||
|
||||
void ExecuteCommand(u32 _Address);
|
||||
|
||||
void EnqRequest(u32 _Address);
|
||||
void EnqReply(u32 _Address);
|
||||
|
||||
enum ECommandType
|
||||
{
|
||||
COMMAND_OPEN_DEVICE = 1,
|
||||
|
|
|
@ -77,17 +77,15 @@ protected:
|
|||
bool m_Hardware;
|
||||
bool m_Active;
|
||||
|
||||
// ===================================================
|
||||
/* A struct for IOS ioctlv calls */
|
||||
// ----------------
|
||||
// A struct for IOS ioctlv calls
|
||||
struct SIOCtlVBuffer
|
||||
{
|
||||
SIOCtlVBuffer(u32 _Address)
|
||||
: m_Address(_Address)
|
||||
{
|
||||
/* These are the Ioctlv parameters in the IOS communication. The BufferVector
|
||||
is a memory address offset at where the in and out buffer addresses are
|
||||
stored. */
|
||||
// These are the Ioctlv parameters in the IOS communication. The BufferVector
|
||||
// is a memory address offset at where the in and out buffer addresses are
|
||||
// stored.
|
||||
Parameter = Memory::Read_U32(m_Address + 0x0C); // command 3, arg0
|
||||
NumberInBuffer = Memory::Read_U32(m_Address + 0x10); // 4, arg1
|
||||
NumberPayloadBuffer = Memory::Read_U32(m_Address + 0x14); // 5, arg2
|
||||
|
@ -144,11 +142,8 @@ protected:
|
|||
std::vector<SBuffer> PayloadBuffer;
|
||||
};
|
||||
|
||||
|
||||
// ===================================================
|
||||
/* Write out the IPC struct from _CommandAddress to _NumberOfCommands numbers
|
||||
of 4 byte commands. */
|
||||
// ----------------
|
||||
// Write out the IPC struct from _CommandAddress to _NumberOfCommands numbers
|
||||
// of 4 byte commands.
|
||||
void DumpCommands(u32 _CommandAddress, size_t _NumberOfCommands = 8,
|
||||
LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE,
|
||||
LogTypes::LOG_LEVELS Verbosity = LogTypes::LDEBUG)
|
||||
|
@ -161,7 +156,6 @@ protected:
|
|||
Memory::Read_U32(_CommandAddress + i*4));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void DumpAsync(u32 BufferVector, u32 NumberInBuffer, u32 NumberOutBuffer,
|
||||
LogTypes::LOG_TYPE LogType = LogTypes::WII_IPC_HLE,
|
||||
|
@ -175,7 +169,8 @@ protected:
|
|||
u32 InBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4;
|
||||
u32 InBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4;
|
||||
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV InBuffer[%i]:", GetDeviceName().c_str(), i);
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV InBuffer[%i]:",
|
||||
GetDeviceName().c_str(), i);
|
||||
|
||||
std::string Temp;
|
||||
for (u32 j = 0; j < InBufferSize; j++)
|
||||
|
@ -188,22 +183,21 @@ protected:
|
|||
GENERIC_LOG(LogType, LogTypes::LDEBUG, " Buffer: %s", Temp.c_str());
|
||||
}
|
||||
|
||||
|
||||
for (u32 i = 0; i < NumberOutBuffer; i++)
|
||||
{
|
||||
u32 OutBuffer = Memory::Read_U32(BufferOffset); BufferOffset += 4;
|
||||
u32 OutBufferSize = Memory::Read_U32(BufferOffset); BufferOffset += 4;
|
||||
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV OutBuffer[%i]:", GetDeviceName().c_str(), i);
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, " OutBuffer: 0x%08x (0x%x):", OutBuffer, OutBufferSize);
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, "%s - IOCtlV OutBuffer[%i]:",
|
||||
GetDeviceName().c_str(), i);
|
||||
GENERIC_LOG(LogType, LogTypes::LINFO, " OutBuffer: 0x%08x (0x%x):",
|
||||
OutBuffer, OutBufferSize);
|
||||
|
||||
#if defined(MAX_LOGLEVEL) && MAX_LOGLEVEL >= INFO_LEVEL
|
||||
DumpCommands(OutBuffer, OutBufferSize, LogType, Verbosity);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -37,10 +37,7 @@ enum
|
|||
IOCTL_STM_READDDRREG2 = 0x4002,
|
||||
};
|
||||
|
||||
|
||||
// =======================================================
|
||||
// The /device/stm/immediate class
|
||||
// -------------
|
||||
// The /dev/stm/immediate
|
||||
class CWII_IPC_HLE_Device_stm_immediate : public IWII_IPC_HLE_Device
|
||||
{
|
||||
public:
|
||||
|
@ -71,11 +68,11 @@ public:
|
|||
|
||||
virtual bool IOCtl(u32 _CommandAddress)
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress +0x0C);
|
||||
u32 BufferIn = Memory::Read_U32(_CommandAddress +0x10);
|
||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress +0x14);
|
||||
u32 BufferOut = Memory::Read_U32(_CommandAddress +0x18);
|
||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress +0x1C);
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
|
||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||
|
||||
// Prepare the out buffer(s) with zeroes as a safety precaution
|
||||
// to avoid returning bad values
|
||||
|
@ -123,16 +120,11 @@ public:
|
|||
|
||||
// Write return value to the IPC call
|
||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||
|
||||
// Generate true or false reply for the main UpdateInterrupts() function
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
// =======================================================
|
||||
// The /device/stm/eventhook class
|
||||
// -------------
|
||||
// The /dev/stm/eventhook
|
||||
class CWII_IPC_HLE_Device_stm_eventhook : public IWII_IPC_HLE_Device
|
||||
{
|
||||
public:
|
||||
|
@ -165,13 +157,13 @@ public:
|
|||
|
||||
virtual bool IOCtl(u32 _CommandAddress)
|
||||
{
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress +0x0C);
|
||||
u32 BufferIn = Memory::Read_U32(_CommandAddress +0x10);
|
||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress +0x14);
|
||||
u32 BufferOut = Memory::Read_U32(_CommandAddress +0x18);
|
||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress +0x1C);
|
||||
u32 Parameter = Memory::Read_U32(_CommandAddress + 0x0C);
|
||||
u32 BufferIn = Memory::Read_U32(_CommandAddress + 0x10);
|
||||
u32 BufferInSize = Memory::Read_U32(_CommandAddress + 0x14);
|
||||
u32 BufferOut = Memory::Read_U32(_CommandAddress + 0x18);
|
||||
u32 BufferOutSize = Memory::Read_U32(_CommandAddress + 0x1C);
|
||||
|
||||
// Prepare the out buffer(s) with zeroes as a safety precaution
|
||||
// Prepare the out buffer(s) with zeros as a safety precaution
|
||||
// to avoid returning bad values
|
||||
Memory::Memset(BufferOut, 0, BufferOutSize);
|
||||
u32 ReturnValue = 0;
|
||||
|
@ -184,42 +176,29 @@ public:
|
|||
m_EventHookAddress = _CommandAddress;
|
||||
|
||||
INFO_LOG(WII_IPC_STM, "%s registers event hook:", GetDeviceName().c_str());
|
||||
DEBUG_LOG(WII_IPC_STM, " 0x1000 - IOCTL_STM_EVENTHOOK", Parameter);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferIn: 0x%08x", BufferIn);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferInSize: 0x%08x", BufferInSize);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferOut: 0x%08x", BufferOut);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferOutSize: 0x%08x", BufferOutSize);
|
||||
DEBUG_LOG(WII_IPC_STM, "0x1000 - IOCTL_STM_EVENTHOOK", Parameter);
|
||||
DEBUG_LOG(WII_IPC_STM, "BufferIn: 0x%08x", BufferIn);
|
||||
DEBUG_LOG(WII_IPC_STM, "BufferInSize: 0x%08x", BufferInSize);
|
||||
DEBUG_LOG(WII_IPC_STM, "BufferOut: 0x%08x", BufferOut);
|
||||
DEBUG_LOG(WII_IPC_STM, "BufferOutSize: 0x%08x", BufferOutSize);
|
||||
|
||||
DumpCommands(BufferIn, BufferInSize/4, LogTypes::WII_IPC_STM);
|
||||
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
{
|
||||
_dbg_assert_msg_(WII_IPC_STM, 0, "CWII_IPC_HLE_Device_stm_eventhook: 0x%x", Parameter);
|
||||
INFO_LOG(WII_IPC_STM, "%s registers event hook:", GetDeviceName().c_str());
|
||||
DEBUG_LOG(WII_IPC_STM, " Parameter: 0x%x", Parameter);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferIn: 0x%08x", BufferIn);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferInSize: 0x%08x", BufferInSize);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferOut: 0x%08x", BufferOut);
|
||||
DEBUG_LOG(WII_IPC_STM, " BufferOutSize: 0x%08x", BufferOutSize);
|
||||
}
|
||||
_dbg_assert_msg_(WII_IPC_STM, 0, "unknown %s ioctl %x",
|
||||
GetDeviceName().c_str(), Parameter);
|
||||
break;
|
||||
}
|
||||
|
||||
// Write return value to the IPC call, 0 means success
|
||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||
|
||||
// Generate true or false reply for the main UpdateInterrupts() function
|
||||
return false;
|
||||
Memory::Write_U32(ReturnValue, _CommandAddress + 0x4);
|
||||
return true;
|
||||
}
|
||||
|
||||
// STATE_TO_SAVE
|
||||
u32 m_EventHookAddress;
|
||||
};
|
||||
|
||||
|
||||
#endif
|
||||
|
||||
|
|
|
@ -316,16 +316,11 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::IOCtlV(u32 _CommandAddress)
|
|||
|
||||
// write return value
|
||||
Memory::Write_U32(0, _CommandAddress + 0x4);
|
||||
return (_SendReply);
|
||||
return _SendReply;
|
||||
}
|
||||
// ================
|
||||
|
||||
|
||||
|
||||
// ===================================================
|
||||
/* Here we handle the USB_IOCTL_BLKMSG Ioctlv */
|
||||
// ----------------
|
||||
|
||||
// Here we handle the USB_IOCTL_BLKMSG Ioctlv
|
||||
void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8* _pData, u32 _Size)
|
||||
{
|
||||
CWII_IPC_HLE_WiiMote* pWiiMote = AccessWiiMote(_ConnectionHandle);
|
||||
|
@ -337,18 +332,12 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendToDevice(u16 _ConnectionHandle, u8
|
|||
pWiiMote->ExecuteL2capCmd(_pData, _Size);
|
||||
}
|
||||
|
||||
// ================
|
||||
|
||||
|
||||
// ===================================================
|
||||
// Here we send ACL pakcets 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::SendACLPacket(u16 _ConnectionHandle, u8* _pData, u32 _Size)
|
||||
{
|
||||
if(m_ACLBuffer.m_address != 0)
|
||||
|
@ -368,7 +357,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u
|
|||
Memory::Write_U32(sizeof(UACLHeader) + _Size, m_ACLBuffer.m_address + 0x4);
|
||||
|
||||
// Send a reply to indicate ACL buffer is sent
|
||||
WII_IPCInterface::EnqReply(m_ACLBuffer.m_address);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_ACLBuffer.m_address);
|
||||
|
||||
// Invalidate ACL buffer
|
||||
m_ACLBuffer.m_address = 0;
|
||||
|
@ -403,7 +392,6 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::SendACLPacket(u16 _ConnectionHandle, u
|
|||
// 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::PurgeACLPool()
|
||||
{
|
||||
if(m_ACLBuffer.m_address == 0)
|
||||
|
@ -420,16 +408,14 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeACLPool()
|
|||
// Write the packet size as return value
|
||||
Memory::Write_U32(sizeof(UACLHeader) + ((UACLHeader*)_Address)->Size, m_ACLBuffer.m_address + 0x4);
|
||||
// Send a reply to indicate ACL buffer is sent
|
||||
WII_IPCInterface::EnqReply(m_ACLBuffer.m_address);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_ACLBuffer.m_address);
|
||||
// Invalidate ACL buffer
|
||||
m_ACLBuffer.m_address = 0;
|
||||
m_ACLBuffer.m_buffer = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
// ===================================================
|
||||
/* See IPC_HLE_PERIOD in SystemTimers.cpp for a documentation of this update. */
|
||||
// ----------------
|
||||
// See IPC_HLE_PERIOD in SystemTimers.cpp for a documentation of this update.
|
||||
u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
||||
{
|
||||
// Check if HCI Pool is not purged
|
||||
|
@ -437,7 +423,7 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
|||
{
|
||||
PurgeHCIPool();
|
||||
if (m_HCIPool.m_number == 0)
|
||||
WII_IPCInterface::EnqReply(m_CtrlSetup.m_Address);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_CtrlSetup.m_Address);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -453,23 +439,22 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
|||
{
|
||||
PurgeACLPool();
|
||||
if (m_ACLPool.m_number == 0)
|
||||
WII_IPCInterface::EnqReply(m_ACLSetup);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_ACLSetup);
|
||||
return true;
|
||||
}
|
||||
|
||||
// --------------------------------------------------------------------
|
||||
/* We wait for ScanEnable to be sent from the game through HCI_CMD_WRITE_SCAN_ENABLE
|
||||
before we initiate the connection.
|
||||
|
||||
FiRES: TODO find a good solution to do this
|
||||
|
||||
/* Why do we need this? 0 worked with the emulated wiimote in all games I tried. Do we have to
|
||||
Why do we need this? 0 worked with the emulated wiimote in all games I tried. Do we have to
|
||||
wait for wiiuse_init() and wiiuse_find() for a real Wiimote here? I'm testing
|
||||
this new method of not waiting at all if there are no real Wiimotes. Please let me know
|
||||
if it doesn't work. */
|
||||
|
||||
// AyuanX: I don't know the Real Wiimote behavior, so I'll leave it here untouched
|
||||
//
|
||||
|
||||
// Initiate ACL connection
|
||||
static int counter = (Core::GetRealWiimote() ? 1000 : 0);
|
||||
if (m_HCIBuffer.m_address && (m_ScanEnable & 0x2))
|
||||
|
@ -537,17 +522,13 @@ u32 CWII_IPC_HLE_Device_usb_oh1_57e_305::Update()
|
|||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
// Events
|
||||
// -----------------
|
||||
// These messages are sent from the Wiimote to the game, for example RequestConnection()
|
||||
// or ConnectionComplete().
|
||||
//
|
||||
|
||||
// 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
|
||||
//
|
||||
void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _event)
|
||||
{
|
||||
if (m_HCIBuffer.m_address != 0)
|
||||
|
@ -560,7 +541,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
|
|||
Memory::Write_U32((u32)_event.m_size, m_HCIBuffer.m_address + 0x4);
|
||||
|
||||
// Send a reply to indicate HCI buffer is filled
|
||||
WII_IPCInterface::EnqReply(m_HCIBuffer.m_address);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_HCIBuffer.m_address);
|
||||
|
||||
// Invalidate HCI buffer
|
||||
m_HCIBuffer.m_address = 0;
|
||||
|
@ -590,7 +571,6 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::AddEventToQueue(const SQueuedEvent& _e
|
|||
// 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 == 0)
|
||||
|
@ -607,7 +587,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::PurgeHCIPool()
|
|||
// 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);
|
||||
WII_IPC_HLE_Interface::EnqReply(m_HCIBuffer.m_address);
|
||||
// Invalidate ACL buffer
|
||||
m_HCIBuffer.m_address = 0;
|
||||
m_HCIBuffer.m_buffer = NULL;
|
||||
|
@ -714,7 +694,7 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConnectionComplete(const bdad
|
|||
return true;
|
||||
}
|
||||
|
||||
/* This is called from Update() after ScanEnable has been enabled. */
|
||||
// This is called from Update() after ScanEnable has been enabled.
|
||||
bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventRequestConnection(CWII_IPC_HLE_WiiMote& _rWiiMote)
|
||||
{
|
||||
SQueuedEvent Event(sizeof(SHCIEventRequestConnection), 0);
|
||||
|
@ -1137,8 +1117,6 @@ bool CWII_IPC_HLE_Device_usb_oh1_57e_305::SendEventConPacketTypeChange(u16 _conn
|
|||
// Command dispatcher
|
||||
// -----------------
|
||||
// This is called from the USB_IOCTL_HCI_COMMAND_MESSAGE Ioctlv
|
||||
//
|
||||
//
|
||||
void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICommandMessage& _rHCICommandMessage)
|
||||
{
|
||||
u8* pInput = Memory::GetPointer(_rHCICommandMessage.m_PayLoadAddr + 3);
|
||||
|
@ -1329,7 +1307,7 @@ void CWII_IPC_HLE_Device_usb_oh1_57e_305::ExecuteHCICommandMessage(const SHCICom
|
|||
if ((m_LastCmd == 0) && (m_HCIPool.m_number == 0))
|
||||
{
|
||||
// If HCI command is finished and HCI pool is empty, send a reply to command
|
||||
WII_IPCInterface::EnqReply(_rHCICommandMessage.m_Address);
|
||||
WII_IPC_HLE_Interface::EnqReply(_rHCICommandMessage.m_Address);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
Loading…
Reference in New Issue