Example #1
0
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
{
	if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
		return g_DeviceMap[_ID];

		return NULL;
}
Example #2
0
IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
{
	if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
	{
		return g_DeviceMap[_ID];
	}

	return nullptr;
}
Example #3
0
void UpdateDevices()
{
	// Check if a hardware device must be updated
	for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
	{
		if (itr->second->IsOpened() && itr->second->Update())
		{
			break;
		}
	}
}
Example #4
0
void SetDefaultContentFile(const std::string& _rFilename)
{
	TDeviceMap::const_iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
		{
			((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
		}
		++itr;
	}
}
Example #5
0
IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
{
	TDeviceMap::const_iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
			return itr->second;
		++itr;
	}

	return NULL;
}
Example #6
0
void Reset(bool _bHard)
{

	CoreTiming::RemoveAllEvents(enque_reply);

	u32 i;
	for (i=0; i<IPC_MAX_FDS; i++)
	{
		if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
		{
			// close all files and delete their resources
			g_FdMap[i]->Close(0, true);
			delete g_FdMap[i];
		}
		g_FdMap[i] = NULL;
	}

	u32 j;
	for (j=0; j<ES_MAX_COUNT; j++)
	{
		es_inuse[j] = false;
	}

	TDeviceMap::iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second)
		{
			// Force close
			itr->second->Close(0, true);
			// Hardware should not be deleted unless it is a hard reset
			if (_bHard)
				delete itr->second;
		}
		++itr;
	}
	if (_bHard)
	{
		g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
	}
	request_queue.clear();

	// lock due to using reply_queue
	{
		std::lock_guard<std::mutex> lk(s_reply_queue);
		reply_queue.clear();
	}
	last_reply_time = 0;
}
Example #7
0
void Reset(bool _bHard)
{
	CoreTiming::RemoveAllEvents(event_enqueue);

	for (IWII_IPC_HLE_Device*& dev : g_FdMap)
	{
		if (dev != nullptr && !dev->IsHardware())
		{
			// close all files and delete their resources
			dev->Close(0, true);
			delete dev;
		}

		dev = nullptr;
	}

	for (bool& in_use : es_inuse)
	{
		in_use = false;
	}

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second)
		{
			// Force close
			entry.second->Close(0, true);

			// Hardware should not be deleted unless it is a hard reset
			if (_bHard)
				delete entry.second;
		}
	}

	if (_bHard)
	{
		g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
	}
	request_queue.clear();
	reply_queue.clear();

	last_reply_time = 0;
}
Example #8
0
void Init()
{
	bool Wee_speeak_support = SConfig::GetInstance().bWiiSpeakSupport;
	_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
	CWII_IPC_HLE_Device_es::m_ContentFile = "";

	num_devices = 0;

	// Build hardware devices
	if (Wee_speeak_support)
	{
		AddDevice<CWII_IPC_HLE_Device_usb_oh0>("/dev/usb/oh0");
		AddDevice<CWII_IPC_HLE_Device_usb_ven>("/dev/usb/ven");
		AddDevice<CWII_IPC_HLE_Device_usb_oh0_57e_308>("/dev/usb/oh0/57e/308");
		AddDevice<CWII_IPC_HLE_Device_usb_oh0_46d_a03>("/dev/usb/oh0/46d/a03");
	}
	AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305>("/dev/usb/oh1/57e/305");
	AddDevice<CWII_IPC_HLE_Device_stm_immediate>("/dev/stm/immediate");
	AddDevice<CWII_IPC_HLE_Device_stm_eventhook>("/dev/stm/eventhook");
	AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");

	// IOS allows two ES devices at a time
	for (u32 j=0; j<ES_MAX_COUNT; j++)
	{
		es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
		es_inuse[j] = false;
	}

	AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
	AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
	AddDevice<CWII_IPC_HLE_Device_net_kd_time>("/dev/net/kd/time");
	AddDevice<CWII_IPC_HLE_Device_net_ncd_manage>("/dev/net/ncd/manage");
	AddDevice<CWII_IPC_HLE_Device_net_wd_command>("/dev/net/wd/command");
	AddDevice<CWII_IPC_HLE_Device_net_ip_top>("/dev/net/ip/top");
	AddDevice<CWII_IPC_HLE_Device_net_ssl>("/dev/net/ssl");
	AddDevice<CWII_IPC_HLE_Device_usb_kbd>("/dev/usb/kbd");
	AddDevice<CWII_IPC_HLE_Device_sdio_slot0>("/dev/sdio/slot0");
	AddDevice<CWII_IPC_HLE_Device_stub>("/dev/sdio/slot1");
	#if defined(__LIBUSB__) || defined(_WIN32)
		AddDevice<CWII_IPC_HLE_Device_hid>("/dev/usb/hid");
	#else
		AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/hid");
	#endif
	AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/oh1");
	AddDevice<IWII_IPC_HLE_Device>("_Unimplemented_Device_");

	event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
}
Example #9
0
void Init()
{

	_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
	CWII_IPC_HLE_Device_es::m_ContentFile = "";
	u32 i;
	for (i=0; i<IPC_MAX_FDS; i++)
	{
		g_FdMap[i] = NULL;
	}

	i = 0;
	// Build hardware devices
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;

	// IOS allows two ES devices at a time<
	u32 j;
	for (j=0; j<ES_MAX_COUNT; j++)
	{
		g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
		es_inuse[j] = false;
	}

	g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, std::string("/dev/net/ncd/manage")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, std::string("/dev/net/wd/command")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, std::string("/dev/net/ip/top")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, std::string("/dev/net/ssl")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, std::string("/dev/usb/kbd")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, std::string("/dev/sdio/slot0")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
	#if  defined(__LIBUSB__) || defined(_WIN32)
		g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, std::string("/dev/usb/hid")); i++;
	#else
        g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
	#endif
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
	g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;

	enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
}
Example #10
0
void Init()
{
  _dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
  CWII_IPC_HLE_Device_es::m_ContentFile = "";

  num_devices = 0;

  // Build hardware devices
  AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305>("/dev/usb/oh1/57e/305");
  AddDevice<CWII_IPC_HLE_Device_stm_immediate>("/dev/stm/immediate");
  AddDevice<CWII_IPC_HLE_Device_stm_eventhook>("/dev/stm/eventhook");
  AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");

  // IOS allows two ES devices at a time
  for (u32 j = 0; j < ES_MAX_COUNT; j++)
  {
    es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
    es_inuse[j] = false;
  }

  AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
  AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
  AddDevice<CWII_IPC_HLE_Device_net_kd_time>("/dev/net/kd/time");
  AddDevice<CWII_IPC_HLE_Device_net_ncd_manage>("/dev/net/ncd/manage");
  AddDevice<CWII_IPC_HLE_Device_net_wd_command>("/dev/net/wd/command");
  AddDevice<CWII_IPC_HLE_Device_net_ip_top>("/dev/net/ip/top");
  AddDevice<CWII_IPC_HLE_Device_net_ssl>("/dev/net/ssl");
  AddDevice<CWII_IPC_HLE_Device_usb_kbd>("/dev/usb/kbd");
  AddDevice<CWII_IPC_HLE_Device_sdio_slot0>("/dev/sdio/slot0");
  AddDevice<CWII_IPC_HLE_Device_stub>("/dev/sdio/slot1");
#if defined(__LIBUSB__) || defined(_WIN32)
  AddDevice<CWII_IPC_HLE_Device_hid>("/dev/usb/hid");
#else
  AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/hid");
#endif
  AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/oh1");
  AddDevice<IWII_IPC_HLE_Device>("_Unimplemented_Device_");

  event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
  event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread);
}
Example #11
0
void Reset(bool _bHard)
{
	CoreTiming::RemoveAllEvents(event_enqueue);

	for (auto& dev : g_FdMap)
	{
		if (dev && !dev->IsHardware())
		{
			// close all files and delete their resources
			dev->Close(0, true);
		}

		dev.reset();
	}

	for (bool& in_use : es_inuse)
	{
		in_use = false;
	}

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second)
		{
			// Force close
			entry.second->Close(0, true);
		}
	}

	if (_bHard)
	{
		g_DeviceMap.clear();
	}
	request_queue.clear();
	reply_queue.clear();

	last_reply_time = 0;
}
Example #12
0
namespace WII_IPC_HLE_Interface
{

typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
static TDeviceMap g_DeviceMap;

// STATE_TO_SAVE
typedef std::map<u32, std::string> TFileNameMap;

#define IPC_MAX_FDS 0x18
#define ES_MAX_COUNT 2
static IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
static bool es_inuse[ES_MAX_COUNT];
static IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];


typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue;   // arm -> ppc
static ipc_msg_queue ack_queue;   // arm -> ppc

static int event_enqueue;

static u64 last_reply_time;

static const u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL;
static const u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL;
static void EnqueueEventCallback(u64 userdata, int)
{
	if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG)
	{
		ack_queue.push_back((u32)userdata);
	}
	else if (userdata & ENQUEUE_REQUEST_FLAG)
	{
		request_queue.push_back((u32)userdata);
	}
	else
	{
		reply_queue.push_back((u32)userdata);
	}
	Update();
}

void Init()
{
	_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
	CWII_IPC_HLE_Device_es::m_ContentFile = "";

	for (IWII_IPC_HLE_Device*& dev : g_FdMap)
	{
		dev = nullptr;
	}

	u32 i = 0;
	// Build hardware devices
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, "/dev/usb/oh1/57e/305"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, "/dev/stm/immediate"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, "/dev/stm/eventhook"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, "/dev/fs"); i++;

	// IOS allows two ES devices at a time
	for (u32 j=0; j<ES_MAX_COUNT; j++)
	{
		g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, "/dev/es"); i++;
		es_inuse[j] = false;
	}

	g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, "/dev/net/kd/request"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, "/dev/net/kd/time"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, "/dev/net/ncd/manage"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, "/dev/net/wd/command"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, "/dev/net/ip/top"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, "/dev/net/ssl"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, "/dev/usb/kbd"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, "/dev/sdio/slot0"); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/sdio/slot1"); i++;
	#if defined(__LIBUSB__) || defined(_WIN32)
		g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, "/dev/usb/hid"); i++;
	#else
		g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/hid"); i++;
	#endif
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, "/dev/usb/oh1"); i++;
	g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, "_Unimplemented_Device_"); i++;

	event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEventCallback);
}

void Reset(bool _bHard)
{
	CoreTiming::RemoveAllEvents(event_enqueue);

	for (IWII_IPC_HLE_Device*& dev : g_FdMap)
	{
		if (dev != nullptr && !dev->IsHardware())
		{
			// close all files and delete their resources
			dev->Close(0, true);
			delete dev;
		}

		dev = nullptr;
	}

	for (bool& in_use : es_inuse)
	{
		in_use = false;
	}

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second)
		{
			// Force close
			entry.second->Close(0, true);

			// Hardware should not be deleted unless it is a hard reset
			if (_bHard)
				delete entry.second;
		}
	}

	if (_bHard)
	{
		g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
	}
	request_queue.clear();
	reply_queue.clear();

	last_reply_time = 0;
}

void Shutdown()
{
	Reset(true);
}

void SetDefaultContentFile(const std::string& _rFilename)
{
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0)
		{
			((CWII_IPC_HLE_Device_es*)entry.second)->LoadWAD(_rFilename);
		}
	}
}

void ES_DIVerify(u8 *_pTMD, u32 _sz)
{
	CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
}

void SDIO_EventNotify()
{
	CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
		(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName("/dev/sdio/slot0");
	if (pDevice)
		pDevice->EventNotify();
}

int getFreeDeviceId()
{
	for (u32 i=0; i<IPC_MAX_FDS; i++)
	{
		if (g_FdMap[i] == nullptr)
		{
			return i;
		}
	}

	return -1;
}

IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
{
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second && entry.second->GetDeviceName() == _rDeviceName)
		{
			return entry.second;
		}
	}

	return nullptr;
}

IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
{
	if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
	{
		return g_DeviceMap[_ID];
	}

	return nullptr;
}

