mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2024-11-15 13:57:57 -07:00
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 "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
|
||||
|
@ -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
|
||||
|
@ -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));
|
||||
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user