From 180ad8076cbc1d64077966f56a2381d83988f5c5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 2 Nov 2017 22:39:36 +0100 Subject: [PATCH] USB: Move common USBv5 IOS code to prepare for HIDv5 USBv5 IOS resource managers share most of their code. Some ioctls are even completely the same! So let's separate the common code from the VEN specific stuff to make HIDv5 easier to implement. --- Source/Core/Core/IOS/USB/USBV5.cpp | 238 +++++++++++++++++++++- Source/Core/Core/IOS/USB/USBV5.h | 59 ++++++ Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp | 243 +---------------------- Source/Core/Core/IOS/USB/USB_VEN/VEN.h | 48 +---- 4 files changed, 305 insertions(+), 283 deletions(-) diff --git a/Source/Core/Core/IOS/USB/USBV5.cpp b/Source/Core/Core/IOS/USB/USBV5.cpp index df81c11014..f0356d4bb6 100644 --- a/Source/Core/Core/IOS/USB/USBV5.cpp +++ b/Source/Core/Core/IOS/USB/USBV5.cpp @@ -4,13 +4,16 @@ #include "Core/IOS/USB/USBV5.h" +#include #include +#include #include -#include -#include "Common/CommonTypes.h" +#include "Common/ChunkFile.h" +#include "Common/Logging/Log.h" +#include "Common/Swap.h" +#include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" -#include "Core/IOS/Device.h" namespace IOS { @@ -53,5 +56,234 @@ V5IsoMessage::V5IsoMessage(Kernel& ios, const IOCtlVRequest& ioctlv) length = std::accumulate(packet_sizes.begin(), packet_sizes.end(), 0); } } // namespace USB + +namespace Device +{ +namespace +{ +#pragma pack(push, 1) +struct DeviceID +{ + u8 ipc_address_shifted; + u8 index; + u16 number; +}; + +struct DeviceEntry +{ + DeviceID id; + u16 vid; + u16 pid; + u16 number; + u8 interface_number; + u8 num_altsettings; +}; +#pragma pack(pop) +} + +USBV5ResourceManager::~USBV5ResourceManager() +{ + StopThreads(); +} + +void USBV5ResourceManager::DoState(PointerWrap& p) +{ + p.Do(m_devicechange_first_call); + u32 hook_address = m_devicechange_hook_request ? m_devicechange_hook_request->address : 0; + p.Do(hook_address); + if (hook_address != 0) + m_devicechange_hook_request = std::make_unique(hook_address); + else + m_devicechange_hook_request.reset(); + + p.Do(m_usbv5_devices); + USBHost::DoState(p); +} + +USBV5ResourceManager::USBV5Device* USBV5ResourceManager::GetUSBV5Device(u32 in_buffer) +{ + const u8 index = Memory::Read_U8(in_buffer + offsetof(DeviceID, index)); + const u16 number = Memory::Read_U16(in_buffer + offsetof(DeviceID, number)); + + if (index >= m_usbv5_devices.size()) + return nullptr; + + USBV5Device* usbv5_device = &m_usbv5_devices[index]; + if (!usbv5_device->in_use || usbv5_device->number != number) + return nullptr; + + return usbv5_device; +} + +IPCCommandResult USBV5ResourceManager::GetDeviceChange(const IOCtlRequest& request) +{ + if (request.buffer_out_size != 0x180 || m_devicechange_hook_request) + return GetDefaultReply(IPC_EINVAL); + + std::lock_guard lk{m_devicechange_hook_address_mutex}; + m_devicechange_hook_request = std::make_unique(request.address); + // On the first call, the reply is sent immediately (instead of on device insertion/removal) + if (m_devicechange_first_call) + { + TriggerDeviceChangeReply(); + m_devicechange_first_call = false; + } + return GetNoReply(); +} + +IPCCommandResult USBV5ResourceManager::SetAlternateSetting(USBV5Device& device, + const IOCtlRequest& request) +{ + const auto host_device = GetDeviceById(device.host_id); + if (!host_device->Attach(device.interface_number)) + return GetDefaultReply(-1); + + const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32)); + + const bool success = host_device->SetAltSetting(alt_setting) == 0; + return GetDefaultReply(success ? IPC_SUCCESS : IPC_EINVAL); +} + +IPCCommandResult USBV5ResourceManager::Shutdown(const IOCtlRequest& request) +{ + if (request.buffer_in != 0 || request.buffer_in_size != 0 || request.buffer_out != 0 || + request.buffer_out_size != 0) + { + return GetDefaultReply(IPC_EINVAL); + } + + std::lock_guard lk{m_devicechange_hook_address_mutex}; + if (m_devicechange_hook_request) + { + m_ios.EnqueueIPCReply(*m_devicechange_hook_request, IPC_SUCCESS); + m_devicechange_hook_request.reset(); + } + return GetDefaultReply(IPC_SUCCESS); +} + +IPCCommandResult USBV5ResourceManager::SuspendResume(USBV5Device& device, + const IOCtlRequest& request) +{ + const auto host_device = GetDeviceById(device.host_id); + const s32 resumed = Memory::Read_U32(request.buffer_in + 8); + + // Note: this is unimplemented because there's no easy way to do this in a + // platform-independant way (libusb does not support power management). + INFO_LOG(IOS_USB, "[%04x:%04x %d] Received %s command", host_device->GetVid(), + host_device->GetPid(), device.interface_number, resumed == 0 ? "suspend" : "resume"); + return GetDefaultReply(IPC_SUCCESS); +} + +s32 USBV5ResourceManager::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv) +{ + switch (ioctlv.request) + { + case USB::IOCTLV_USBV5_CTRLMSG: + return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); + case USB::IOCTLV_USBV5_INTRMSG: + return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); + case USB::IOCTLV_USBV5_BULKMSG: + return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); + case USB::IOCTLV_USBV5_ISOMSG: + return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); + default: + return IPC_EINVAL; + } +} + +IPCCommandResult USBV5ResourceManager::HandleDeviceIOCtl(const IOCtlRequest& request, + Handler handler) +{ + if (request.buffer_in == 0 || request.buffer_in_size != 0x20) + return GetDefaultReply(IPC_EINVAL); + + std::lock_guard lock{m_usbv5_devices_mutex}; + USBV5Device* device = GetUSBV5Device(request.buffer_in); + if (!device) + return GetDefaultReply(IPC_EINVAL); + return handler(*device); +} + +void USBV5ResourceManager::OnDeviceChange(const ChangeEvent event, + std::shared_ptr device) +{ + std::lock_guard lock{m_usbv5_devices_mutex}; + const u64 host_device_id = device->GetId(); + if (event == ChangeEvent::Inserted) + { + for (const auto& interface : device->GetInterfaces(0)) + { + if (interface.bAlternateSetting != 0) + continue; + + auto it = std::find_if(m_usbv5_devices.rbegin(), m_usbv5_devices.rend(), + [](const USBV5Device& entry) { return !entry.in_use; }); + if (it == m_usbv5_devices.rend()) + return; + + it->in_use = true; + it->interface_number = interface.bInterfaceNumber; + it->number = m_current_device_number; + it->host_id = host_device_id; + } + } + else if (event == ChangeEvent::Removed) + { + for (USBV5Device& entry : m_usbv5_devices) + { + if (entry.host_id == host_device_id) + entry.in_use = false; + } + } +} + +void USBV5ResourceManager::OnDeviceChangeEnd() +{ + std::lock_guard lk{m_devicechange_hook_address_mutex}; + TriggerDeviceChangeReply(); + ++m_current_device_number; +} + +// Must be called with m_devicechange_hook_address_mutex locked +void USBV5ResourceManager::TriggerDeviceChangeReply() +{ + if (!m_devicechange_hook_request) + return; + + std::lock_guard lock{m_usbv5_devices_mutex}; + u8 num_devices = 0; + for (auto it = m_usbv5_devices.crbegin(); it != m_usbv5_devices.crend(); ++it) + { + const USBV5Device& usbv5_device = *it; + if (!usbv5_device.in_use) + continue; + + const auto device = GetDeviceById(usbv5_device.host_id); + if (!device) + continue; + + DeviceEntry entry; + // The actual value is static_cast(hook_internal_ipc_request >> 8). + // Since we don't actually emulate the IOS kernel and internal IPC, + // just pretend the value is 0xe7 (most common value according to hwtests). + entry.id.ipc_address_shifted = 0xe7; + entry.id.index = static_cast(std::distance(m_usbv5_devices.cbegin(), it.base()) - 1); + entry.id.number = Common::swap16(usbv5_device.number); + entry.vid = Common::swap16(device->GetVid()); + entry.pid = Common::swap16(device->GetPid()); + entry.number = Common::swap16(usbv5_device.number); + entry.interface_number = usbv5_device.interface_number; + entry.num_altsettings = device->GetNumberOfAltSettings(entry.interface_number); + + Memory::CopyToEmu(m_devicechange_hook_request->buffer_out + sizeof(entry) * num_devices, &entry, + sizeof(entry)); + ++num_devices; + } + + m_ios.EnqueueIPCReply(*m_devicechange_hook_request, num_devices, 0, CoreTiming::FromThread::ANY); + m_devicechange_hook_request.reset(); + INFO_LOG(IOS_USB, "%d USBv5 device(s), including interfaces", num_devices); +} +} // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USBV5.h b/Source/Core/Core/IOS/USB/USBV5.h index 2db6c22110..47db9da9dc 100644 --- a/Source/Core/Core/IOS/USB/USBV5.h +++ b/Source/Core/Core/IOS/USB/USBV5.h @@ -4,8 +4,18 @@ #pragma once +#include +#include +#include +#include + #include "Common/CommonTypes.h" +#include "Core/IOS/Device.h" +#include "Core/IOS/IOS.h" #include "Core/IOS/USB/Common.h" +#include "Core/IOS/USB/Host.h" + +class PointerWrap; // Used by late USB interfaces for /dev/usb/ven and /dev/usb/hid (since IOS57 which // reorganised the USB modules in IOS). @@ -54,5 +64,54 @@ struct V5IsoMessage final : IsoMessage V5IsoMessage(Kernel& ios, const IOCtlVRequest& cmd_buffer); }; } // namespace USB + +namespace Device +{ +class USBV5ResourceManager : public USBHost +{ +public: + using USBHost::USBHost; + ~USBV5ResourceManager() override; + + IPCCommandResult IOCtl(const IOCtlRequest& request) override = 0; + IPCCommandResult IOCtlV(const IOCtlVRequest& request) override = 0; + + void DoState(PointerWrap& p) override; + +protected: + struct USBV5Device; + USBV5Device* GetUSBV5Device(u32 in_buffer); + + IPCCommandResult GetDeviceChange(const IOCtlRequest& request); + IPCCommandResult SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request); + IPCCommandResult Shutdown(const IOCtlRequest& request); + IPCCommandResult SuspendResume(USBV5Device& device, const IOCtlRequest& request); + s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& request); + + using Handler = std::function; + IPCCommandResult HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler); + + void OnDeviceChange(ChangeEvent event, std::shared_ptr device) override; + void OnDeviceChangeEnd() override; + void TriggerDeviceChangeReply(); + + bool m_devicechange_first_call = true; + std::mutex m_devicechange_hook_address_mutex; + std::unique_ptr m_devicechange_hook_request; + + // Each interface of a USB device is internally considered as a unique device. + // USBv5 resource managers can handle up to 32 devices/interfaces. + struct USBV5Device + { + bool in_use = false; + u8 interface_number = 0; + u16 number = 0; + u64 host_id = 0; + }; + std::array m_usbv5_devices{}; + mutable std::mutex m_usbv5_devices_mutex; + u16 m_current_device_number = 0x21; +}; +} // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp index 27fb03087d..fcc7e3792b 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp @@ -6,20 +6,13 @@ #include #include -#include #include #include -#include -#include "Common/ChunkFile.h" +#include "Common/CommonTypes.h" #include "Common/Logging/Log.h" -#include "Common/Swap.h" - -#include "Core/CoreTiming.h" #include "Core/HW/Memmap.h" -#include "Core/IOS/Device.h" #include "Core/IOS/USB/Common.h" -#include "Core/IOS/USB/USBV5.h" namespace IOS { @@ -27,38 +20,9 @@ namespace HLE { namespace Device { -namespace -{ -#pragma pack(push, 1) -struct DeviceID -{ - u8 ipc_address_shifted; - u8 index; - u16 number; -}; - -struct DeviceEntry -{ - DeviceID id; - u16 vid; - u16 pid; - u16 number; - u8 interface_number; - u8 num_altsettings; -}; -#pragma pack(pop) -} - constexpr u32 USBV5_VERSION = 0x50001; -USB_VEN::USB_VEN(Kernel& ios, const std::string& device_name) : USBHost(ios, device_name) -{ -} - -USB_VEN::~USB_VEN() -{ - StopThreads(); -} +USB_VEN::~USB_VEN() = default; ReturnCode USB_VEN::Open(const OpenRequest& request) { @@ -81,15 +45,17 @@ IPCCommandResult USB_VEN::IOCtl(const IOCtlRequest& request) case USB::IOCTL_USBV5_SHUTDOWN: return Shutdown(request); case USB::IOCTL_USBV5_GETDEVPARAMS: - return HandleDeviceIOCtl(request, &USB_VEN::GetDeviceInfo); + return HandleDeviceIOCtl(request, [&](auto& device) { return GetDeviceInfo(device, request); }); case USB::IOCTL_USBV5_ATTACHFINISH: return GetDefaultReply(IPC_SUCCESS); case USB::IOCTL_USBV5_SETALTERNATE: - return HandleDeviceIOCtl(request, &USB_VEN::SetAlternateSetting); + return HandleDeviceIOCtl(request, + [&](auto& device) { return SetAlternateSetting(device, request); }); case USB::IOCTL_USBV5_SUSPEND_RESUME: - return HandleDeviceIOCtl(request, &USB_VEN::SuspendResume); + return HandleDeviceIOCtl(request, [&](auto& device) { return SuspendResume(device, request); }); case USB::IOCTL_USBV5_CANCELENDPOINT: - return HandleDeviceIOCtl(request, &USB_VEN::CancelEndpoint); + return HandleDeviceIOCtl(request, + [&](auto& device) { return CancelEndpoint(device, request); }); default: request.DumpUnknown(GetDeviceName(), LogTypes::IOS_USB, LogTypes::LERROR); return GetDefaultReply(IPC_SUCCESS); @@ -129,35 +95,6 @@ IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request) } } -void USB_VEN::DoState(PointerWrap& p) -{ - p.Do(m_devicechange_first_call); - u32 hook_address = m_devicechange_hook_request ? m_devicechange_hook_request->address : 0; - p.Do(hook_address); - if (hook_address != 0) - m_devicechange_hook_request = std::make_unique(hook_address); - else - m_devicechange_hook_request.reset(); - - p.Do(m_usbv5_devices); - USBHost::DoState(p); -} - -USB_VEN::USBV5Device* USB_VEN::GetUSBV5Device(u32 in_buffer) -{ - const u8 index = Memory::Read_U8(in_buffer + offsetof(DeviceID, index)); - const u16 number = Memory::Read_U16(in_buffer + offsetof(DeviceID, number)); - - if (index >= m_usbv5_devices.size()) - return nullptr; - - USBV5Device* usbv5_device = &m_usbv5_devices[index]; - if (!usbv5_device->in_use || usbv5_device->number != number) - return nullptr; - - return usbv5_device; -} - IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request) { const u8 endpoint = static_cast(Memory::Read_U32(request.buffer_in + 8)); @@ -165,22 +102,6 @@ IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest return GetDefaultReply(IPC_SUCCESS); } -IPCCommandResult USB_VEN::GetDeviceChange(const IOCtlRequest& request) -{ - if (request.buffer_out_size != 0x180 || m_devicechange_hook_request) - return GetDefaultReply(IPC_EINVAL); - - std::lock_guard lk{m_devicechange_hook_address_mutex}; - m_devicechange_hook_request = std::make_unique(request.address); - // On the first call, the reply is sent immediately (instead of on device insertion/removal) - if (m_devicechange_first_call) - { - TriggerDeviceChangeReply(); - m_devicechange_first_call = false; - } - return GetNoReply(); -} - IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request) { if (request.buffer_out == 0 || request.buffer_out_size != 0xc0) @@ -222,154 +143,6 @@ IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& return GetDefaultReply(IPC_SUCCESS); } - -IPCCommandResult USB_VEN::SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request) -{ - const auto host_device = GetDeviceById(device.host_id); - if (!host_device->Attach(device.interface_number)) - return GetDefaultReply(-1); - - const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32)); - - const bool success = host_device->SetAltSetting(alt_setting) == 0; - return GetDefaultReply(success ? IPC_SUCCESS : IPC_EINVAL); -} - -IPCCommandResult USB_VEN::Shutdown(const IOCtlRequest& request) -{ - if (request.buffer_in != 0 || request.buffer_in_size != 0 || request.buffer_out != 0 || - request.buffer_out_size != 0) - { - return GetDefaultReply(IPC_EINVAL); - } - - std::lock_guard lk{m_devicechange_hook_address_mutex}; - if (m_devicechange_hook_request) - { - m_ios.EnqueueIPCReply(*m_devicechange_hook_request, IPC_SUCCESS); - m_devicechange_hook_request.reset(); - } - return GetDefaultReply(IPC_SUCCESS); -} - -IPCCommandResult USB_VEN::SuspendResume(USBV5Device& device, const IOCtlRequest& request) -{ - const auto host_device = GetDeviceById(device.host_id); - const s32 resumed = Memory::Read_U32(request.buffer_in + 8); - - // Note: this is unimplemented because there's no easy way to do this in a - // platform-independant way (libusb does not support power management). - INFO_LOG(IOS_USB, "[%04x:%04x %d] Received %s command", host_device->GetVid(), - host_device->GetPid(), device.interface_number, resumed == 0 ? "suspend" : "resume"); - return GetDefaultReply(IPC_SUCCESS); -} - -s32 USB_VEN::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv) -{ - switch (ioctlv.request) - { - case USB::IOCTLV_USBV5_CTRLMSG: - return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); - case USB::IOCTLV_USBV5_INTRMSG: - return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); - case USB::IOCTLV_USBV5_BULKMSG: - return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); - case USB::IOCTLV_USBV5_ISOMSG: - return device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); - default: - return IPC_EINVAL; - } -} - -IPCCommandResult USB_VEN::HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler) -{ - if (request.buffer_in == 0 || request.buffer_in_size != 0x20) - return GetDefaultReply(IPC_EINVAL); - - std::lock_guard lock{m_usbv5_devices_mutex}; - USBV5Device* device = GetUSBV5Device(request.buffer_in); - if (!device) - return GetDefaultReply(IPC_EINVAL); - return handler(this, *device, request); -} - -void USB_VEN::OnDeviceChange(const ChangeEvent event, std::shared_ptr device) -{ - std::lock_guard lock{m_usbv5_devices_mutex}; - const u64 host_device_id = device->GetId(); - if (event == ChangeEvent::Inserted) - { - for (const auto& interface : device->GetInterfaces(0)) - { - if (interface.bAlternateSetting != 0) - continue; - - auto it = std::find_if(m_usbv5_devices.rbegin(), m_usbv5_devices.rend(), - [](const USBV5Device& entry) { return !entry.in_use; }); - if (it == m_usbv5_devices.rend()) - return; - - it->in_use = true; - it->interface_number = interface.bInterfaceNumber; - it->number = m_current_device_number; - it->host_id = host_device_id; - } - } - else if (event == ChangeEvent::Removed) - { - for (USBV5Device& entry : m_usbv5_devices) - { - if (entry.host_id == host_device_id) - entry.in_use = false; - } - } -} - -void USB_VEN::OnDeviceChangeEnd() -{ - std::lock_guard lk{m_devicechange_hook_address_mutex}; - TriggerDeviceChangeReply(); - ++m_current_device_number; -} - -void USB_VEN::TriggerDeviceChangeReply() -{ - if (!m_devicechange_hook_request) - return; - - std::lock_guard lock{m_usbv5_devices_mutex}; - u8 num_devices = 0; - for (auto it = m_usbv5_devices.crbegin(); it != m_usbv5_devices.crend(); ++it) - { - const USBV5Device& usbv5_device = *it; - if (!usbv5_device.in_use) - continue; - - const auto device = GetDeviceById(usbv5_device.host_id); - if (!device) - continue; - - DeviceEntry entry; - // The actual value is static_cast(hook_internal_ipc_request >> 8). - // Since we don't actually emulate the IOS kernel and internal IPC, - // just pretend the value is 0xe7 (most common value according to hwtests). - entry.id.ipc_address_shifted = 0xe7; - entry.id.index = static_cast(std::distance(m_usbv5_devices.cbegin(), it.base()) - 1); - entry.id.number = Common::swap16(usbv5_device.number); - entry.vid = Common::swap16(device->GetVid()); - entry.pid = Common::swap16(device->GetPid()); - entry.number = Common::swap16(usbv5_device.number); - entry.interface_number = usbv5_device.interface_number; - entry.num_altsettings = device->GetNumberOfAltSettings(entry.interface_number); - - Memory::CopyToEmu(m_devicechange_hook_request->buffer_out + sizeof(entry) * num_devices++, - &entry, sizeof(entry)); - } - - m_ios.EnqueueIPCReply(*m_devicechange_hook_request, num_devices, 0, CoreTiming::FromThread::ANY); - m_devicechange_hook_request.reset(); - INFO_LOG(IOS_USB, "%d USBv5 device(s), including interfaces", num_devices); -} } // namespace Device } // namespace HLE } // namespace IOS diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h index 3ec4d62445..a246152bb9 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h @@ -4,18 +4,10 @@ #pragma once -#include -#include -#include -#include -#include - -#include "Common/CommonTypes.h" #include "Core/IOS/Device.h" #include "Core/IOS/IOS.h" #include "Core/IOS/USB/Host.h" - -class PointerWrap; +#include "Core/IOS/USB/USBV5.h" namespace IOS { @@ -23,53 +15,19 @@ namespace HLE { namespace Device { -class USB_VEN final : public USBHost +class USB_VEN final : public USBV5ResourceManager { public: - USB_VEN(Kernel& ios, const std::string& device_name); + using USBV5ResourceManager::USBV5ResourceManager; ~USB_VEN() override; ReturnCode Open(const OpenRequest& request) override; IPCCommandResult IOCtl(const IOCtlRequest& request) override; IPCCommandResult IOCtlV(const IOCtlVRequest& request) override; - void DoState(PointerWrap& p) override; - private: - struct USBV5Device; - USBV5Device* GetUSBV5Device(u32 in_buffer); - IPCCommandResult CancelEndpoint(USBV5Device& device, const IOCtlRequest& request); - IPCCommandResult GetDeviceChange(const IOCtlRequest& request); IPCCommandResult GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request); - IPCCommandResult SetAlternateSetting(USBV5Device& device, const IOCtlRequest& request); - IPCCommandResult Shutdown(const IOCtlRequest& request); - IPCCommandResult SuspendResume(USBV5Device& device, const IOCtlRequest& request); - s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& request); - - using Handler = std::function; - IPCCommandResult HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler); - - void OnDeviceChange(ChangeEvent, std::shared_ptr) override; - void OnDeviceChangeEnd() override; - void TriggerDeviceChangeReply(); - - bool m_devicechange_first_call = true; - std::mutex m_devicechange_hook_address_mutex; - std::unique_ptr m_devicechange_hook_request; - - // Each interface of a USB device is internally considered as a unique device. - // USBv5 resource managers can handle up to 32 devices/interfaces. - struct USBV5Device - { - bool in_use = false; - u8 interface_number; - u16 number; - u64 host_id; - }; - std::array m_usbv5_devices; - mutable std::mutex m_usbv5_devices_mutex; - u16 m_current_device_number = 0x21; }; } // namespace Device } // namespace HLE