// 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
	IWII_IPC_HLE_Device* pDevice = nullptr;

	INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
	pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);

	return pDevice;
}


void DoState(PointerWrap &p)
{
	p.Do(request_queue);
	p.Do(reply_queue);
	p.Do(last_reply_time);

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second->IsHardware())
		{
			entry.second->DoState(p);
		}
	}

	if (p.GetMode() == PointerWrap::MODE_READ)
	{
		for (u32 i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = 0;
					p.Do(hwId);
					g_FdMap[i] = AccessDeviceByID(hwId);
				}
				else
				{
					g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
					g_FdMap[i]->DoState(p);
				}
			}
			else
			{
				g_FdMap[i] = nullptr;
			}
		}

		for (u32 i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);

			es_handles[i] = AccessDeviceByID(handleID);
		}
	}
	else
	{
		for (IWII_IPC_HLE_Device*& dev : g_FdMap)
		{
			u32 exists = dev ? 1 : 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = dev->IsHardware() ? 1 : 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = dev->GetDeviceID();
					p.Do(hwId);
				}
				else
				{
					dev->DoState(p);
				}
			}
		}

		for (u32 i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);
		}
	}
}

void ExecuteCommand(u32 _Address)
{
	bool CmdSuccess = false;

	IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
	volatile s32 DeviceID = Memory::Read_U32(_Address + 8);

	IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr;

	INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);

	switch (Command)
	{
	case IPC_CMD_OPEN:
	{
		u32 Mode = Memory::Read_U32(_Address + 0x10);
		DeviceID = getFreeDeviceId();

		std::string DeviceName = Memory::GetString(Memory::Read_U32(_Address + 0xC));

		WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
		if (DeviceID >= 0)
		{
			if (DeviceName.find("/dev/es") == 0)
			{
				u32 j;
				for (j=0; j<ES_MAX_COUNT; j++)
				{
					if (!es_inuse[j])
					{
						es_inuse[j] = true;
						g_FdMap[DeviceID] = es_handles[j];
						CmdSuccess = es_handles[j]->Open(_Address, Mode);
						Memory::Write_U32(DeviceID, _Address+4);
						break;
					}
				}

				if (j == ES_MAX_COUNT)
				{
					Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
					CmdSuccess = true;
				}
			}
			else if (DeviceName.find("/dev/") == 0)
			{
				pDevice = GetDeviceByName(DeviceName);
				if (pDevice)
				{
					g_FdMap[DeviceID] = pDevice;
					CmdSuccess = pDevice->Open(_Address, Mode);
					INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
					Memory::Write_U32(DeviceID, _Address+4);
				}
				else
				{
					WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
					Memory::Write_U32(FS_ENOENT, _Address+4);
					CmdSuccess = true;
				}
			}
			else
			{
				pDevice = CreateFileIO(DeviceID, DeviceName);
				CmdSuccess = pDevice->Open(_Address, Mode);

				INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
				if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
				{
					g_FdMap[DeviceID] = pDevice;
				}
				else
				{
					delete pDevice;
					pDevice = nullptr;
				}
			}
		}
		else
		{
			Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case IPC_CMD_CLOSE:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Close(_Address);

			for (u32 j=0; j<ES_MAX_COUNT; j++)
			{
				if (es_handles[j] == g_FdMap[DeviceID])
				{
					es_inuse[j] = false;
				}
			}

			g_FdMap[DeviceID] = nullptr;

			// Don't delete hardware
			if (!pDevice->IsHardware())
			{
				delete pDevice;
				pDevice = nullptr;
			}
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case IPC_CMD_READ:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Read(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case IPC_CMD_WRITE:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Write(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case IPC_CMD_SEEK:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Seek(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case IPC_CMD_IOCTL:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->IOCtl(_Address);
		}
		break;
	}
	case IPC_CMD_IOCTLV:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->IOCtlV(_Address);
		}
		break;
	}
	default:
	{
		_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
		break;
	}
	}


	if (CmdSuccess)
	{
		// The original hardware overwrites the command type with the async reply type.
		Memory::Write_U32(IPC_REP_ASYNC, _Address);
		// IOS also seems to write back the command that was responded to in the FD field.
		Memory::Write_U32(Command, _Address + 8);

		// Ensure replies happen in order, fairly ugly
		// Without this, tons of games fail now that DI commands have different reply delays
		int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;
		if (!reply_delay)
		{
			int delay_us = 250;
			reply_delay = SystemTimers::GetTicksPerSecond() / 1000000 * delay_us;
		}

		const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();

		if (ticks_til_last_reply > 0)
		{
			reply_delay = (int)ticks_til_last_reply;
		}

		last_reply_time = CoreTiming::GetTicks() + reply_delay;

		// Generate a reply to the IPC command
		EnqueueReply(_Address, reply_delay);
	}
}

// Happens AS SOON AS IPC gets a new pointer!
void EnqueueRequest(u32 address)
{
	CoreTiming::ScheduleEvent(1000, event_enqueue, address | ENQUEUE_REQUEST_FLAG);
}

// Called when IOS module has some reply
// NOTE: Only call this if you have correctly handled
//       CommandAddress+0 and CommandAddress+8.
//       Please search for examples of this being called elsewhere.
void EnqueueReply(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, address);
}

void EnqueueReply_Threadsafe(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent_Threadsafe(cycles_in_future, event_enqueue, address);
}

void EnqueueCommandAcknowledgement(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue,
	                          address | ENQUEUE_ACKNOWLEDGEMENT_FLAG);
}

// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
// Takes care of routing ipc <-> ipc HLE
void Update()
{
	if (!WII_IPCInterface::IsReady())
		return;

	if (request_queue.size())
	{
		WII_IPCInterface::GenerateAck(request_queue.front());
		INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
		u32 command = request_queue.front();
		request_queue.pop_front();
		ExecuteCommand(command);
		return;
	}

	if (reply_queue.size())
	{
		WII_IPCInterface::GenerateReply(reply_queue.front());
		INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
		reply_queue.pop_front();
		return;
	}

	if (ack_queue.size())
	{
		WII_IPCInterface::GenerateAck(ack_queue.front());
		WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", ack_queue.front());
		ack_queue.pop_front();
		return;
	}
}

