From 6bb03d900c3bb61e4fb8b855f06de8dd3d9eebc7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9o=20Lam?= Date: Thu, 2 Nov 2017 21:56:16 +0100 Subject: [PATCH] USB: Separate the descriptor copy logic The descriptor copy code is not actually the same in HIDv4 and VEN, so it did not make a lot of sense to put it in USB/Common.cpp. Separate and move it to HIDv4 and VEN. This cleanup is important because there are even more differences between HIDv4 and HIDv5. --- Source/Core/Core/IOS/USB/Common.cpp | 77 +++------------------- Source/Core/Core/IOS/USB/Common.h | 7 +- Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp | 36 +++++++++- Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp | 37 ++++++++--- 4 files changed, 77 insertions(+), 80 deletions(-) diff --git a/Source/Core/Core/IOS/USB/Common.cpp b/Source/Core/Core/IOS/USB/Common.cpp index a9627b0974..a91ac518b1 100644 --- a/Source/Core/Core/IOS/USB/Common.cpp +++ b/Source/Core/Core/IOS/USB/Common.cpp @@ -6,7 +6,6 @@ #include -#include "Common/Align.h" #include "Common/Assert.h" #include "Common/CommonTypes.h" #include "Common/StringUtil.h" @@ -70,82 +69,26 @@ bool Device::HasClass(const u8 device_class) const }); } -static void CopyToBufferAligned(std::vector* buffer, const void* data, const size_t size) +void DeviceDescriptor::Swap() { - buffer->insert(buffer->end(), static_cast(data), static_cast(data) + size); - const size_t number_of_padding_bytes = Common::AlignUp(size, 4) - size; - buffer->insert(buffer->end(), number_of_padding_bytes, 0); + bcdUSB = Common::swap16(bcdUSB); + idVendor = Common::swap16(idVendor); + idProduct = Common::swap16(idProduct); + bcdDevice = Common::swap16(bcdDevice); } -static void CopyDescriptorToBuffer(std::vector* buffer, DeviceDescriptor descriptor) +void ConfigDescriptor::Swap() { - descriptor.bcdUSB = Common::swap16(descriptor.bcdUSB); - descriptor.idVendor = Common::swap16(descriptor.idVendor); - descriptor.idProduct = Common::swap16(descriptor.idProduct); - descriptor.bcdDevice = Common::swap16(descriptor.bcdDevice); - CopyToBufferAligned(buffer, &descriptor, descriptor.bLength); + wTotalLength = Common::swap16(wTotalLength); } -static void CopyDescriptorToBuffer(std::vector* buffer, ConfigDescriptor descriptor) +void InterfaceDescriptor::Swap() { - descriptor.wTotalLength = Common::swap16(descriptor.wTotalLength); - CopyToBufferAligned(buffer, &descriptor, descriptor.bLength); } -static void CopyDescriptorToBuffer(std::vector* buffer, InterfaceDescriptor descriptor) +void EndpointDescriptor::Swap() { - CopyToBufferAligned(buffer, &descriptor, descriptor.bLength); -} - -static void CopyDescriptorToBuffer(std::vector* buffer, EndpointDescriptor descriptor) -{ - descriptor.wMaxPacketSize = Common::swap16(descriptor.wMaxPacketSize); - // IOS only copies 8 bytes from the endpoint descriptor, regardless of the actual length - CopyToBufferAligned(buffer, &descriptor, sizeof(descriptor)); -} - -std::vector Device::GetDescriptorsUSBV4() const -{ - return GetDescriptors([](const auto& descriptor) { return true; }); -} - -std::vector Device::GetDescriptorsUSBV5(const u8 interface, const u8 alt_setting) const -{ - return GetDescriptors([interface, alt_setting](const auto& descriptor) { - // The USBV5 interfaces present each interface as a different device, - // and the descriptors are filtered by alternate setting. - return descriptor.bInterfaceNumber == interface && descriptor.bAlternateSetting == alt_setting; - }); -} - -std::vector -Device::GetDescriptors(std::function predicate) const -{ - std::vector buffer; - - const auto device_descriptor = GetDeviceDescriptor(); - CopyDescriptorToBuffer(&buffer, device_descriptor); - - const auto configurations = GetConfigurations(); - for (size_t c = 0; c < configurations.size(); ++c) - { - const auto& config_descriptor = configurations[c]; - CopyDescriptorToBuffer(&buffer, config_descriptor); - - const auto interfaces = GetInterfaces(static_cast(c)); - for (size_t i = interfaces.size(); i-- > 0;) - { - const auto& descriptor = interfaces[i]; - if (!predicate(descriptor)) - continue; - - CopyDescriptorToBuffer(&buffer, descriptor); - for (const auto& endpoint_descriptor : GetEndpoints( - static_cast(c), descriptor.bInterfaceNumber, descriptor.bAlternateSetting)) - CopyDescriptorToBuffer(&buffer, endpoint_descriptor); - } - } - return buffer; + wMaxPacketSize = Common::swap16(wMaxPacketSize); } std::string Device::GetErrorName(const int error_code) const diff --git a/Source/Core/Core/IOS/USB/Common.h b/Source/Core/Core/IOS/USB/Common.h index 9efb6630a1..2013716a07 100644 --- a/Source/Core/Core/IOS/USB/Common.h +++ b/Source/Core/Core/IOS/USB/Common.h @@ -44,6 +44,7 @@ constexpr u16 USBHDR(u8 dir, u8 type, u8 recipient, u8 request) struct DeviceDescriptor { + void Swap(); u8 bLength; u8 bDescriptorType; u16 bcdUSB; @@ -62,6 +63,7 @@ struct DeviceDescriptor struct ConfigDescriptor { + void Swap(); u8 bLength; u8 bDescriptorType; u16 wTotalLength; @@ -74,6 +76,7 @@ struct ConfigDescriptor struct InterfaceDescriptor { + void Swap(); u8 bLength; u8 bDescriptorType; u8 bInterfaceNumber; @@ -87,6 +90,7 @@ struct InterfaceDescriptor struct EndpointDescriptor { + void Swap(); u8 bLength; u8 bDescriptorType; u8 bEndpointAddress; @@ -158,8 +162,6 @@ public: u16 GetVid() const; u16 GetPid() const; bool HasClass(u8 device_class) const; - std::vector GetDescriptorsUSBV4() const; - std::vector GetDescriptorsUSBV5(u8 interface, u8 alt_setting) const; virtual DeviceDescriptor GetDeviceDescriptor() const = 0; virtual std::vector GetConfigurations() const = 0; @@ -178,7 +180,6 @@ public: virtual int SubmitTransfer(std::unique_ptr message) = 0; protected: - std::vector GetDescriptors(std::function predicate) const; u64 m_id = 0xFFFFFFFFFFFFFFFF; }; } // namespace USB diff --git a/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp index edcf8b18c3..b0a1606e6c 100644 --- a/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp +++ b/Source/Core/Core/IOS/USB/USB_HID/HIDv4.cpp @@ -210,6 +210,40 @@ void USB_HIDv4::TriggerDeviceChangeReply() m_devicechange_hook_request.reset(); } +template +static void CopyDescriptorToBuffer(std::vector* buffer, T descriptor) +{ + const size_t size = sizeof(descriptor); + descriptor.Swap(); + buffer->insert(buffer->end(), reinterpret_cast(&descriptor), + reinterpret_cast(&descriptor) + size); + const size_t number_of_padding_bytes = Common::AlignUp(size, 4) - size; + buffer->insert(buffer->end(), number_of_padding_bytes, 0); +} + +static std::vector GetDescriptors(const USB::Device& device) +{ + std::vector buffer; + + CopyDescriptorToBuffer(&buffer, device.GetDeviceDescriptor()); + const auto configurations = device.GetConfigurations(); + for (size_t c = 0; c < configurations.size(); ++c) + { + CopyDescriptorToBuffer(&buffer, configurations[c]); + const auto interfaces = device.GetInterfaces(static_cast(c)); + for (size_t i = interfaces.size(); i-- > 0;) + { + CopyDescriptorToBuffer(&buffer, interfaces[i]); + for (const auto& endpoint_descriptor : device.GetEndpoints( + static_cast(c), interfaces[i].bInterfaceNumber, interfaces[i].bAlternateSetting)) + { + CopyDescriptorToBuffer(&buffer, endpoint_descriptor); + } + } + } + return buffer; +} + std::vector USB_HIDv4::GetDeviceEntry(const USB::Device& device) const { std::lock_guard id_map_lock{m_id_map_mutex}; @@ -219,7 +253,7 @@ std::vector USB_HIDv4::GetDeviceEntry(const USB::Device& device) const // 4-8 bytes: device ID // the rest of the buffer is device descriptors data std::vector entry(8); - const std::vector descriptors = device.GetDescriptorsUSBV4(); + const std::vector descriptors = GetDescriptors(device); const u32 entry_size = Common::swap32(static_cast(entry.size() + descriptors.size())); const u32 ios_device_id = Common::swap32(m_device_ids.at(device.GetId())); std::memcpy(entry.data(), &entry_size, sizeof(entry_size)); diff --git a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp index 552d278863..27fb03087d 100644 --- a/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp +++ b/Source/Core/Core/IOS/USB/USB_VEN/VEN.cpp @@ -186,20 +186,39 @@ IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest& if (request.buffer_out == 0 || request.buffer_out_size != 0xc0) return GetDefaultReply(IPC_EINVAL); - const auto host_device = GetDeviceById(device.host_id); + const std::shared_ptr host_device = GetDeviceById(device.host_id); const u8 alt_setting = Memory::Read_U8(request.buffer_in + 8); - auto descriptors = host_device->GetDescriptorsUSBV5(device.interface_number, alt_setting); - if (descriptors.empty()) - return GetDefaultReply(IPC_ENOENT); - - descriptors.resize(request.buffer_out_size - 20); - if (descriptors.size() > request.buffer_out_size - 20) - WARN_LOG(IOS_USB, "Buffer is too large. Only the first 172 bytes will be copied."); Memory::Memset(request.buffer_out, 0, request.buffer_out_size); Memory::Write_U32(Memory::Read_U32(request.buffer_in), request.buffer_out); Memory::Write_U32(1, request.buffer_out + 4); - Memory::CopyToEmu(request.buffer_out + 20, descriptors.data(), descriptors.size()); + + USB::DeviceDescriptor device_descriptor = host_device->GetDeviceDescriptor(); + device_descriptor.Swap(); + Memory::CopyToEmu(request.buffer_out + 20, &device_descriptor, sizeof(device_descriptor)); + + // VEN only cares about the first configuration. + USB::ConfigDescriptor config_descriptor = host_device->GetConfigurations()[0]; + config_descriptor.Swap(); + Memory::CopyToEmu(request.buffer_out + 40, &config_descriptor, sizeof(config_descriptor)); + + std::vector interfaces = host_device->GetInterfaces(0); + auto it = std::find_if(interfaces.begin(), interfaces.end(), [&](const auto& interface) { + return interface.bInterfaceNumber == device.interface_number && + interface.bAlternateSetting == alt_setting; + }); + if (it == interfaces.end()) + return GetDefaultReply(IPC_EINVAL); + it->Swap(); + Memory::CopyToEmu(request.buffer_out + 52, &*it, sizeof(*it)); + + auto endpoints = host_device->GetEndpoints(0, it->bInterfaceNumber, it->bAlternateSetting); + for (size_t i = 0; i < endpoints.size(); ++i) + { + endpoints[i].Swap(); + Memory::CopyToEmu(request.buffer_out + 64 + 8 * static_cast(i), &endpoints[i], + sizeof(endpoints[i])); + } return GetDefaultReply(IPC_SUCCESS); }