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:
parent
c6038155cc
commit
6bb03d900c
|
@ -6,7 +6,6 @@
|
||||||
|
|
||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
|
|
||||||
#include "Common/Align.h"
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
#include "Common/StringUtil.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);
|
bcdUSB = Common::swap16(bcdUSB);
|
||||||
const size_t number_of_padding_bytes = Common::AlignUp(size, 4) - size;
|
idVendor = Common::swap16(idVendor);
|
||||||
buffer->insert(buffer->end(), number_of_padding_bytes, 0);
|
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);
|
wTotalLength = Common::swap16(wTotalLength);
|
||||||
descriptor.idVendor = Common::swap16(descriptor.idVendor);
|
|
||||||
descriptor.idProduct = Common::swap16(descriptor.idProduct);
|
|
||||||
descriptor.bcdDevice = Common::swap16(descriptor.bcdDevice);
|
|
||||||
CopyToBufferAligned(buffer, &descriptor, descriptor.bLength);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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);
|
wMaxPacketSize = Common::swap16(wMaxPacketSize);
|
||||||
}
|
|
||||||
|
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::string Device::GetErrorName(const int error_code) const
|
std::string Device::GetErrorName(const int error_code) const
|
||||||
|
|
|
@ -44,6 +44,7 @@ constexpr u16 USBHDR(u8 dir, u8 type, u8 recipient, u8 request)
|
||||||
|
|
||||||
struct DeviceDescriptor
|
struct DeviceDescriptor
|
||||||
{
|
{
|
||||||
|
void Swap();
|
||||||
u8 bLength;
|
u8 bLength;
|
||||||
u8 bDescriptorType;
|
u8 bDescriptorType;
|
||||||
u16 bcdUSB;
|
u16 bcdUSB;
|
||||||
|
@ -62,6 +63,7 @@ struct DeviceDescriptor
|
||||||
|
|
||||||
struct ConfigDescriptor
|
struct ConfigDescriptor
|
||||||
{
|
{
|
||||||
|
void Swap();
|
||||||
u8 bLength;
|
u8 bLength;
|
||||||
u8 bDescriptorType;
|
u8 bDescriptorType;
|
||||||
u16 wTotalLength;
|
u16 wTotalLength;
|
||||||
|
@ -74,6 +76,7 @@ struct ConfigDescriptor
|
||||||
|
|
||||||
struct InterfaceDescriptor
|
struct InterfaceDescriptor
|
||||||
{
|
{
|
||||||
|
void Swap();
|
||||||
u8 bLength;
|
u8 bLength;
|
||||||
u8 bDescriptorType;
|
u8 bDescriptorType;
|
||||||
u8 bInterfaceNumber;
|
u8 bInterfaceNumber;
|
||||||
|
@ -87,6 +90,7 @@ struct InterfaceDescriptor
|
||||||
|
|
||||||
struct EndpointDescriptor
|
struct EndpointDescriptor
|
||||||
{
|
{
|
||||||
|
void Swap();
|
||||||
u8 bLength;
|
u8 bLength;
|
||||||
u8 bDescriptorType;
|
u8 bDescriptorType;
|
||||||
u8 bEndpointAddress;
|
u8 bEndpointAddress;
|
||||||
|
@ -158,8 +162,6 @@ public:
|
||||||
u16 GetVid() const;
|
u16 GetVid() const;
|
||||||
u16 GetPid() const;
|
u16 GetPid() const;
|
||||||
bool HasClass(u8 device_class) 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 DeviceDescriptor GetDeviceDescriptor() const = 0;
|
||||||
virtual std::vector<ConfigDescriptor> GetConfigurations() const = 0;
|
virtual std::vector<ConfigDescriptor> GetConfigurations() const = 0;
|
||||||
|
@ -178,7 +180,6 @@ public:
|
||||||
virtual int SubmitTransfer(std::unique_ptr<IsoMessage> message) = 0;
|
virtual int SubmitTransfer(std::unique_ptr<IsoMessage> message) = 0;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
std::vector<u8> GetDescriptors(std::function<bool(const InterfaceDescriptor&)> predicate) const;
|
|
||||||
u64 m_id = 0xFFFFFFFFFFFFFFFF;
|
u64 m_id = 0xFFFFFFFFFFFFFFFF;
|
||||||
};
|
};
|
||||||
} // namespace USB
|
} // namespace USB
|
||||||
|
|
|
@ -210,6 +210,40 @@ void USB_HIDv4::TriggerDeviceChangeReply()
|
||||||
m_devicechange_hook_request.reset();
|
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::vector<u8> USB_HIDv4::GetDeviceEntry(const USB::Device& device) const
|
||||||
{
|
{
|
||||||
std::lock_guard<std::mutex> id_map_lock{m_id_map_mutex};
|
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
|
// 4-8 bytes: device ID
|
||||||
// the rest of the buffer is device descriptors data
|
// the rest of the buffer is device descriptors data
|
||||||
std::vector<u8> entry(8);
|
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 entry_size = Common::swap32(static_cast<u32>(entry.size() + descriptors.size()));
|
||||||
const u32 ios_device_id = Common::swap32(m_device_ids.at(device.GetId()));
|
const u32 ios_device_id = Common::swap32(m_device_ids.at(device.GetId()));
|
||||||
std::memcpy(entry.data(), &entry_size, sizeof(entry_size));
|
std::memcpy(entry.data(), &entry_size, sizeof(entry_size));
|
||||||
|
|
|
@ -186,20 +186,39 @@ IPCCommandResult USB_VEN::GetDeviceInfo(USBV5Device& device, const IOCtlRequest&
|
||||||
if (request.buffer_out == 0 || request.buffer_out_size != 0xc0)
|
if (request.buffer_out == 0 || request.buffer_out_size != 0xc0)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
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);
|
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::Memset(request.buffer_out, 0, request.buffer_out_size);
|
||||||
Memory::Write_U32(Memory::Read_U32(request.buffer_in), request.buffer_out);
|
Memory::Write_U32(Memory::Read_U32(request.buffer_in), request.buffer_out);
|
||||||
Memory::Write_U32(1, request.buffer_out + 4);
|
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);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in New Issue