void UpdateDevices()
{
	// Check if a hardware device must be updated
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second->IsOpened())
		{
			entry.second->Update();
		}
	}
}


} // end of namespace WII_IPC_HLE_Interface
Example #13
0
namespace WII_IPC_HLE_Interface
{

typedef std::map<u32, IWII_IPC_HLE_Device*> TDeviceMap;
TDeviceMap g_DeviceMap;

// STATE_TO_SAVE
typedef std::map<u32, std::string> TFileNameMap;

#define IPC_MAX_FDS 0x18
#define ES_MAX_COUNT 2
IWII_IPC_HLE_Device* g_FdMap[IPC_MAX_FDS];
bool es_inuse[ES_MAX_COUNT];
IWII_IPC_HLE_Device* es_handles[ES_MAX_COUNT];


typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue;	// ppc -> arm
static ipc_msg_queue reply_queue;	// arm -> ppc
static std::mutex s_reply_queue;

static int enque_reply;

static u64 last_reply_time;

void EnqueReplyCallback(u64 userdata, int)
{
	std::lock_guard<std::mutex> lk(s_reply_queue);
	reply_queue.push_back(userdata);
}

void Init()
{

	_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
	CWII_IPC_HLE_Device_es::m_ContentFile = "";
	u32 i;
	for (i=0; i<IPC_MAX_FDS; i++)
	{
		g_FdMap[i] = NULL;
	}

	i = 0;
	// Build hardware devices
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_oh1_57e_305(i, std::string("/dev/usb/oh1/57e/305")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_immediate(i, std::string("/dev/stm/immediate")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stm_eventhook(i, std::string("/dev/stm/eventhook")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_fs(i, std::string("/dev/fs")); i++;

	// IOS allows two ES devices at a time<
	u32 j;
	for (j=0; j<ES_MAX_COUNT; j++)
	{
		g_DeviceMap[i] = es_handles[j] = new CWII_IPC_HLE_Device_es(i, std::string("/dev/es")); i++;
		es_inuse[j] = false;
	}

	g_DeviceMap[i] = new CWII_IPC_HLE_Device_di(i, std::string("/dev/di")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_request(i, std::string("/dev/net/kd/request")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_kd_time(i, std::string("/dev/net/kd/time")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ncd_manage(i, std::string("/dev/net/ncd/manage")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_wd_command(i, std::string("/dev/net/wd/command")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ip_top(i, std::string("/dev/net/ip/top")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_net_ssl(i, std::string("/dev/net/ssl")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_usb_kbd(i, std::string("/dev/usb/kbd")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_sdio_slot0(i, std::string("/dev/sdio/slot0")); i++;
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/sdio/slot1")); i++;
	#if  defined(__LIBUSB__) || defined(_WIN32)
		g_DeviceMap[i] = new CWII_IPC_HLE_Device_hid(i, std::string("/dev/usb/hid")); i++;
	#else
        g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/hid")); i++;
	#endif
	g_DeviceMap[i] = new CWII_IPC_HLE_Device_stub(i, std::string("/dev/usb/oh1")); i++;
	g_DeviceMap[i] = new IWII_IPC_HLE_Device(i, std::string("_Unimplemented_Device_")); i++;

	enque_reply = CoreTiming::RegisterEvent("IPCReply", EnqueReplyCallback);
}

void Reset(bool _bHard)
{

	CoreTiming::RemoveAllEvents(enque_reply);

	u32 i;
	for (i=0; i<IPC_MAX_FDS; i++)
	{
		if (g_FdMap[i] != NULL && !g_FdMap[i]->IsHardware())
		{
			// close all files and delete their resources
			g_FdMap[i]->Close(0, true);
			delete g_FdMap[i];
		}
		g_FdMap[i] = NULL;
	}

	u32 j;
	for (j=0; j<ES_MAX_COUNT; j++)
	{
		es_inuse[j] = false;
	}

	TDeviceMap::iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second)
		{
			// Force close
			itr->second->Close(0, true);
			// Hardware should not be deleted unless it is a hard reset
			if (_bHard)
				delete itr->second;
		}
		++itr;
	}
	if (_bHard)
	{
		g_DeviceMap.erase(g_DeviceMap.begin(), g_DeviceMap.end());
	}
	request_queue.clear();

	// lock due to using reply_queue
	{
		std::lock_guard<std::mutex> lk(s_reply_queue);
		reply_queue.clear();
	}
	last_reply_time = 0;
}

void Shutdown()
{
	Reset(true);
}

void SetDefaultContentFile(const std::string& _rFilename)
{
	TDeviceMap::const_iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second && itr->second->GetDeviceName().find(std::string("/dev/es")) == 0)
		{
			((CWII_IPC_HLE_Device_es*)itr->second)->LoadWAD(_rFilename);
		}
		++itr;
	}
}

void ES_DIVerify(u8 *_pTMD, u32 _sz)
{
	CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
}

void SDIO_EventNotify()
{
	CWII_IPC_HLE_Device_sdio_slot0 *pDevice =
		(CWII_IPC_HLE_Device_sdio_slot0*)GetDeviceByName(std::string("/dev/sdio/slot0"));
	if (pDevice)
		pDevice->EventNotify();
}
int getFreeDeviceId()
{
	u32 i;
	for (i=0; i<IPC_MAX_FDS; i++)
	{
		if (g_FdMap[i] == NULL)
		{
			return i;
		}
	}
	return -1;
}

IWII_IPC_HLE_Device* GetDeviceByName(const std::string& _rDeviceName)
{
	TDeviceMap::const_iterator itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
		if (itr->second && itr->second->GetDeviceName() == _rDeviceName)
			return itr->second;
		++itr;
	}

	return NULL;
}

IWII_IPC_HLE_Device* AccessDeviceByID(u32 _ID)
{
	if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
		return g_DeviceMap[_ID];

		return NULL;
}

// 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
	IWII_IPC_HLE_Device* pDevice = NULL;

	INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
	pDevice = new CWII_IPC_HLE_Device_FileIO(_DeviceID, _rDeviceName);

	return pDevice;
}


void DoState(PointerWrap &p)
{
	std::lock_guard<std::mutex> lk(s_reply_queue);

	p.Do(request_queue);
	p.Do(reply_queue);
	p.Do(last_reply_time);

	TDeviceMap::const_iterator itr;

	itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
			if (itr->second->IsHardware())
			{
				itr->second->DoState(p);
			}
			++itr;
	}

	if (p.GetMode() == PointerWrap::MODE_READ)
	{
		u32 i;
		for (i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = 0;
					p.Do(hwId);
					g_FdMap[i] = AccessDeviceByID(hwId);
				}
				else
				{
					g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
					g_FdMap[i]->DoState(p);
				}
			}
			else
			{
				g_FdMap[i] = NULL;
			}
		}
		for (i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);

			es_handles[i] = AccessDeviceByID(handleID);
		}
	}
	else
	{
		u32 i;
		for (i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = g_FdMap[i] ? 1 : 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = g_FdMap[i]->GetDeviceID();
					p.Do(hwId);
				}
				else
				{
					g_FdMap[i]->DoState(p);
				}
			}
		}
		for (i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);
		}
	}
}

