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.
This commit is contained in:
Léo Lam 2017-11-02 21:56:16 +01:00
parent c6038155cc
commit 6bb03d900c
4 changed files with 77 additions and 80 deletions

View File

@ -6,7 +6,6 @@
#include <algorithm>
#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<u8>* buffer, const void* data, const size_t size)
void DeviceDescriptor::Swap()
{
buffer->insert(buffer->end(), static_cast<const u8*>(data), static_cast<const u8*>(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<u8>* 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<u8>* buffer, ConfigDescriptor descriptor)
void InterfaceDescriptor::Swap()
{
descriptor.wTotalLength = Common::swap16(descriptor.wTotalLength);
CopyToBufferAligned(buffer, &descriptor, descriptor.bLength);
}
static void CopyDescriptorToBuffer(std::vector<u8>* buffer, InterfaceDescriptor descriptor)
void EndpointDescriptor::Swap()
{
CopyToBufferAligned(buffer, &descriptor, descriptor.bLength);
}
static void CopyDescriptorToBuffer(std::vector<u8>* 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<u8> Device::GetDescriptorsUSBV4() const
{
return GetDescriptors([](const auto& descriptor) { return true; });
}
std::vector<u8> 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<u8>
Device::GetDescriptors(std::function<bool(const InterfaceDescriptor&)> predicate) const
{
std::vector<u8> 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<u8>(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<u8>(c), descriptor.bInterfaceNumber, descriptor.bAlternateSetting))
CopyDescriptorToBuffer(&buffer, endpoint_descriptor);
}
}
return buffer;
wMaxPacketSize = Common::swap16(wMaxPacketSize);
}
std::string Device::GetErrorName(const int error_code) const

View File

@ -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<u8> GetDescriptorsUSBV4() const;
std::vector<u8> GetDescriptorsUSBV5(u8 interface, u8 alt_setting) const;
virtual DeviceDescriptor GetDeviceDescriptor() const = 0;
virtual std::vector<ConfigDescriptor> GetConfigurations() const = 0;
@ -178,7 +180,6 @@ public:
virtual int SubmitTransfer(std::unique_ptr<IsoMessage> message) = 0;
protected:
std::vector<u8> GetDescriptors(std::function<bool(const InterfaceDescriptor&)> predicate) const;
u64 m_id = 0xFFFFFFFFFFFFFFFF;
};
} // namespace USB

View File

@ -210,6 +210,40 @@ void USB_HIDv4::TriggerDeviceChangeReply()
m_devicechange_hook_request.reset();
}
template <typename T>
static void CopyDescriptorToBuffer(std::vector<u8>* buffer, T descriptor)
{
const size_t size = sizeof(descriptor);
descriptor.Swap();
buffer->insert(buffer->end(), reinterpret_cast<const u8*>(&descriptor),
reinterpret_cast<const u8*>(&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<u8> GetDescriptors(const USB::Device& device)
{
std::vector<u8> 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<u8>(c));
for (size_t i = interfaces.size(); i-- > 0;)
{
CopyDescriptorToBuffer(&buffer, interfaces[i]);
for (const auto& endpoint_descriptor : device.GetEndpoints(
static_cast<u8>(c), interfaces[i].bInterfaceNumber, interfaces[i].bAlternateSetting))
{
CopyDescriptorToBuffer(&buffer, endpoint_descriptor);
}
}
}
return buffer;
}
std::vector<u8> USB_HIDv4::GetDeviceEntry(const USB::Device& device) const
{
std::lock_guard<std::mutex> id_map_lock{m_id_map_mutex};
@ -219,7 +253,7 @@ std::vector<u8> USB_HIDv4::GetDeviceEntry(const USB::Device& device) const
// 4-8 bytes: device ID
// the rest of the buffer is device descriptors data
std::vector<u8> entry(8);
const std::vector<u8> descriptors = device.GetDescriptorsUSBV4();
const std::vector<u8> descriptors = GetDescriptors(device);
const u32 entry_size = Common::swap32(static_cast<u32>(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));

View File

@ -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<USB::Device> 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<USB::InterfaceDescriptor> 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<u8>(i), &endpoints[i],
sizeof(endpoints[i]));
}
return GetDefaultReply(IPC_SUCCESS);
}