IOS: Check for available features when adding devices

Prevents resource managers that shouldn't be visible from being exposed
to titles.

This adds a new function to get features for an IOS version, and also
moves the version checks from the modules themselves to VersionInfo.
This hopefully documents some of the differences between IOS better
and should be slightly cleaner than having random version checks.
This commit is contained in:
Léo Lam 2017-08-19 15:55:10 +02:00
parent 24e7b465be
commit e4ea4da782
8 changed files with 143 additions and 52 deletions

View File

@ -345,33 +345,70 @@ void Kernel::AddStaticDevices()
{
std::lock_guard<std::mutex> lock(m_device_map_mutex);
const Feature features = GetFeatures(GetVersion());
// OH1 (Bluetooth)
AddDevice(std::make_unique<Device::Stub>(*this, "/dev/usb/oh1"));
if (!SConfig::GetInstance().m_bt_passthrough_enabled)
AddDevice(std::make_unique<Device::BluetoothEmu>(*this, "/dev/usb/oh1/57e/305"));
else
AddDevice(std::make_unique<Device::BluetoothReal>(*this, "/dev/usb/oh1/57e/305"));
// Other core modules
AddDevice(std::make_unique<Device::STMImmediate>(*this, "/dev/stm/immediate"));
AddDevice(std::make_unique<Device::STMEventHook>(*this, "/dev/stm/eventhook"));
AddDevice(std::make_unique<Device::DI>(*this, "/dev/di"));
AddDevice(std::make_unique<Device::NetKDRequest>(*this, "/dev/net/kd/request"));
AddDevice(std::make_unique<Device::NetKDTime>(*this, "/dev/net/kd/time"));
AddDevice(std::make_unique<Device::NetNCDManage>(*this, "/dev/net/ncd/manage"));
AddDevice(std::make_unique<Device::NetWDCommand>(*this, "/dev/net/wd/command"));
AddDevice(std::make_unique<Device::NetIPTop>(*this, "/dev/net/ip/top"));
AddDevice(std::make_unique<Device::NetSSL>(*this, "/dev/net/ssl"));
AddDevice(std::make_unique<Device::USB_KBD>(*this, "/dev/usb/kbd"));
AddDevice(std::make_unique<Device::SDIOSlot0>(*this, "/dev/sdio/slot0"));
AddDevice(std::make_unique<Device::Stub>(*this, "/dev/sdio/slot1"));
if (GetVersion() == 59)
AddDevice(std::make_unique<Device::USB_HIDv5>(*this, "/dev/usb/hid"));
else
AddDevice(std::make_unique<Device::USB_HIDv4>(*this, "/dev/usb/hid"));
// Network modules
if (HasFeature(features, Feature::KD))
{
AddDevice(std::make_unique<Device::NetKDRequest>(*this, "/dev/net/kd/request"));
AddDevice(std::make_unique<Device::NetKDTime>(*this, "/dev/net/kd/time"));
}
if (HasFeature(features, Feature::NCD))
{
AddDevice(std::make_unique<Device::NetNCDManage>(*this, "/dev/net/ncd/manage"));
}
if (HasFeature(features, Feature::WiFi))
{
AddDevice(std::make_unique<Device::NetWDCommand>(*this, "/dev/net/wd/command"));
}
if (HasFeature(features, Feature::SO))
{
AddDevice(std::make_unique<Device::NetIPTop>(*this, "/dev/net/ip/top"));
}
if (HasFeature(features, Feature::SSL))
{
AddDevice(std::make_unique<Device::NetSSL>(*this, "/dev/net/ssl"));
}
// USB modules
// OH0 is unconditionally added because this device path is registered in all cases.
AddDevice(std::make_unique<Device::OH0>(*this, "/dev/usb/oh0"));
AddDevice(std::make_unique<Device::Stub>(*this, "/dev/usb/oh1"));
if (HasFeature(features, Feature::NewUSB))
{
AddDevice(std::make_unique<Device::USB_HIDv5>(*this, "/dev/usb/hid"));
AddDevice(std::make_unique<Device::USB_VEN>(*this, "/dev/usb/ven"));
// TODO(IOS): register /dev/usb/usb, /dev/usb/msc, /dev/usb/hub and /dev/usb/ehc
// as stubs that return IPC_EACCES.
}
else
{
if (HasFeature(features, Feature::USB_HIDv4))
AddDevice(std::make_unique<Device::USB_HIDv4>(*this, "/dev/usb/hid"));
if (HasFeature(features, Feature::USB_KBD))
AddDevice(std::make_unique<Device::USB_KBD>(*this, "/dev/usb/kbd"));
}
if (HasFeature(features, Feature::WFS))
{
AddDevice(std::make_unique<Device::WFSSRV>(*this, "/dev/usb/wfssrv"));
AddDevice(std::make_unique<Device::WFSI>(*this, "/dev/wfsi"));
}
}
s32 Kernel::GetFreeDeviceID()
{
@ -411,7 +448,8 @@ s32 Kernel::OpenDevice(OpenRequest& request)
request.fd = new_fd;
std::shared_ptr<Device::Device> device;
if (request.path.find("/dev/usb/oh0/") == 0 && !GetDeviceByName(request.path))
if (request.path.find("/dev/usb/oh0/") == 0 && !GetDeviceByName(request.path) &&
!HasFeature(GetVersion(), Feature::NewUSB))
{
device = std::make_shared<Device::OH0Device>(*this, request.path);
}

View File

@ -18,6 +18,7 @@
#include "Core/ConfigManager.h"
#include "Core/HW/Memmap.h"
#include "Core/IOS/IOS.h"
#include "Core/IOS/VersionInfo.h"
namespace IOS
{
@ -25,28 +26,8 @@ namespace HLE
{
namespace Device
{
constexpr bool SupportsSDHC(u32 ios_version)
{
switch (ios_version)
{
// Known versions to support SDHC
case 48:
case 56:
case 57:
case 58:
case 59:
case 60:
case 61:
case 70:
case 80:
return true;
default:
return false;
};
}
SDIOSlot0::SDIOSlot0(Kernel& ios, const std::string& device_name)
: Device(ios, device_name), m_sdhc_supported(SupportsSDHC(ios.GetVersion()))
: Device(ios, device_name), m_sdhc_supported(HasFeature(ios.GetVersion(), Feature::SDv2))
{
}

View File

@ -18,6 +18,7 @@
#include "Core/HW/Memmap.h"
#include "Core/IOS/USB/Common.h"
#include "Core/IOS/USB/USBV0.h"
#include "Core/IOS/VersionInfo.h"
namespace IOS
{
@ -36,8 +37,7 @@ OH0::~OH0()
ReturnCode OH0::Open(const OpenRequest& request)
{
const u32 ios_major_version = m_ios.GetVersion();
if (ios_major_version == 57 || ios_major_version == 58 || ios_major_version == 59)
if (HasFeature(m_ios.GetVersion(), Feature::NewUSB))
return IPC_EACCES;
return USBHost::Open(request);
}

View File

@ -57,10 +57,6 @@ void OH0Device::DoState(PointerWrap& p)
ReturnCode OH0Device::Open(const OpenRequest& request)
{
const u32 ios_major_version = m_ios.GetVersion();
if (ios_major_version == 57 || ios_major_version == 58 || ios_major_version == 59)
return IPC_ENOENT;
if (m_vid == 0 && m_pid == 0)
return IPC_ENOENT;

View File

@ -35,14 +35,6 @@ USB_VEN::~USB_VEN()
StopThreads();
}
ReturnCode USB_VEN::Open(const OpenRequest& request)
{
const u32 ios_major_version = m_ios.GetVersion();
if (ios_major_version != 57 && ios_major_version != 58 && ios_major_version != 59)
return IPC_ENOENT;
return USBHost::Open(request);
}
IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request)
{
request.Log(GetDeviceName(), LogTypes::IOS_USB);

View File

@ -31,7 +31,6 @@ public:
USB_VEN(Kernel& ios, const std::string& device_name);
~USB_VEN() override;
ReturnCode Open(const OpenRequest& request) override;
IPCCommandResult IOCtl(const IOCtlRequest& request) override;
IPCCommandResult IOCtlV(const IOCtlVRequest& request) override;

View File

@ -335,5 +335,44 @@ const std::array<MemoryValues, 41>& GetMemoryValues()
{
return ios_memory_values;
}
Feature GetFeatures(u32 version)
{
// Common features that are present in most versions.
Feature features = Feature::Core | Feature::SDIO | Feature::SO | Feature::Ethernet;
// IOS4 is a tiny IOS that was presumably used during manufacturing. It lacks network support.
if (version != 4)
features |= Feature::KD | Feature::SSL | Feature::NCD | Feature::WiFi;
if (version == 48 || (version >= 56 && version <= 62) || version == 70 || version == 80)
features |= Feature::SDv2;
if (version == 57 || version == 58 || version == 59)
features |= Feature::NewUSB;
if (version == 58 || version == 59)
features |= Feature::EHCI;
if (version == 59)
features |= Feature::WFS;
// No IOS earlier than IOS30 has USB_KBD. Any IOS with the new USB modules lacks this module.
// TODO(IOS): it is currently unknown which other versions don't have it.
if (version >= 30 && !HasFeature(features, Feature::NewUSB))
features |= Feature::USB_KBD;
// Just like KBD, USB_HIDv4 is not present on any IOS with the new USB modules
// (since it's been replaced with USB_HIDv5 there).
// Additionally, it appears that HIDv4 and KBD are never both present.
// TODO(IOS): figure out which versions have HIDv4. For now we just include both KBD and HIDv4.
if (!HasFeature(features, Feature::NewUSB))
features |= Feature::USB_HIDv4;
return features;
}
bool HasFeature(u32 major_version, Feature feature)
{
return HasFeature(GetFeatures(major_version), feature);
}
}
}

View File

@ -37,5 +37,51 @@ struct MemoryValues
};
const std::array<MemoryValues, 41>& GetMemoryValues();
enum class Feature
{
// Kernel, ES, FS, STM, DI, OH0, OH1
Core = 1 << 0,
// SDIO
SDIO = 1 << 1,
// Network (base support: SO, Ethernet; KD, SSL, NCD, Wi-Fi)
SO = 1 << 2,
Ethernet = 1 << 3,
KD = 1 << 4,
SSL = 1 << 5,
NCD = 1 << 6,
WiFi = 1 << 7,
// KBD
USB_KBD = 1 << 8,
// USB_HID v4
USB_HIDv4 = 1 << 9,
// SDv2 support
SDv2 = 1 << 10,
// New USB modules (USB, USB_VEN, USB_HUB, USB_MSC, OHCI0, USB_HIDv5)
NewUSB = 1 << 11,
// EHCI
EHCI = 1 << 12,
// WFS (WFSSRV, WFSI, USB_SHARED)
WFS = 1 << 13,
};
constexpr Feature operator|(Feature lhs, Feature rhs)
{
return static_cast<Feature>(static_cast<int>(lhs) | static_cast<int>(rhs));
}
constexpr Feature& operator|=(Feature& lhs, Feature rhs)
{
lhs = lhs | rhs;
return lhs;
}
constexpr bool HasFeature(Feature features, Feature feature)
{
return (static_cast<int>(features) & static_cast<int>(feature)) != 0;
}
bool HasFeature(u32 major_version, Feature feature);
Feature GetFeatures(u32 major_version);
}
}