void ExecuteCommand(u32 _Address)
{
	bool CmdSuccess = false;

	ECommandType Command = static_cast<ECommandType>(Memory::Read_U32(_Address));
	volatile s32 DeviceID = Memory::Read_U32(_Address + 8);

	IWII_IPC_HLE_Device* pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : NULL;

	INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice);

	switch (Command)
	{
	case COMMAND_OPEN_DEVICE:
	{
		u32 Mode = Memory::Read_U32(_Address + 0x10);
		DeviceID = getFreeDeviceId();

		std::string DeviceName;
		Memory::GetString(DeviceName, Memory::Read_U32(_Address + 0xC));


		WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
		if (DeviceID >= 0)
		{
			if (DeviceName.find("/dev/es") == 0)
			{
				u32 j;
				for (j=0; j<ES_MAX_COUNT; j++)
				{
					if (!es_inuse[j])
					{
						es_inuse[j] = true;
						g_FdMap[DeviceID] = es_handles[j];
						CmdSuccess = es_handles[j]->Open(_Address, Mode);
						Memory::Write_U32(DeviceID, _Address+4);
						break;
					}
				}
				if (j == ES_MAX_COUNT)
				{
					Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
					CmdSuccess = true;
				}

			}
			else if (DeviceName.find("/dev/") == 0)
			{
				pDevice = GetDeviceByName(DeviceName);
				if (pDevice)
				{
					g_FdMap[DeviceID] = pDevice;
					CmdSuccess = pDevice->Open(_Address, Mode);
					INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
					Memory::Write_U32(DeviceID, _Address+4);
				}
				else
				{
					WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
					Memory::Write_U32(FS_ENOENT, _Address+4);
					CmdSuccess = true;
				}
			}
			else
			{
				pDevice = CreateFileIO(DeviceID, DeviceName);
				CmdSuccess = pDevice->Open(_Address, Mode);

				INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
				if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
				{
					g_FdMap[DeviceID] = pDevice;
				}
				else
				{
					delete pDevice;
					pDevice = NULL;
				}
			}

		}
		else
		{
			Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case COMMAND_CLOSE_DEVICE:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Close(_Address);

			u32 j;
			for (j=0; j<ES_MAX_COUNT; j++)
			{
				if (es_handles[j] == g_FdMap[DeviceID])
				{
					es_inuse[j] = false;
				}
			}

			g_FdMap[DeviceID] = NULL;

			// Don't delete hardware
			if (!pDevice->IsHardware())
			{
				delete pDevice;
				pDevice = NULL;
			}
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case COMMAND_READ:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Read(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case COMMAND_WRITE:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Write(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case COMMAND_SEEK:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->Seek(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			CmdSuccess = true;
		}
		break;
	}
	case COMMAND_IOCTL:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->IOCtl(_Address);
		}
		break;
	}
	case COMMAND_IOCTLV:
	{
		if (pDevice)
		{
			CmdSuccess = pDevice->IOCtlV(_Address);
		}
		break;
	}
	default:
	{
		_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
		break;
	}
	}


	if (CmdSuccess)
	{
		// It seems that the original hardware overwrites the command after it has been
		// 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);

		// Ensure replies happen in order, fairly ugly
		// Without this, tons of games fail now that DI commands have different reply delays
		int reply_delay = pDevice ? pDevice->GetCmdDelay(_Address) : 0;

		const s64 ticks_til_last_reply = last_reply_time - CoreTiming::GetTicks();

		if (ticks_til_last_reply > 0)
			reply_delay = ticks_til_last_reply;

		last_reply_time = CoreTiming::GetTicks() + reply_delay;

		// Generate a reply to the IPC command
		EnqReply(_Address, reply_delay);
	}
}

// Happens AS SOON AS IPC gets a new pointer!
void EnqRequest(u32 _Address)
{
	request_queue.push_back(_Address);
}

// Called when IOS module has some reply
void EnqReply(u32 _Address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent(cycles_in_future, enque_reply, _Address);
}

// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
// Takes care of routing ipc <-> ipc HLE
void Update()
{
	if (!WII_IPCInterface::IsReady())
		return;

	UpdateDevices();

	if (request_queue.size())
	{
		WII_IPCInterface::GenerateAck(request_queue.front());
		INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
		u32 command = request_queue.front();
		request_queue.pop_front();
		ExecuteCommand(command);

#if MAX_LOGLEVEL >= DEBUG_LEVEL
		Dolphin_Debugger::PrintCallstack(LogTypes::WII_IPC_HLE, LogTypes::LDEBUG);
#endif
	}

	// lock due to using reply_queue
	{
		std::lock_guard<std::mutex> lk(s_reply_queue);
		if (reply_queue.size())
		{
			WII_IPCInterface::GenerateReply(reply_queue.front());
			INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
			reply_queue.pop_front();
		}
	}
}

