USB_HIDv5: Submit interrupt transfers to the correct endpoint
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. This commit changes HIDv5 to keep track of endpoints (like IOS does) and use them when submitting interrupt transfers.
This commit is contained in:
parent
ff52333b14
commit
ac3b866083
|
@ -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<USB::V5CtrlMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_INTRMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IntrMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_BULKMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5BulkMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_ISOMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IsoMessage>(m_ios, ioctlv));
|
||||
default:
|
||||
return IPC_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
IPCCommandResult USBV5ResourceManager::HandleDeviceIOCtl(const IOCtlRequest& request,
|
||||
Handler handler)
|
||||
{
|
||||
|
|
|
@ -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(USBV5Device&)>;
|
||||
IPCCommandResult HandleDeviceIOCtl(const IOCtlRequest& request, Handler handler);
|
||||
|
|
|
@ -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<USB::V5CtrlMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_INTRMSG:
|
||||
{
|
||||
auto message = std::make_unique<USB::V5IntrMessage>(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));
|
||||
}
|
||||
|
|
|
@ -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<AdditionalDeviceData, 32> m_additional_device_data{};
|
||||
};
|
||||
} // namespace Device
|
||||
} // namespace HLE
|
||||
|
|
|
@ -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<USB::V5CtrlMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_INTRMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IntrMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_BULKMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5BulkMessage>(m_ios, ioctlv));
|
||||
case USB::IOCTLV_USBV5_ISOMSG:
|
||||
return device.SubmitTransfer(std::make_unique<USB::V5IsoMessage>(m_ios, ioctlv));
|
||||
default:
|
||||
return IPC_EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
||||
{
|
||||
const u8 endpoint = static_cast<u8>(Memory::Read_U32(request.buffer_in + 8));
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in New Issue