diff --git a/Source/Core/Core/IOS/USB/USBV5.cpp b/Source/Core/Core/IOS/USB/USBV5.cpp index d4712c9488..804989b75a 100644 --- a/Source/Core/Core/IOS/USB/USBV5.cpp +++ b/Source/Core/Core/IOS/USB/USBV5.cpp @@ -174,23 +174,6 @@ IPCCommandResult USBV5ResourceManager::SuspendResume(USBV5Device& device, 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) { diff --git a/Source/Core/Core/IOS/USB/USBV5.h b/Source/Core/Core/IOS/USB/USBV5.h index fbfde46fb3..ceca6bcb71 100644 --- a/Source/Core/Core/IOS/USB/USBV5.h +++ b/Source/Core/Core/IOS/USB/USBV5.h @@ -86,7 +86,6 @@ protected: 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); diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp index dfc12f6b6a..c8f6b8f241 100644 --- a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.cpp @@ -71,13 +71,40 @@ IPCCommandResult USB_HIDv5::IOCtlV(const IOCtlVRequest& request) auto host_device = GetDeviceById(device->host_id); host_device->Attach(device->interface_number); return HandleTransfer(host_device, request.request, - [&, this]() { return SubmitTransfer(*host_device, request); }); + [&, this]() { return SubmitTransfer(*device, *host_device, request); }); } default: return GetDefaultReply(IPC_EINVAL); } } +s32 USB_HIDv5::SubmitTransfer(USBV5Device& device, USB::Device& host_device, + const IOCtlVRequest& ioctlv) +{ + switch (ioctlv.request) + { + case USB::IOCTLV_USBV5_CTRLMSG: + return host_device.SubmitTransfer(std::make_unique(m_ios, ioctlv)); + case USB::IOCTLV_USBV5_INTRMSG: + { + auto message = std::make_unique(m_ios, ioctlv); + + // Unlike VEN, the endpoint is determined by the value at 8-12. + // If it's non-zero, HID submits the request to the interrupt OUT endpoint. + // Otherwise, the request is submitted to the IN endpoint. + AdditionalDeviceData* data = &m_additional_device_data[&device - m_usbv5_devices.data()]; + if (Memory::Read_U32(ioctlv.in_vectors[0].address + 8) != 0) + message->endpoint = data->interrupt_out_endpoint; + else + message->endpoint = data->interrupt_in_endpoint; + + return host_device.SubmitTransfer(std::move(message)); + } + default: + return IPC_EINVAL; + } +} + IPCCommandResult USB_HIDv5::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request) { // FIXME: Unlike VEN, there are 3 valid values for the endpoint, @@ -128,7 +155,15 @@ IPCCommandResult USB_HIDv5::GetDeviceInfo(USBV5Device& device, const IOCtlReques constexpr u8 ENDPOINT_IN = 0x80; if (endpoint.bmAttributes == ENDPOINT_INTERRUPT) { - const u32 offset = (endpoint.bEndpointAddress & ENDPOINT_IN) != 0 ? 80 : 88; + const bool is_in_endpoint = (endpoint.bEndpointAddress & ENDPOINT_IN) != 0; + + AdditionalDeviceData* data = &m_additional_device_data[&device - m_usbv5_devices.data()]; + if (is_in_endpoint) + data->interrupt_in_endpoint = endpoint.bEndpointAddress; + else + data->interrupt_out_endpoint = endpoint.bEndpointAddress; + + const u32 offset = is_in_endpoint ? 80 : 88; endpoint.Swap(); Memory::CopyToEmu(request.buffer_out + offset, &endpoint, sizeof(endpoint)); } diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h index 625a810f54..82709898fa 100644 --- a/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv5.h @@ -27,9 +27,16 @@ public: private: IPCCommandResult CancelEndpoint(USBV5Device& device, const IOCtlRequest& request); IPCCommandResult GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request); + s32 SubmitTransfer(USBV5Device& device, USB::Device& host_device, const IOCtlVRequest& ioctlv); bool ShouldAddDevice(const USB::Device& device) const override; bool HasInterfaceNumberInIDs() const override { return true; } + struct AdditionalDeviceData + { + u8 interrupt_in_endpoint = 0; + u8 interrupt_out_endpoint = 0; + }; + std::array m_additional_device_data{}; }; } // namespace Device } // namespace HLE diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp index fcc7e3792b..93fad5d0c1 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp @@ -95,6 +95,23 @@ IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request) } } +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::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request) { const u8 endpoint = static_cast(Memory::Read_U32(request.buffer_in + 8)); diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h index 58c4af767e..8205b0ca2d 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.h +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.h @@ -29,6 +29,7 @@ private: IPCCommandResult CancelEndpoint(USBV5Device& device, const IOCtlRequest& request); IPCCommandResult GetDeviceInfo(USBV5Device& device, const IOCtlRequest& request); + s32 SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv); bool HasInterfaceNumberInIDs() const override { return false; } }; } // namespace Device