void UpdateDevices()
{
	// Check if a hardware device must be updated
	for (TDeviceMap::const_iterator itr = g_DeviceMap.begin(); itr != g_DeviceMap.end(); ++itr)
	{
		if (itr->second->IsOpened() && itr->second->Update())
		{
			break;
		}
	}
}


} // end of namespace WII_IPC_HLE_Interface
Example #14
0
void DoState(PointerWrap &p)
{
	std::lock_guard<std::mutex> lk(s_reply_queue);

	p.Do(request_queue);
	p.Do(reply_queue);
	p.Do(last_reply_time);

	TDeviceMap::const_iterator itr;

	itr = g_DeviceMap.begin();
	while (itr != g_DeviceMap.end())
	{
			if (itr->second->IsHardware())
			{
				itr->second->DoState(p);
			}
			++itr;
	}

	if (p.GetMode() == PointerWrap::MODE_READ)
	{
		u32 i;
		for (i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = 0;
					p.Do(hwId);
					g_FdMap[i] = AccessDeviceByID(hwId);
				}
				else
				{
					g_FdMap[i] = new CWII_IPC_HLE_Device_FileIO(i, "");
					g_FdMap[i]->DoState(p);
				}
			}
			else
			{
				g_FdMap[i] = NULL;
			}
		}
		for (i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);

			es_handles[i] = AccessDeviceByID(handleID);
		}
	}
	else
	{
		u32 i;
		for (i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = g_FdMap[i] ? 1 : 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = g_FdMap[i]->IsHardware() ? 1 : 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = g_FdMap[i]->GetDeviceID();
					p.Do(hwId);
				}
				else
				{
					g_FdMap[i]->DoState(p);
				}
			}
		}
		for (i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);
		}
	}
}
Example #15
0
namespace WII_IPC_HLE_Interface
{

typedef std::map<u32, std::shared_ptr<IWII_IPC_HLE_Device>> TDeviceMap;
static TDeviceMap g_DeviceMap;

// STATE_TO_SAVE
#define IPC_MAX_FDS 0x18
#define ES_MAX_COUNT 2
static std::shared_ptr<IWII_IPC_HLE_Device> g_FdMap[IPC_MAX_FDS];
static bool es_inuse[ES_MAX_COUNT];
static std::shared_ptr<IWII_IPC_HLE_Device> es_handles[ES_MAX_COUNT];


typedef std::deque<u32> ipc_msg_queue;
static ipc_msg_queue request_queue; // ppc -> arm
static ipc_msg_queue reply_queue;   // arm -> ppc
static ipc_msg_queue ack_queue;   // arm -> ppc

static int event_enqueue;

static u64 last_reply_time;

static const u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL;
static const u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL;
static void EnqueueEvent(u64 userdata, int cycles_late = 0)
{
	if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG)
	{
		ack_queue.push_back((u32)userdata);
	}
	else if (userdata & ENQUEUE_REQUEST_FLAG)
	{
		request_queue.push_back((u32)userdata);
	}
	else
	{
		reply_queue.push_back((u32)userdata);
	}
	Update();
}

static u32 num_devices;

template <typename T>
std::shared_ptr<T> AddDevice(const char* deviceName)
{
	auto device = std::make_shared<T>(num_devices, deviceName);
	g_DeviceMap[num_devices] = device;
	num_devices++;
	return device;
}

void Init()
{
	bool Wee_speeak_support = SConfig::GetInstance().bWiiSpeakSupport;
	_dbg_assert_msg_(WII_IPC_HLE, g_DeviceMap.empty(), "DeviceMap isn't empty on init");
	CWII_IPC_HLE_Device_es::m_ContentFile = "";

	num_devices = 0;

	// Build hardware devices
	if (Wee_speeak_support)
	{
		AddDevice<CWII_IPC_HLE_Device_usb_oh0>("/dev/usb/oh0");
		AddDevice<CWII_IPC_HLE_Device_usb_ven>("/dev/usb/ven");
		AddDevice<CWII_IPC_HLE_Device_usb_oh0_57e_308>("/dev/usb/oh0/57e/308");
		AddDevice<CWII_IPC_HLE_Device_usb_oh0_46d_a03>("/dev/usb/oh0/46d/a03");
	}
	AddDevice<CWII_IPC_HLE_Device_usb_oh1_57e_305>("/dev/usb/oh1/57e/305");
	AddDevice<CWII_IPC_HLE_Device_stm_immediate>("/dev/stm/immediate");
	AddDevice<CWII_IPC_HLE_Device_stm_eventhook>("/dev/stm/eventhook");
	AddDevice<CWII_IPC_HLE_Device_fs>("/dev/fs");

	// IOS allows two ES devices at a time
	for (u32 j=0; j<ES_MAX_COUNT; j++)
	{
		es_handles[j] = AddDevice<CWII_IPC_HLE_Device_es>("/dev/es");
		es_inuse[j] = false;
	}

	AddDevice<CWII_IPC_HLE_Device_di>("/dev/di");
	AddDevice<CWII_IPC_HLE_Device_net_kd_request>("/dev/net/kd/request");
	AddDevice<CWII_IPC_HLE_Device_net_kd_time>("/dev/net/kd/time");
	AddDevice<CWII_IPC_HLE_Device_net_ncd_manage>("/dev/net/ncd/manage");
	AddDevice<CWII_IPC_HLE_Device_net_wd_command>("/dev/net/wd/command");
	AddDevice<CWII_IPC_HLE_Device_net_ip_top>("/dev/net/ip/top");
	AddDevice<CWII_IPC_HLE_Device_net_ssl>("/dev/net/ssl");
	AddDevice<CWII_IPC_HLE_Device_usb_kbd>("/dev/usb/kbd");
	AddDevice<CWII_IPC_HLE_Device_sdio_slot0>("/dev/sdio/slot0");
	AddDevice<CWII_IPC_HLE_Device_stub>("/dev/sdio/slot1");
	#if defined(__LIBUSB__) || defined(_WIN32)
		AddDevice<CWII_IPC_HLE_Device_hid>("/dev/usb/hid");
	#else
		AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/hid");
	#endif
	AddDevice<CWII_IPC_HLE_Device_stub>("/dev/usb/oh1");
	AddDevice<IWII_IPC_HLE_Device>("_Unimplemented_Device_");

	event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
}

