2015-05-24 06:55:12 +02:00
|
|
|
// Copyright 2008 Dolphin Emulator Project
|
2015-05-18 01:08:10 +02:00
|
|
|
// Licensed under GPLv2+
|
2013-04-17 22:43:11 -04:00
|
|
|
// Refer to the license.txt file included.
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2017-01-05 01:10:03 +01:00
|
|
|
// This is the main Wii IPC file that handles all incoming IPC requests and directs them
|
|
|
|
// to the right function.
|
|
|
|
//
|
|
|
|
// IPC basics (IOS' usage):
|
|
|
|
// All IPC request handlers will write a return value to 0x04.
|
|
|
|
// Open: Device file descriptor or error code
|
|
|
|
// Close: IPC_SUCCESS
|
|
|
|
// Read: Bytes read
|
|
|
|
// Write: Bytes written
|
|
|
|
// Seek: Seek position
|
|
|
|
// Ioctl: Depends on the handler
|
|
|
|
// Ioctlv: Depends on the handler
|
|
|
|
// Replies may be sent immediately or asynchronously for ioctls and ioctlvs.
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-10-22 17:00:32 +02:00
|
|
|
#include <deque>
|
2014-02-19 13:09:14 -05:00
|
|
|
#include <map>
|
2016-10-22 17:00:32 +02:00
|
|
|
#include <memory>
|
2016-08-23 16:19:30 +02:00
|
|
|
#include <mutex>
|
2014-02-17 05:18:15 -05:00
|
|
|
#include <string>
|
2016-10-22 17:00:32 +02:00
|
|
|
#include <utility>
|
2015-12-19 17:52:10 -05:00
|
|
|
#include <vector>
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-10-22 17:00:32 +02:00
|
|
|
#include "Common/Assert.h"
|
2014-07-27 13:37:09 -04:00
|
|
|
#include "Common/ChunkFile.h"
|
2014-09-07 20:06:58 -05:00
|
|
|
#include "Common/CommonTypes.h"
|
2016-10-22 17:00:32 +02:00
|
|
|
#include "Common/Logging/Log.h"
|
2014-02-17 05:18:15 -05:00
|
|
|
#include "Core/ConfigManager.h"
|
2016-07-08 00:02:06 +02:00
|
|
|
#include "Core/Core.h"
|
2014-02-17 05:18:15 -05:00
|
|
|
#include "Core/CoreTiming.h"
|
|
|
|
#include "Core/HW/Memmap.h"
|
|
|
|
#include "Core/HW/WII_IPC.h"
|
2017-01-18 13:50:28 +01:00
|
|
|
#include "Core/IOS/DI/DI.h"
|
|
|
|
#include "Core/IOS/Device.h"
|
|
|
|
#include "Core/IOS/DeviceStub.h"
|
|
|
|
#include "Core/IOS/ES/ES.h"
|
|
|
|
#include "Core/IOS/FS/FS.h"
|
|
|
|
#include "Core/IOS/FS/FileIO.h"
|
|
|
|
#include "Core/IOS/IPC.h"
|
|
|
|
#include "Core/IOS/Network/Net.h"
|
|
|
|
#include "Core/IOS/Network/SSL.h"
|
|
|
|
#include "Core/IOS/SDIO/SDIOSlot0.h"
|
|
|
|
#include "Core/IOS/STM/STM.h"
|
|
|
|
#include "Core/IOS/USB/Bluetooth/BTEmu.h"
|
|
|
|
#include "Core/IOS/USB/Bluetooth/BTReal.h"
|
|
|
|
#include "Core/IOS/USB/USB_KBD.h"
|
|
|
|
#include "Core/IOS/USB/USB_VEN.h"
|
|
|
|
#include "Core/IOS/WFS/WFSI.h"
|
|
|
|
#include "Core/IOS/WFS/WFSSRV.h"
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-10-22 17:00:32 +02:00
|
|
|
namespace CoreTiming
|
|
|
|
{
|
|
|
|
struct EventType;
|
|
|
|
} // namespace CoreTiming
|
|
|
|
|
2016-09-07 23:39:46 +02:00
|
|
|
#if defined(__LIBUSB__)
|
2017-01-18 13:50:28 +01:00
|
|
|
#include "Core/IOS/USB/USB_HIDv4.h"
|
2012-12-30 16:57:37 +13:00
|
|
|
#endif
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2017-01-17 15:01:30 -05:00
|
|
|
namespace IOS
|
|
|
|
{
|
|
|
|
namespace HLE
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
static std::map<u32, std::shared_ptr<Device::Device>> s_device_map;
|
2016-10-03 01:08:50 +02:00
|
|
|
static std::mutex s_device_map_mutex;
|
2008-12-08 05:30:24 +00:00
|
|
|
|
|
|
|
// STATE_TO_SAVE
|
2017-01-05 00:41:42 +01:00
|
|
|
constexpr u8 IPC_MAX_FDS = 0x18;
|
2017-01-08 20:54:13 +01:00
|
|
|
constexpr u8 ES_MAX_COUNT = 3;
|
2017-01-18 20:27:51 +01:00
|
|
|
static std::shared_ptr<Device::Device> s_fdmap[IPC_MAX_FDS];
|
|
|
|
static std::shared_ptr<Device::ES> s_es_handles[ES_MAX_COUNT];
|
2012-03-18 21:00:23 +13:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
using IPCMsgQueue = std::deque<u32>;
|
|
|
|
static IPCMsgQueue s_request_queue; // ppc -> arm
|
|
|
|
static IPCMsgQueue s_reply_queue; // arm -> ppc
|
|
|
|
static IPCMsgQueue s_ack_queue; // arm -> ppc
|
2010-03-23 03:32:19 +00:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
static CoreTiming::EventType* s_event_enqueue;
|
|
|
|
static CoreTiming::EventType* s_event_sdio_notify;
|
2013-02-01 20:53:05 -06:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
static u64 s_last_reply_time;
|
2013-02-08 16:20:15 -06:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
static constexpr u64 ENQUEUE_REQUEST_FLAG = 0x100000000ULL;
|
|
|
|
static constexpr u64 ENQUEUE_ACKNOWLEDGEMENT_FLAG = 0x200000000ULL;
|
2016-04-10 02:06:09 +12:00
|
|
|
static void EnqueueEvent(u64 userdata, s64 cycles_late = 0)
|
2013-02-01 20:53:05 -06:00
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
if (userdata & ENQUEUE_ACKNOWLEDGEMENT_FLAG)
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
s_ack_queue.push_back(static_cast<u32>(userdata));
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
else if (userdata & ENQUEUE_REQUEST_FLAG)
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
s_request_queue.push_back(static_cast<u32>(userdata));
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
s_reply_queue.push_back(static_cast<u32>(userdata));
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
Update();
|
2013-02-01 20:53:05 -06:00
|
|
|
}
|
|
|
|
|
2016-07-18 19:30:47 +02:00
|
|
|
static void SDIO_EventNotify_CPUThread(u64 userdata, s64 cycles_late)
|
2016-07-08 00:02:06 +02:00
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
auto device = static_cast<Device::SDIOSlot0*>(GetDeviceByName("/dev/sdio/slot0").get());
|
2016-07-08 00:02:06 +02:00
|
|
|
if (device)
|
|
|
|
device->EventNotify();
|
|
|
|
}
|
|
|
|
|
2015-06-24 04:50:02 +12:00
|
|
|
static u32 num_devices;
|
|
|
|
|
|
|
|
template <typename T>
|
2016-10-03 01:08:50 +02:00
|
|
|
std::shared_ptr<T> AddDevice(const char* device_name)
|
2015-06-24 04:50:02 +12:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
auto device = std::make_shared<T>(num_devices, device_name);
|
2017-01-18 20:27:51 +01:00
|
|
|
_assert_(device->GetDeviceType() == Device::Device::DeviceType::Static);
|
2016-10-03 01:08:50 +02:00
|
|
|
s_device_map[num_devices] = device;
|
2016-06-24 10:43:46 +02:00
|
|
|
num_devices++;
|
|
|
|
return device;
|
2015-06-24 04:50:02 +12:00
|
|
|
}
|
|
|
|
|
2016-09-06 02:59:22 +00:00
|
|
|
void Reinit()
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
2017-01-18 20:38:44 +01:00
|
|
|
_assert_msg_(IOS, s_device_map.empty(), "Reinit called while already initialized");
|
2017-01-18 20:27:51 +01:00
|
|
|
Device::ES::m_ContentFile = "";
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
num_devices = 0;
|
|
|
|
|
|
|
|
// Build hardware devices
|
2016-08-23 16:19:30 +02:00
|
|
|
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::BluetoothEmu>("/dev/usb/oh1/57e/305");
|
2016-08-23 16:19:30 +02:00
|
|
|
else
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::BluetoothReal>("/dev/usb/oh1/57e/305");
|
2016-08-23 16:19:30 +02:00
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::STMImmediate>("/dev/stm/immediate");
|
|
|
|
AddDevice<Device::STMEventHook>("/dev/stm/eventhook");
|
|
|
|
AddDevice<Device::FS>("/dev/fs");
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
// IOS allows two ES devices at a time
|
2016-12-05 22:31:51 +01:00
|
|
|
for (auto& es_device : s_es_handles)
|
2017-01-18 20:27:51 +01:00
|
|
|
es_device = AddDevice<Device::ES>("/dev/es");
|
|
|
|
|
|
|
|
AddDevice<Device::DI>("/dev/di");
|
|
|
|
AddDevice<Device::NetKDRequest>("/dev/net/kd/request");
|
|
|
|
AddDevice<Device::NetKDTime>("/dev/net/kd/time");
|
|
|
|
AddDevice<Device::NetNCDManage>("/dev/net/ncd/manage");
|
|
|
|
AddDevice<Device::NetWDCommand>("/dev/net/wd/command");
|
|
|
|
AddDevice<Device::NetIPTop>("/dev/net/ip/top");
|
|
|
|
AddDevice<Device::NetSSL>("/dev/net/ssl");
|
|
|
|
AddDevice<Device::USB_KBD>("/dev/usb/kbd");
|
|
|
|
AddDevice<Device::USB_VEN>("/dev/usb/ven");
|
|
|
|
AddDevice<Device::SDIOSlot0>("/dev/sdio/slot0");
|
|
|
|
AddDevice<Device::Stub>("/dev/sdio/slot1");
|
2016-09-07 23:39:46 +02:00
|
|
|
#if defined(__LIBUSB__)
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::USB_HIDv4>("/dev/usb/hid");
|
2016-06-24 10:43:46 +02:00
|
|
|
#else
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::Stub>("/dev/usb/hid");
|
2016-06-24 10:43:46 +02:00
|
|
|
#endif
|
2017-01-18 20:27:51 +01:00
|
|
|
AddDevice<Device::Stub>("/dev/usb/oh1");
|
|
|
|
AddDevice<Device::WFSSRV>("/dev/usb/wfssrv");
|
|
|
|
AddDevice<Device::WFSI>("/dev/wfsi");
|
2016-09-06 02:59:22 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Init()
|
|
|
|
{
|
|
|
|
Reinit();
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
s_event_enqueue = CoreTiming::RegisterEvent("IPCEvent", EnqueueEvent);
|
|
|
|
s_event_sdio_notify = CoreTiming::RegisterEvent("SDIO_EventNotify", SDIO_EventNotify_CPUThread);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
void Reset(bool hard)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
CoreTiming::RemoveAllEvents(s_event_enqueue);
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2017-01-11 14:47:02 +01:00
|
|
|
// Close all devices that were opened and delete their resources
|
|
|
|
for (auto& device : s_fdmap)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-11 14:47:02 +01:00
|
|
|
if (!device)
|
|
|
|
continue;
|
2017-01-15 01:43:00 +01:00
|
|
|
device->Close();
|
2017-01-11 14:47:02 +01:00
|
|
|
device.reset();
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
|
2017-01-11 14:47:02 +01:00
|
|
|
if (hard)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
2017-01-11 14:47:02 +01:00
|
|
|
s_device_map.clear();
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2016-08-23 16:19:30 +02:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
s_request_queue.clear();
|
|
|
|
s_reply_queue.clear();
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
s_last_reply_time = 0;
|
2009-02-24 07:23:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
void Shutdown()
|
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
Reset(true);
|
2009-02-27 23:44:15 +00:00
|
|
|
}
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
void SetDefaultContentFile(const std::string& file_name)
|
2009-02-27 23:44:15 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
2017-01-11 14:47:02 +01:00
|
|
|
for (const auto& es : s_es_handles)
|
|
|
|
es->LoadWAD(file_name);
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2010-09-14 12:32:02 +00:00
|
|
|
|
2015-12-19 17:52:10 -05:00
|
|
|
void ES_DIVerify(const std::vector<u8>& tmd)
|
2010-09-07 06:06:08 +00:00
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
Device::ES::ES_DIVerify(tmd);
|
2010-09-07 06:06:08 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2011-02-11 00:31:37 +00:00
|
|
|
void SDIO_EventNotify()
|
|
|
|
{
|
2016-07-08 00:02:06 +02:00
|
|
|
// TODO: Potential race condition: If IsRunning() becomes false after
|
|
|
|
// it's checked, an event may be scheduled after CoreTiming shuts down.
|
|
|
|
if (SConfig::GetInstance().bWii && Core::IsRunning())
|
2016-10-03 01:08:50 +02:00
|
|
|
CoreTiming::ScheduleEvent(0, s_event_sdio_notify, 0, CoreTiming::FromThread::NON_CPU);
|
2011-02-11 00:31:37 +00:00
|
|
|
}
|
2014-02-24 08:58:22 -05:00
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
static int GetFreeDeviceID()
|
2012-03-18 21:00:23 +13:00
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
for (u32 i = 0; i < IPC_MAX_FDS; i++)
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
if (s_fdmap[i] == nullptr)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
return i;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return -1;
|
2012-03-18 21:00:23 +13:00
|
|
|
}
|
2011-02-11 00:31:37 +00:00
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
std::shared_ptr<Device::Device> GetDeviceByName(const std::string& device_name)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
|
|
|
for (const auto& entry : s_device_map)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
if (entry.second && entry.second->GetDeviceName() == device_name)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
return entry.second;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return nullptr;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
std::shared_ptr<Device::Device> AccessDeviceByID(u32 id)
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
std::lock_guard<std::mutex> lock(s_device_map_mutex);
|
|
|
|
if (s_device_map.find(id) != s_device_map.end())
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
return s_device_map[id];
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2016-06-24 10:43:46 +02:00
|
|
|
return nullptr;
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2016-06-24 10:43:46 +02:00
|
|
|
void DoState(PointerWrap& p)
|
2009-11-24 05:03:47 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
p.Do(s_request_queue);
|
|
|
|
p.Do(s_reply_queue);
|
|
|
|
p.Do(s_last_reply_time);
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
// We need to make sure all file handles are closed so IOS::HLE::Device::FS::DoState can
|
2016-06-24 10:43:46 +02:00
|
|
|
// successfully save or re-create /tmp
|
2016-10-03 01:08:50 +02:00
|
|
|
for (auto& descriptor : s_fdmap)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
if (descriptor)
|
|
|
|
descriptor->PrepareForState(p.GetMode());
|
|
|
|
}
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
for (const auto& entry : s_device_map)
|
2016-12-28 19:26:27 +01:00
|
|
|
entry.second->DoState(p);
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
if (p.GetMode() == PointerWrap::MODE_READ)
|
|
|
|
{
|
|
|
|
for (u32 i = 0; i < IPC_MAX_FDS; i++)
|
|
|
|
{
|
|
|
|
u32 exists = 0;
|
|
|
|
p.Do(exists);
|
|
|
|
if (exists)
|
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
auto device_type = Device::Device::DeviceType::Static;
|
2016-12-28 19:26:27 +01:00
|
|
|
p.Do(device_type);
|
|
|
|
switch (device_type)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
case Device::Device::DeviceType::Static:
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-12-28 19:26:27 +01:00
|
|
|
u32 device_id = 0;
|
|
|
|
p.Do(device_id);
|
|
|
|
s_fdmap[i] = AccessDeviceByID(device_id);
|
|
|
|
break;
|
|
|
|
}
|
2017-01-18 20:27:51 +01:00
|
|
|
case Device::Device::DeviceType::FileIO:
|
|
|
|
s_fdmap[i] = std::make_shared<Device::FileIO>(i, "");
|
2016-10-03 01:08:50 +02:00
|
|
|
s_fdmap[i]->DoState(p);
|
2016-12-28 19:26:27 +01:00
|
|
|
break;
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 22:31:51 +01:00
|
|
|
for (auto& es_device : s_es_handles)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-12-05 22:31:51 +01:00
|
|
|
const u32 handle_id = es_device->GetDeviceID();
|
|
|
|
p.Do(handle_id);
|
2017-01-18 20:27:51 +01:00
|
|
|
es_device = std::static_pointer_cast<Device::ES>(AccessDeviceByID(handle_id));
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
for (auto& descriptor : s_fdmap)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
u32 exists = descriptor ? 1 : 0;
|
|
|
|
p.Do(exists);
|
|
|
|
if (exists)
|
|
|
|
{
|
2016-12-28 19:26:27 +01:00
|
|
|
auto device_type = descriptor->GetDeviceType();
|
|
|
|
p.Do(device_type);
|
2017-01-18 20:27:51 +01:00
|
|
|
if (device_type == Device::Device::DeviceType::Static)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
u32 hwId = descriptor->GetDeviceID();
|
|
|
|
p.Do(hwId);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
descriptor->DoState(p);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2016-12-05 22:31:51 +01:00
|
|
|
for (const auto& es_device : s_es_handles)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-12-05 22:31:51 +01:00
|
|
|
const u32 handle_id = es_device->GetDeviceID();
|
|
|
|
p.Do(handle_id);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
|
|
|
}
|
2009-11-24 05:03:47 +00:00
|
|
|
}
|
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
static std::shared_ptr<Device::Device> GetUnusedESDevice()
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2016-12-05 22:31:51 +01:00
|
|
|
const auto iterator = std::find_if(std::begin(s_es_handles), std::end(s_es_handles),
|
|
|
|
[](const auto& es_device) { return !es_device->IsOpened(); });
|
|
|
|
return (iterator != std::end(s_es_handles)) ? *iterator : nullptr;
|
2016-12-03 22:23:15 +01:00
|
|
|
}
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2016-12-03 22:23:15 +01:00
|
|
|
// Returns the FD for the newly opened device (on success) or an error code.
|
2017-01-15 01:43:00 +01:00
|
|
|
static s32 OpenDevice(const IOSOpenRequest& request)
|
2016-12-03 22:23:15 +01:00
|
|
|
{
|
|
|
|
const s32 new_fd = GetFreeDeviceID();
|
2017-01-18 20:38:44 +01:00
|
|
|
INFO_LOG(IOS, "Opening %s (mode %d, fd %d)", request.path.c_str(), request.flags, new_fd);
|
2016-12-03 22:23:15 +01:00
|
|
|
if (new_fd < 0 || new_fd >= IPC_MAX_FDS)
|
|
|
|
{
|
2017-01-18 20:38:44 +01:00
|
|
|
ERROR_LOG(IOS, "Couldn't get a free fd, too many open files");
|
2016-12-03 22:23:15 +01:00
|
|
|
return FS_EFDEXHAUSTED;
|
|
|
|
}
|
2016-06-24 10:43:46 +02:00
|
|
|
|
2017-01-18 20:27:51 +01:00
|
|
|
std::shared_ptr<Device::Device> device;
|
2017-01-15 01:43:00 +01:00
|
|
|
if (request.path == "/dev/es")
|
2016-12-03 22:23:15 +01:00
|
|
|
{
|
|
|
|
device = GetUnusedESDevice();
|
|
|
|
if (!device)
|
2016-12-09 20:29:12 +01:00
|
|
|
return IPC_EESEXHAUSTED;
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2017-01-15 01:43:00 +01:00
|
|
|
else if (request.path.find("/dev/") == 0)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-15 01:43:00 +01:00
|
|
|
device = GetDeviceByName(request.path);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2017-01-15 01:43:00 +01:00
|
|
|
else if (request.path.find('/') == 0)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-18 20:27:51 +01:00
|
|
|
device = std::make_shared<Device::FileIO>(new_fd, request.path);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2016-12-03 22:23:15 +01:00
|
|
|
|
|
|
|
if (!device)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-18 20:38:44 +01:00
|
|
|
ERROR_LOG(IOS, "Unknown device: %s", request.path.c_str());
|
2016-12-09 20:29:12 +01:00
|
|
|
return IPC_ENOENT;
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2016-12-03 22:23:15 +01:00
|
|
|
|
2017-01-15 01:43:00 +01:00
|
|
|
const IOSReturnCode code = device->Open(request);
|
|
|
|
if (code < IPC_SUCCESS)
|
|
|
|
return code;
|
2016-12-03 22:23:15 +01:00
|
|
|
s_fdmap[new_fd] = device;
|
|
|
|
return new_fd;
|
|
|
|
}
|
|
|
|
|
2017-01-15 01:43:00 +01:00
|
|
|
static IPCCommandResult HandleCommand(const IOSRequest& request)
|
2016-12-03 22:23:15 +01:00
|
|
|
{
|
2017-01-15 01:43:00 +01:00
|
|
|
if (request.command == IPC_CMD_OPEN)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-15 01:43:00 +01:00
|
|
|
IOSOpenRequest open_request{request.address};
|
|
|
|
const s32 new_fd = OpenDevice(open_request);
|
2017-01-18 20:27:51 +01:00
|
|
|
return Device::Device::GetDefaultReply(new_fd);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2016-12-03 22:23:15 +01:00
|
|
|
|
2017-01-15 01:43:00 +01:00
|
|
|
const auto device = (request.fd < IPC_MAX_FDS) ? s_fdmap[request.fd] : nullptr;
|
2016-12-03 22:23:15 +01:00
|
|
|
if (!device)
|
2017-01-18 20:27:51 +01:00
|
|
|
return Device::Device::GetDefaultReply(IPC_EINVAL);
|
2016-12-03 22:23:15 +01:00
|
|
|
|
2017-01-15 01:43:00 +01:00
|
|
|
switch (request.command)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_CLOSE:
|
2017-01-15 01:43:00 +01:00
|
|
|
s_fdmap[request.fd].reset();
|
|
|
|
device->Close();
|
2017-01-18 20:27:51 +01:00
|
|
|
return Device::Device::GetDefaultReply(IPC_SUCCESS);
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_READ:
|
2017-01-15 01:43:00 +01:00
|
|
|
return device->Read(IOSReadWriteRequest{request.address});
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_WRITE:
|
2017-01-15 01:43:00 +01:00
|
|
|
return device->Write(IOSReadWriteRequest{request.address});
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_SEEK:
|
2017-01-15 01:43:00 +01:00
|
|
|
return device->Seek(IOSSeekRequest{request.address});
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_IOCTL:
|
2017-01-15 01:43:00 +01:00
|
|
|
return device->IOCtl(IOSIOCtlRequest{request.address});
|
2016-12-03 22:23:15 +01:00
|
|
|
case IPC_CMD_IOCTLV:
|
2017-01-15 01:43:00 +01:00
|
|
|
return device->IOCtlV(IOSIOCtlVRequest{request.address});
|
2016-06-24 10:43:46 +02:00
|
|
|
default:
|
2017-01-18 20:38:44 +01:00
|
|
|
_assert_msg_(IOS, false, "Unexpected command: %x", request.command);
|
2017-01-18 20:27:51 +01:00
|
|
|
return Device::Device::GetDefaultReply(IPC_EINVAL);
|
2016-06-24 10:43:46 +02:00
|
|
|
}
|
2016-12-03 22:23:15 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
void ExecuteCommand(const u32 address)
|
|
|
|
{
|
2017-01-15 01:43:00 +01:00
|
|
|
IOSRequest request{address};
|
|
|
|
IPCCommandResult result = HandleCommand(request);
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
// Ensure replies happen in order
|
2016-10-03 01:08:50 +02:00
|
|
|
const s64 ticks_until_last_reply = s_last_reply_time - CoreTiming::GetTicks();
|
2016-06-24 10:43:46 +02:00
|
|
|
if (ticks_until_last_reply > 0)
|
|
|
|
result.reply_delay_ticks += ticks_until_last_reply;
|
2016-10-03 01:08:50 +02:00
|
|
|
s_last_reply_time = CoreTiming::GetTicks() + result.reply_delay_ticks;
|
2016-06-24 10:43:46 +02:00
|
|
|
|
|
|
|
if (result.send_reply)
|
2017-01-17 00:28:22 +01:00
|
|
|
EnqueueReply(request, result.return_value, static_cast<int>(result.reply_delay_ticks));
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
|
|
|
|
2010-03-23 03:32:19 +00:00
|
|
|
// Happens AS SOON AS IPC gets a new pointer!
|
2014-06-13 20:28:06 -07:00
|
|
|
void EnqueueRequest(u32 address)
|
2010-03-23 03:32:19 +00:00
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
CoreTiming::ScheduleEvent(1000, s_event_enqueue, address | ENQUEUE_REQUEST_FLAG);
|
2010-03-23 03:32:19 +00:00
|
|
|
}
|
|
|
|
|
2016-10-21 17:47:02 +02:00
|
|
|
// Called to send a reply to an IOS syscall
|
2017-01-17 00:28:22 +01:00
|
|
|
void EnqueueReply(const IOSRequest& request, const s32 return_value, int cycles_in_future,
|
|
|
|
CoreTiming::FromThread from)
|
2010-03-23 03:32:19 +00:00
|
|
|
{
|
2017-01-17 00:28:22 +01:00
|
|
|
Memory::Write_U32(static_cast<u32>(return_value), request.address + 4);
|
2016-10-21 17:47:02 +02:00
|
|
|
// IOS writes back the command that was responded to in the FD field.
|
2017-01-15 01:43:00 +01:00
|
|
|
Memory::Write_U32(request.command, request.address + 8);
|
2016-12-03 22:53:47 +01:00
|
|
|
// IOS also overwrites the command type with the reply type.
|
2017-01-15 01:43:00 +01:00
|
|
|
Memory::Write_U32(IPC_REPLY, request.address);
|
|
|
|
CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue, request.address, from);
|
|
|
|
}
|
|
|
|
|
2014-05-28 18:46:34 -07:00
|
|
|
void EnqueueCommandAcknowledgement(u32 address, int cycles_in_future)
|
|
|
|
{
|
2016-10-03 01:08:50 +02:00
|
|
|
CoreTiming::ScheduleEvent(cycles_in_future, s_event_enqueue,
|
2016-06-24 10:43:46 +02:00
|
|
|
address | ENQUEUE_ACKNOWLEDGEMENT_FLAG);
|
2014-05-28 18:46:34 -07:00
|
|
|
}
|
|
|
|
|
2010-03-23 03:32:19 +00:00
|
|
|
// This is called every IPC_HLE_PERIOD from SystemTimers.cpp
|
|
|
|
// Takes care of routing ipc <-> ipc HLE
|
2009-11-24 05:03:47 +00:00
|
|
|
void Update()
|
2008-12-08 05:30:24 +00:00
|
|
|
{
|
2017-01-17 15:01:30 -05:00
|
|
|
if (!IsReady())
|
2016-06-24 10:43:46 +02:00
|
|
|
return;
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
if (s_request_queue.size())
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-17 15:01:30 -05:00
|
|
|
GenerateAck(s_request_queue.front());
|
2017-01-18 20:38:44 +01:00
|
|
|
DEBUG_LOG(IOS, "||-- Acknowledge IPC Request @ 0x%08x", s_request_queue.front());
|
2016-10-03 01:08:50 +02:00
|
|
|
u32 command = s_request_queue.front();
|
|
|
|
s_request_queue.pop_front();
|
2016-06-24 10:43:46 +02:00
|
|
|
ExecuteCommand(command);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
if (s_reply_queue.size())
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-17 15:01:30 -05:00
|
|
|
GenerateReply(s_reply_queue.front());
|
2017-01-18 20:38:44 +01:00
|
|
|
DEBUG_LOG(IOS, "<<-- Reply to IPC Request @ 0x%08x", s_reply_queue.front());
|
2016-10-03 01:08:50 +02:00
|
|
|
s_reply_queue.pop_front();
|
2016-06-24 10:43:46 +02:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2016-10-03 01:08:50 +02:00
|
|
|
if (s_ack_queue.size())
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
2017-01-17 15:01:30 -05:00
|
|
|
GenerateAck(s_ack_queue.front());
|
2017-01-18 20:38:44 +01:00
|
|
|
WARN_LOG(IOS, "<<-- Double-ack to IPC Request @ 0x%08x", s_ack_queue.front());
|
2016-10-03 01:08:50 +02:00
|
|
|
s_ack_queue.pop_front();
|
2016-06-24 10:43:46 +02:00
|
|
|
return;
|
|
|
|
}
|
2009-02-27 23:44:15 +00:00
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
|
2009-11-24 05:03:47 +00:00
|
|
|
void UpdateDevices()
|
2009-02-27 23:44:15 +00:00
|
|
|
{
|
2016-06-24 10:43:46 +02:00
|
|
|
// Check if a hardware device must be updated
|
2016-10-03 01:08:50 +02:00
|
|
|
for (const auto& entry : s_device_map)
|
2016-06-24 10:43:46 +02:00
|
|
|
{
|
|
|
|
if (entry.second->IsOpened())
|
|
|
|
{
|
|
|
|
entry.second->Update();
|
|
|
|
}
|
|
|
|
}
|
2008-12-08 05:30:24 +00:00
|
|
|
}
|
2017-01-17 15:01:30 -05:00
|
|
|
} // namespace HLE
|
|
|
|
} // namespace IOS
|