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