void Reset(bool _bHard)
{
	CoreTiming::RemoveAllEvents(event_enqueue);

	for (auto& dev : g_FdMap)
	{
		if (dev && !dev->IsHardware())
		{
			// close all files and delete their resources
			dev->Close(0, true);
		}

		dev.reset();
	}

	for (bool& in_use : es_inuse)
	{
		in_use = false;
	}

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second)
		{
			// Force close
			entry.second->Close(0, true);
		}
	}

	if (_bHard)
	{
		g_DeviceMap.clear();
	}
	request_queue.clear();
	reply_queue.clear();

	last_reply_time = 0;
}

void Shutdown()
{
	Reset(true);
}

void SetDefaultContentFile(const std::string& _rFilename)
{
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second && entry.second->GetDeviceName().find("/dev/es") == 0)
		{
			static_cast<CWII_IPC_HLE_Device_es*>(entry.second.get())->LoadWAD(_rFilename);
		}
	}
}

void ES_DIVerify(u8 *_pTMD, u32 _sz)
{
	CWII_IPC_HLE_Device_es::ES_DIVerify(_pTMD, _sz);
}

void SDIO_EventNotify()
{
	auto pDevice = static_cast<CWII_IPC_HLE_Device_sdio_slot0*>(GetDeviceByName("/dev/sdio/slot0").get());
	if (pDevice)
		pDevice->EventNotify();
}

int getFreeDeviceId()
{
	for (u32 i=0; i<IPC_MAX_FDS; i++)
	{
		if (g_FdMap[i] == nullptr)
		{
			return i;
		}
	}

	return -1;
}

std::shared_ptr<IWII_IPC_HLE_Device> GetDeviceByName(const std::string& _rDeviceName)
{
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second && entry.second->GetDeviceName() == _rDeviceName)
		{
			return entry.second;
		}
	}

	return nullptr;
}

std::shared_ptr<IWII_IPC_HLE_Device> AccessDeviceByID(u32 _ID)
{
	if (g_DeviceMap.find(_ID) != g_DeviceMap.end())
	{
		return g_DeviceMap[_ID];
	}

	return nullptr;
}

// This is called from ExecuteCommand() COMMAND_OPEN_DEVICE
std::shared_ptr<IWII_IPC_HLE_Device> CreateFileIO(u32 _DeviceID, const std::string& _rDeviceName)
{
	// scan device name and create the right one
	INFO_LOG(WII_IPC_FILEIO, "IOP: Create FileIO %s", _rDeviceName.c_str());
	return std::make_shared<CWII_IPC_HLE_Device_FileIO>(_DeviceID, _rDeviceName);
}


void DoState(PointerWrap &p)
{
	p.Do(request_queue);
	p.Do(reply_queue);
	p.Do(last_reply_time);

	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second->IsHardware())
		{
			entry.second->DoState(p);
		}
	}

	if (p.GetMode() == PointerWrap::MODE_READ)
	{
		for (u32 i=0; i<IPC_MAX_FDS; i++)
		{
			u32 exists = 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = 0;
					p.Do(hwId);
					g_FdMap[i] = AccessDeviceByID(hwId);
				}
				else
				{
					g_FdMap[i] = std::make_shared<CWII_IPC_HLE_Device_FileIO>(i, "");
					g_FdMap[i]->DoState(p);
				}
			}
			else
			{
				g_FdMap[i].reset();
			}
		}

		for (u32 i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);

			es_handles[i] = AccessDeviceByID(handleID);
		}
	}
	else
	{
		for (auto& dev : g_FdMap)
		{
			u32 exists = dev ? 1 : 0;
			p.Do(exists);
			if (exists)
			{
				u32 isHw = dev->IsHardware() ? 1 : 0;
				p.Do(isHw);
				if (isHw)
				{
					u32 hwId = dev->GetDeviceID();
					p.Do(hwId);
				}
				else
				{
					dev->DoState(p);
				}
			}
		}

		for (u32 i=0; i<ES_MAX_COUNT; i++)
		{
			p.Do(es_inuse[i]);
			u32 handleID = es_handles[i]->GetDeviceID();
			p.Do(handleID);
		}
	}
}

