mirror of
https://github.com/dolphin-emu/dolphin.git
synced 2025-01-10 08:09:26 +01:00
IOS/USB: Claim all interfaces ahead-of-time
To avoid having to claim/release interfaces all the time, and having to trigger interface changes from several places, all interfaces are now claimed ahead of time. This commit also makes us avoid changing the active interface when it's not necessary. Changing the active interface has side effects such as resetting the active alternate setting -- which is extremely undesirable because it would require the emulated software to change the alternate setting again, which isn't supposed to be necessary at all. This fixes Your Shape, which submits isochronous transfers on an endpoint that only exists in alt setting 6 right after submitting control transfers (which would have reset to alt setting 0 prior to this fix).
This commit is contained in:
parent
2b44e1b851
commit
6dd0fe21f2
@ -15,6 +15,8 @@
|
|||||||
|
|
||||||
namespace IOS::HLE::USB
|
namespace IOS::HLE::USB
|
||||||
{
|
{
|
||||||
|
constexpr u8 DEFAULT_CONFIG_NUM = 0;
|
||||||
|
|
||||||
enum StandardDeviceRequestCodes
|
enum StandardDeviceRequestCodes
|
||||||
{
|
{
|
||||||
REQUEST_GET_DESCRIPTOR = 6,
|
REQUEST_GET_DESCRIPTOR = 6,
|
||||||
@ -165,7 +167,13 @@ public:
|
|||||||
virtual std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const = 0;
|
virtual std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const = 0;
|
||||||
|
|
||||||
virtual std::string GetErrorName(int error_code) const;
|
virtual std::string GetErrorName(int error_code) const;
|
||||||
virtual bool Attach(u8 interface) = 0;
|
/// Ensure the device is ready to use.
|
||||||
|
virtual bool Attach() = 0;
|
||||||
|
/// Ensure the device is ready to use and change the active interface (if needed).
|
||||||
|
///
|
||||||
|
/// This may reset the active alt setting, so prefer using Attach when interface changes
|
||||||
|
/// are unnecessary (e.g. for control requests).
|
||||||
|
virtual bool AttachAndChangeInterface(u8 interface) = 0;
|
||||||
virtual int CancelTransfer(u8 endpoint) = 0;
|
virtual int CancelTransfer(u8 endpoint) = 0;
|
||||||
virtual int ChangeInterface(u8 interface) = 0;
|
virtual int ChangeInterface(u8 interface) = 0;
|
||||||
virtual int GetNumberOfAltSettings(u8 interface) = 0;
|
virtual int GetNumberOfAltSettings(u8 interface) = 0;
|
||||||
|
@ -42,10 +42,11 @@ LibusbDevice::LibusbDevice(Kernel& ios, libusb_device* device,
|
|||||||
|
|
||||||
LibusbDevice::~LibusbDevice()
|
LibusbDevice::~LibusbDevice()
|
||||||
{
|
{
|
||||||
if (m_device_attached)
|
|
||||||
DetachInterface();
|
|
||||||
if (m_handle != nullptr)
|
if (m_handle != nullptr)
|
||||||
|
{
|
||||||
|
ReleaseAllInterfacesForCurrentConfig();
|
||||||
libusb_close(m_handle);
|
libusb_close(m_handle);
|
||||||
|
}
|
||||||
libusb_unref_device(m_device);
|
libusb_unref_device(m_device);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -124,28 +125,39 @@ std::string LibusbDevice::GetErrorName(const int error_code) const
|
|||||||
return libusb_error_name(error_code);
|
return libusb_error_name(error_code);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool LibusbDevice::Attach(const u8 interface)
|
bool LibusbDevice::Attach()
|
||||||
{
|
{
|
||||||
if (m_device_attached && interface != m_active_interface)
|
|
||||||
return ChangeInterface(interface) == 0;
|
|
||||||
|
|
||||||
if (m_device_attached)
|
if (m_device_attached)
|
||||||
return true;
|
return true;
|
||||||
|
|
||||||
m_device_attached = false;
|
if (!m_handle)
|
||||||
|
{
|
||||||
NOTICE_LOG(IOS_USB, "[%04x:%04x] Opening device", m_vid, m_pid);
|
NOTICE_LOG(IOS_USB, "[%04x:%04x] Opening device", m_vid, m_pid);
|
||||||
const int ret = libusb_open(m_device, &m_handle);
|
const int ret = libusb_open(m_device, &m_handle);
|
||||||
if (ret != 0)
|
if (ret != 0)
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to open: %s", m_vid, m_pid, libusb_error_name(ret));
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to open: %s", m_vid, m_pid, libusb_error_name(ret));
|
||||||
|
m_handle = nullptr;
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
if (AttachInterface(interface) != 0)
|
}
|
||||||
|
if (ClaimAllInterfaces(DEFAULT_CONFIG_NUM) < 0)
|
||||||
return false;
|
return false;
|
||||||
m_device_attached = true;
|
m_device_attached = true;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool LibusbDevice::AttachAndChangeInterface(const u8 interface)
|
||||||
|
{
|
||||||
|
if (!Attach())
|
||||||
|
return false;
|
||||||
|
|
||||||
|
if (interface != m_active_interface)
|
||||||
|
return ChangeInterface(interface) == 0;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int LibusbDevice::CancelTransfer(const u8 endpoint)
|
int LibusbDevice::CancelTransfer(const u8 endpoint)
|
||||||
{
|
{
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x %d] Cancelling transfers (endpoint 0x%x)", m_vid, m_pid,
|
INFO_LOG(IOS_USB, "[%04x:%04x %d] Cancelling transfers (endpoint 0x%x)", m_vid, m_pid,
|
||||||
@ -159,15 +171,10 @@ int LibusbDevice::CancelTransfer(const u8 endpoint)
|
|||||||
|
|
||||||
int LibusbDevice::ChangeInterface(const u8 interface)
|
int LibusbDevice::ChangeInterface(const u8 interface)
|
||||||
{
|
{
|
||||||
if (!m_device_attached || interface >= m_config_descriptors[0]->Get()->bNumInterfaces)
|
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
|
||||||
|
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x %d] Changing interface to %d", m_vid, m_pid, m_active_interface,
|
INFO_LOG(IOS_USB, "[%04x:%04x %d] Changing interface to %d", m_vid, m_pid, m_active_interface,
|
||||||
interface);
|
interface);
|
||||||
const int ret = DetachInterface();
|
m_active_interface = interface;
|
||||||
if (ret < 0)
|
return 0;
|
||||||
return ret;
|
|
||||||
return AttachInterface(interface);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LibusbDevice::SetAltSetting(const u8 alt_setting)
|
int LibusbDevice::SetAltSetting(const u8 alt_setting)
|
||||||
@ -217,9 +224,13 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
|||||||
{
|
{
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_CONFIGURATION index=%04x value=%04x", m_vid,
|
INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_CONFIGURATION index=%04x value=%04x", m_vid,
|
||||||
m_pid, m_active_interface, cmd->index, cmd->value);
|
m_pid, m_active_interface, cmd->index, cmd->value);
|
||||||
|
ReleaseAllInterfacesForCurrentConfig();
|
||||||
const int ret = libusb_set_configuration(m_handle, cmd->value);
|
const int ret = libusb_set_configuration(m_handle, cmd->value);
|
||||||
if (ret == 0)
|
if (ret == 0)
|
||||||
|
{
|
||||||
|
ClaimAllInterfaces(cmd->value);
|
||||||
m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length);
|
m_ios.EnqueueIPCReply(cmd->ios_request, cmd->length);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -395,50 +406,61 @@ int LibusbDevice::GetNumberOfAltSettings(const u8 interface_number)
|
|||||||
return m_config_descriptors[0]->Get()->interface[interface_number].num_altsetting;
|
return m_config_descriptors[0]->Get()->interface[interface_number].num_altsetting;
|
||||||
}
|
}
|
||||||
|
|
||||||
int LibusbDevice::AttachInterface(const u8 interface)
|
template <typename Configs, typename Function>
|
||||||
|
static int DoForEachInterface(const Configs& configs, u8 config_num, Function action)
|
||||||
{
|
{
|
||||||
if (m_handle == nullptr)
|
int ret = LIBUSB_ERROR_NOT_FOUND;
|
||||||
{
|
if (configs.size() <= config_num || !configs[config_num]->IsValid())
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Cannot attach without a valid device handle", m_vid, m_pid);
|
|
||||||
return -1;
|
|
||||||
}
|
|
||||||
|
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x] Attaching interface %d", m_vid, m_pid, interface);
|
|
||||||
const int ret = libusb_detach_kernel_driver(m_handle, interface);
|
|
||||||
if (ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND && ret != LIBUSB_ERROR_NOT_SUPPORTED)
|
|
||||||
{
|
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to detach kernel driver: %s", m_vid, m_pid,
|
|
||||||
libusb_error_name(ret));
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
for (u8 i = 0; i < configs[config_num]->Get()->bNumInterfaces; ++i)
|
||||||
const int r = libusb_claim_interface(m_handle, interface);
|
|
||||||
if (r < 0)
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Couldn't claim interface %d: %s", m_vid, m_pid, interface,
|
ret = action(i);
|
||||||
libusb_error_name(r));
|
if (ret < 0)
|
||||||
return r;
|
break;
|
||||||
}
|
}
|
||||||
m_active_interface = interface;
|
return ret;
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
int LibusbDevice::DetachInterface()
|
int LibusbDevice::ClaimAllInterfaces(u8 config_num) const
|
||||||
{
|
{
|
||||||
if (m_handle == nullptr)
|
const int ret = DoForEachInterface(m_config_descriptors, config_num, [this](u8 i) {
|
||||||
|
const int ret2 = libusb_detach_kernel_driver(m_handle, i);
|
||||||
|
if (ret2 < 0 && ret2 != LIBUSB_ERROR_NOT_FOUND && ret2 != LIBUSB_ERROR_NOT_SUPPORTED)
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Cannot detach without a valid device handle", m_vid, m_pid);
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to detach kernel driver: %s", m_vid, m_pid,
|
||||||
return -1;
|
libusb_error_name(ret2));
|
||||||
|
return ret2;
|
||||||
}
|
}
|
||||||
|
return libusb_claim_interface(m_handle, i);
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x] Detaching interface %d", m_vid, m_pid, m_active_interface);
|
});
|
||||||
const int ret = libusb_release_interface(m_handle, m_active_interface);
|
if (ret < 0)
|
||||||
if (ret < 0 && ret != LIBUSB_ERROR_NO_DEVICE)
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to release interface %d: %s", m_vid, m_pid,
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to claim all interfaces (configuration %u)", m_vid,
|
||||||
m_active_interface, libusb_error_name(ret));
|
m_pid, config_num);
|
||||||
|
}
|
||||||
return ret;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibusbDevice::ReleaseAllInterfaces(u8 config_num) const
|
||||||
|
{
|
||||||
|
const int ret = DoForEachInterface(m_config_descriptors, config_num, [this](u8 i) {
|
||||||
|
return libusb_release_interface(m_handle, i);
|
||||||
|
});
|
||||||
|
if (ret < 0 && ret != LIBUSB_ERROR_NO_DEVICE && ret != LIBUSB_ERROR_NOT_FOUND)
|
||||||
|
{
|
||||||
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to release all interfaces (configuration %u)", m_vid,
|
||||||
|
m_pid, config_num);
|
||||||
}
|
}
|
||||||
return 0;
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int LibusbDevice::ReleaseAllInterfacesForCurrentConfig() const
|
||||||
|
{
|
||||||
|
int config_num;
|
||||||
|
const int get_config_ret = libusb_get_configuration(m_handle, &config_num);
|
||||||
|
if (get_config_ret < 0)
|
||||||
|
return get_config_ret;
|
||||||
|
return ReleaseAllInterfaces(config_num);
|
||||||
}
|
}
|
||||||
|
|
||||||
LibusbConfigDescriptor::LibusbConfigDescriptor(libusb_device* device, const u8 config_num)
|
LibusbConfigDescriptor::LibusbConfigDescriptor(libusb_device* device, const u8 config_num)
|
||||||
|
@ -48,7 +48,8 @@ public:
|
|||||||
std::vector<InterfaceDescriptor> GetInterfaces(u8 config) const override;
|
std::vector<InterfaceDescriptor> GetInterfaces(u8 config) const override;
|
||||||
std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const override;
|
std::vector<EndpointDescriptor> GetEndpoints(u8 config, u8 interface, u8 alt) const override;
|
||||||
std::string GetErrorName(int error_code) const override;
|
std::string GetErrorName(int error_code) const override;
|
||||||
bool Attach(u8 interface) override;
|
bool Attach() override;
|
||||||
|
bool AttachAndChangeInterface(u8 interface) override;
|
||||||
int CancelTransfer(u8 endpoint) override;
|
int CancelTransfer(u8 endpoint) override;
|
||||||
int ChangeInterface(u8 interface) override;
|
int ChangeInterface(u8 interface) override;
|
||||||
int GetNumberOfAltSettings(u8 interface) override;
|
int GetNumberOfAltSettings(u8 interface) override;
|
||||||
@ -85,8 +86,9 @@ private:
|
|||||||
static void CtrlTransferCallback(libusb_transfer* transfer);
|
static void CtrlTransferCallback(libusb_transfer* transfer);
|
||||||
static void TransferCallback(libusb_transfer* transfer);
|
static void TransferCallback(libusb_transfer* transfer);
|
||||||
|
|
||||||
int AttachInterface(u8 interface);
|
int ClaimAllInterfaces(u8 config_num) const;
|
||||||
int DetachInterface();
|
int ReleaseAllInterfaces(u8 config_num) const;
|
||||||
|
int ReleaseAllInterfacesForCurrentConfig() const;
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::USB
|
} // namespace IOS::HLE::USB
|
||||||
#endif
|
#endif
|
||||||
|
@ -252,8 +252,10 @@ std::pair<ReturnCode, u64> OH0::DeviceOpen(const u16 vid, const u16 pid)
|
|||||||
has_device_with_vid_pid = true;
|
has_device_with_vid_pid = true;
|
||||||
|
|
||||||
if (m_opened_devices.find(device.second->GetId()) != m_opened_devices.cend() ||
|
if (m_opened_devices.find(device.second->GetId()) != m_opened_devices.cend() ||
|
||||||
!device.second->Attach(0))
|
!device.second->Attach())
|
||||||
|
{
|
||||||
continue;
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
m_opened_devices.emplace(device.second->GetId());
|
m_opened_devices.emplace(device.second->GetId());
|
||||||
return {IPC_SUCCESS, device.second->GetId()};
|
return {IPC_SUCCESS, device.second->GetId()};
|
||||||
|
@ -140,7 +140,7 @@ IPCCommandResult USBV5ResourceManager::SetAlternateSetting(USBV5Device& device,
|
|||||||
const IOCtlRequest& request)
|
const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const auto host_device = GetDeviceById(device.host_id);
|
const auto host_device = GetDeviceById(device.host_id);
|
||||||
if (!host_device->Attach(device.interface_number))
|
if (!host_device->AttachAndChangeInterface(device.interface_number))
|
||||||
return GetDefaultReply(-1);
|
return GetDefaultReply(-1);
|
||||||
|
|
||||||
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32));
|
const u8 alt_setting = Memory::Read_U8(request.buffer_in + 2 * sizeof(s32));
|
||||||
|
@ -55,7 +55,7 @@ IPCCommandResult USB_HIDv4::IOCtl(const IOCtlRequest& request)
|
|||||||
if (request.buffer_in == 0 || request.buffer_in_size != 32)
|
if (request.buffer_in == 0 || request.buffer_in_size != 32)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return GetDefaultReply(IPC_EINVAL);
|
||||||
const auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in + 16));
|
const auto device = GetDeviceByIOSID(Memory::Read_U32(request.buffer_in + 16));
|
||||||
if (!device->Attach(0))
|
if (!device->Attach())
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return GetDefaultReply(IPC_EINVAL);
|
||||||
return HandleTransfer(device, request.request,
|
return HandleTransfer(device, request.request,
|
||||||
[&, this]() { return SubmitTransfer(*device, request); });
|
[&, this]() { return SubmitTransfer(*device, request); });
|
||||||
|
@ -67,7 +67,10 @@ IPCCommandResult USB_HIDv5::IOCtlV(const IOCtlVRequest& request)
|
|||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return GetDefaultReply(IPC_EINVAL);
|
||||||
auto host_device = GetDeviceById(device->host_id);
|
auto host_device = GetDeviceById(device->host_id);
|
||||||
host_device->Attach(device->interface_number);
|
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
||||||
|
host_device->Attach();
|
||||||
|
else
|
||||||
|
host_device->AttachAndChangeInterface(device->interface_number);
|
||||||
return HandleTransfer(host_device, request.request,
|
return HandleTransfer(host_device, request.request,
|
||||||
[&, this]() { return SubmitTransfer(*device, *host_device, request); });
|
[&, this]() { return SubmitTransfer(*device, *host_device, request); });
|
||||||
}
|
}
|
||||||
|
@ -76,7 +76,10 @@ IPCCommandResult USB_VEN::IOCtlV(const IOCtlVRequest& request)
|
|||||||
if (!device)
|
if (!device)
|
||||||
return GetDefaultReply(IPC_EINVAL);
|
return GetDefaultReply(IPC_EINVAL);
|
||||||
auto host_device = GetDeviceById(device->host_id);
|
auto host_device = GetDeviceById(device->host_id);
|
||||||
host_device->Attach(device->interface_number);
|
if (request.request == USB::IOCTLV_USBV5_CTRLMSG)
|
||||||
|
host_device->Attach();
|
||||||
|
else
|
||||||
|
host_device->AttachAndChangeInterface(device->interface_number);
|
||||||
return HandleTransfer(host_device, request.request,
|
return HandleTransfer(host_device, request.request,
|
||||||
[&, this]() { return SubmitTransfer(*host_device, request); });
|
[&, this]() { return SubmitTransfer(*host_device, request); });
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user