void ExecuteCommand(u32 _Address)
{
	IPCCommandResult result = IWII_IPC_HLE_Device::GetNoReply();

	IPCCommandType Command = static_cast<IPCCommandType>(Memory::Read_U32(_Address));
	s32 DeviceID = Memory::Read_U32(_Address + 8);

	std::shared_ptr<IWII_IPC_HLE_Device> pDevice = (DeviceID >= 0 && DeviceID < IPC_MAX_FDS) ? g_FdMap[DeviceID] : nullptr;

	INFO_LOG(WII_IPC_HLE, "-->> Execute Command Address: 0x%08x (code: %x, device: %x) %p", _Address, Command, DeviceID, pDevice.get());

	switch (Command)
	{
	case IPC_CMD_OPEN:
	{
		u32 Mode = Memory::Read_U32(_Address + 0x10);
		DeviceID = getFreeDeviceId();

		std::string DeviceName = Memory::GetString(Memory::Read_U32(_Address + 0xC));

		WARN_LOG(WII_IPC_HLE, "Trying to open %s as %d", DeviceName.c_str(), DeviceID);
		if (DeviceID >= 0)
		{
			if (DeviceName.find("/dev/es") == 0)
			{
				u32 j;
				for (j=0; j<ES_MAX_COUNT; j++)
				{
					if (!es_inuse[j])
					{
						es_inuse[j] = true;
						g_FdMap[DeviceID] = es_handles[j];
						result = es_handles[j]->Open(_Address, Mode);
						Memory::Write_U32(DeviceID, _Address+4);
						break;
					}
				}

				if (j == ES_MAX_COUNT)
				{
					Memory::Write_U32(FS_EESEXHAUSTED, _Address + 4);
					result = IWII_IPC_HLE_Device::GetDefaultReply();
				}
			}
			else if (DeviceName.find("/dev/") == 0)
			{
				pDevice = GetDeviceByName(DeviceName);
				if (pDevice)
				{
					g_FdMap[DeviceID] = pDevice;
					result = pDevice->Open(_Address, Mode);
					INFO_LOG(WII_IPC_FILEIO, "IOP: ReOpen (Device=%s, DeviceID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
					Memory::Write_U32(DeviceID, _Address+4);
				}
				else
				{
					WARN_LOG(WII_IPC_HLE, "Unimplemented device: %s", DeviceName.c_str());
					Memory::Write_U32(FS_ENOENT, _Address+4);
					result = IWII_IPC_HLE_Device::GetDefaultReply();
				}
			}
			else
			{
				pDevice = CreateFileIO(DeviceID, DeviceName);
				result = pDevice->Open(_Address, Mode);

				INFO_LOG(WII_IPC_FILEIO, "IOP: Open File (Device=%s, ID=%08x, Mode=%i)",
						pDevice->GetDeviceName().c_str(), DeviceID, Mode);
				if (Memory::Read_U32(_Address + 4) == (u32)DeviceID)
				{
					g_FdMap[DeviceID] = pDevice;
				}
			}
		}
		else
		{
			Memory::Write_U32(FS_EFDEXHAUSTED, _Address + 4);
			result = IWII_IPC_HLE_Device::GetDefaultReply();
		}
		break;
	}
	case IPC_CMD_CLOSE:
	{
		if (pDevice)
		{
			result = pDevice->Close(_Address);

			for (u32 j=0; j<ES_MAX_COUNT; j++)
			{
				if (es_handles[j] == g_FdMap[DeviceID])
				{
					es_inuse[j] = false;
				}
			}

			g_FdMap[DeviceID].reset();
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			result = IWII_IPC_HLE_Device::GetDefaultReply();
		}
		break;
	}
	case IPC_CMD_READ:
	{
		if (pDevice)
		{
			result = pDevice->Read(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			result = IWII_IPC_HLE_Device::GetDefaultReply();
		}
		break;
	}
	case IPC_CMD_WRITE:
	{
		if (pDevice)
		{
			result = pDevice->Write(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			result = IWII_IPC_HLE_Device::GetDefaultReply();
		}
		break;
	}
	case IPC_CMD_SEEK:
	{
		if (pDevice)
		{
			result = pDevice->Seek(_Address);
		}
		else
		{
			Memory::Write_U32(FS_EINVAL, _Address + 4);
			result = IWII_IPC_HLE_Device::GetDefaultReply();
		}
		break;
	}
	case IPC_CMD_IOCTL:
	{
		if (pDevice)
		{
			result = pDevice->IOCtl(_Address);
		}
		break;
	}
	case IPC_CMD_IOCTLV:
	{
		if (pDevice)
		{
			result = pDevice->IOCtlV(_Address);
		}
		break;
	}
	default:
	{
		_dbg_assert_msg_(WII_IPC_HLE, 0, "Unknown IPC Command %i (0x%08x)", Command, _Address);
		break;
	}
	}

	// Ensure replies happen in order
	const s64 ticks_until_last_reply = last_reply_time - CoreTiming::GetTicks();
	if (ticks_until_last_reply > 0)
		result.reply_delay_ticks += ticks_until_last_reply;
	last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks;

	if (result.send_reply)
	{
		// The original hardware overwrites the command type with the async reply type.
		Memory::Write_U32(IPC_REP_ASYNC, _Address);
		// IOS also seems to write back the command that was responded to in the FD field.
		Memory::Write_U32(Command, _Address + 8);
		// Generate a reply to the IPC command
		EnqueueReply(_Address, (int)result.reply_delay_ticks);
	}
}

// Happens AS SOON AS IPC gets a new pointer!
void EnqueueRequest(u32 address)
{
	CoreTiming::ScheduleEvent(1000, event_enqueue, address | ENQUEUE_REQUEST_FLAG);
}

// Called when IOS module has some reply
// NOTE: Only call this if you have correctly handled
//       CommandAddress+0 and CommandAddress+8.
//       Please search for examples of this being called elsewhere.
void EnqueueReply(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue, address);
}

void EnqueueReply_Threadsafe(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent_Threadsafe(cycles_in_future, event_enqueue, address);
}

void EnqueueReply_Immediate(u32 address)
{
	EnqueueEvent(address);
}

void EnqueueCommandAcknowledgement(u32 address, int cycles_in_future)
{
	CoreTiming::ScheduleEvent(cycles_in_future, event_enqueue,
	                          address | ENQUEUE_ACKNOWLEDGEMENT_FLAG);
}

// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
// Takes care of routing ipc <-> ipc HLE
void Update()
{
	if (!WII_IPCInterface::IsReady())
		return;

	if (request_queue.size())
	{
		WII_IPCInterface::GenerateAck(request_queue.front());
		INFO_LOG(WII_IPC_HLE, "||-- Acknowledge IPC Request @ 0x%08x", request_queue.front());
		u32 command = request_queue.front();
		request_queue.pop_front();
		ExecuteCommand(command);
		return;
	}

	if (reply_queue.size())
	{
		WII_IPCInterface::GenerateReply(reply_queue.front());
		INFO_LOG(WII_IPC_HLE, "<<-- Reply to IPC Request @ 0x%08x", reply_queue.front());
		reply_queue.pop_front();
		return;
	}

	if (ack_queue.size())
	{
		WII_IPCInterface::GenerateAck(ack_queue.front());
		WARN_LOG(WII_IPC_HLE, "<<-- Double-ack to IPC Request @ 0x%08x", ack_queue.front());
		ack_queue.pop_front();
		return;
	}
}

void UpdateDevices()
{
	// Check if a hardware device must be updated
	for (const auto& entry : g_DeviceMap)
	{
		if (entry.second->IsOpened())
		{
			entry.second->Update();
		}
	}
}


} // end of namespace WII_IPC_HLE_Interface