commit
5fb56505b2
|
@ -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,
|
||||||
|
@ -127,14 +129,14 @@ struct CtrlMessage : TransferCommand
|
||||||
|
|
||||||
struct BulkMessage : TransferCommand
|
struct BulkMessage : TransferCommand
|
||||||
{
|
{
|
||||||
u16 length = 0;
|
u32 length = 0;
|
||||||
u8 endpoint = 0;
|
u8 endpoint = 0;
|
||||||
using TransferCommand::TransferCommand;
|
using TransferCommand::TransferCommand;
|
||||||
};
|
};
|
||||||
|
|
||||||
struct IntrMessage : TransferCommand
|
struct IntrMessage : TransferCommand
|
||||||
{
|
{
|
||||||
u16 length = 0;
|
u32 length = 0;
|
||||||
u8 endpoint = 0;
|
u8 endpoint = 0;
|
||||||
using TransferCommand::TransferCommand;
|
using TransferCommand::TransferCommand;
|
||||||
};
|
};
|
||||||
|
@ -143,7 +145,7 @@ struct IsoMessage : TransferCommand
|
||||||
{
|
{
|
||||||
u32 packet_sizes_addr = 0;
|
u32 packet_sizes_addr = 0;
|
||||||
std::vector<u16> packet_sizes;
|
std::vector<u16> packet_sizes;
|
||||||
u16 length = 0;
|
u32 length = 0;
|
||||||
u8 num_packets = 0;
|
u8 num_packets = 0;
|
||||||
u8 endpoint = 0;
|
u8 endpoint = 0;
|
||||||
using TransferCommand::TransferCommand;
|
using TransferCommand::TransferCommand;
|
||||||
|
@ -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;
|
||||||
|
|
|
@ -45,12 +45,14 @@ USBHost::~USBHost()
|
||||||
|
|
||||||
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
IPCCommandResult USBHost::Open(const OpenRequest& request)
|
||||||
{
|
{
|
||||||
// Force a device scan to complete, because some games (including Your Shape) only care
|
if (!m_has_initialised)
|
||||||
// about the initial device list (in the first GETDEVICECHANGE reply).
|
|
||||||
while (!UpdateDevices())
|
|
||||||
{
|
{
|
||||||
|
StartThreads();
|
||||||
|
// Force a device scan to complete, because some games (including Your Shape) only care
|
||||||
|
// about the initial device list (in the first GETDEVICECHANGE reply).
|
||||||
|
m_first_scan_complete_event.Wait();
|
||||||
|
m_has_initialised = true;
|
||||||
}
|
}
|
||||||
StartThreads();
|
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -117,6 +119,7 @@ bool USBHost::UpdateDevices(const bool always_add_hooks)
|
||||||
return false;
|
return false;
|
||||||
DetectRemovedDevices(plugged_devices, hooks);
|
DetectRemovedDevices(plugged_devices, hooks);
|
||||||
DispatchHooks(hooks);
|
DispatchHooks(hooks);
|
||||||
|
m_first_scan_complete_event.Set();
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#include "Common/CommonTypes.h"
|
#include "Common/CommonTypes.h"
|
||||||
|
#include "Common/Event.h"
|
||||||
#include "Common/Flag.h"
|
#include "Common/Flag.h"
|
||||||
#include "Core/IOS/Device.h"
|
#include "Core/IOS/Device.h"
|
||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
|
@ -76,5 +77,7 @@ private:
|
||||||
// Device scanning thread
|
// Device scanning thread
|
||||||
Common::Flag m_scan_thread_running;
|
Common::Flag m_scan_thread_running;
|
||||||
std::thread m_scan_thread;
|
std::thread m_scan_thread;
|
||||||
|
Common::Event m_first_scan_complete_event;
|
||||||
|
bool m_has_initialised = false;
|
||||||
};
|
};
|
||||||
} // namespace IOS::HLE::Device
|
} // namespace IOS::HLE::Device
|
||||||
|
|
|
@ -18,6 +18,7 @@
|
||||||
|
|
||||||
#include "Common/Assert.h"
|
#include "Common/Assert.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
|
#include "Common/StringUtil.h"
|
||||||
#include "Core/HW/Memmap.h"
|
#include "Core/HW/Memmap.h"
|
||||||
#include "Core/IOS/Device.h"
|
#include "Core/IOS/Device.h"
|
||||||
#include "Core/IOS/IOS.h"
|
#include "Core/IOS/IOS.h"
|
||||||
|
@ -41,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);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -123,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);
|
|
||||||
const int ret = libusb_open(m_device, &m_handle);
|
|
||||||
if (ret != 0)
|
|
||||||
{
|
{
|
||||||
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to open: %s", m_vid, m_pid, libusb_error_name(ret));
|
NOTICE_LOG(IOS_USB, "[%04x:%04x] Opening device", m_vid, m_pid);
|
||||||
return false;
|
const int ret = libusb_open(m_device, &m_handle);
|
||||||
|
if (ret != 0)
|
||||||
|
{
|
||||||
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to open: %s", m_vid, m_pid, libusb_error_name(ret));
|
||||||
|
m_handle = nullptr;
|
||||||
|
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,
|
||||||
|
@ -158,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)
|
||||||
|
@ -184,11 +192,19 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
||||||
if (!m_device_attached)
|
if (!m_device_attached)
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
DEBUG_LOG(IOS_USB,
|
||||||
|
"[%04x:%04x %d] Control: bRequestType=%02x bRequest=%02x wValue=%04x"
|
||||||
|
" wIndex=%04x wLength=%04x",
|
||||||
|
m_vid, m_pid, m_active_interface, cmd->request_type, cmd->request, cmd->value,
|
||||||
|
cmd->index, cmd->length);
|
||||||
|
|
||||||
switch ((cmd->request_type << 8) | cmd->request)
|
switch ((cmd->request_type << 8) | cmd->request)
|
||||||
{
|
{
|
||||||
// The following requests have to go through libusb and cannot be directly sent to the device.
|
// The following requests have to go through libusb and cannot be directly sent to the device.
|
||||||
case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_INTERFACE, REQUEST_SET_INTERFACE):
|
case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_INTERFACE, REQUEST_SET_INTERFACE):
|
||||||
{
|
{
|
||||||
|
INFO_LOG(IOS_USB, "[%04x:%04x %d] REQUEST_SET_INTERFACE index=%04x value=%04x", m_vid, m_pid,
|
||||||
|
m_active_interface, cmd->index, cmd->value);
|
||||||
if (static_cast<u8>(cmd->index) != m_active_interface)
|
if (static_cast<u8>(cmd->index) != m_active_interface)
|
||||||
{
|
{
|
||||||
const int ret = ChangeInterface(static_cast<u8>(cmd->index));
|
const int ret = ChangeInterface(static_cast<u8>(cmd->index));
|
||||||
|
@ -206,9 +222,15 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<CtrlMessage> cmd)
|
||||||
}
|
}
|
||||||
case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_DEVICE, REQUEST_SET_CONFIGURATION):
|
case USBHDR(DIR_HOST2DEVICE, TYPE_STANDARD, REC_DEVICE, REQUEST_SET_CONFIGURATION):
|
||||||
{
|
{
|
||||||
|
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);
|
||||||
|
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;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -230,6 +252,9 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<BulkMessage> cmd)
|
||||||
if (!m_device_attached)
|
if (!m_device_attached)
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
DEBUG_LOG(IOS_USB, "[%04x:%04x %d] Bulk: length=%04x endpoint=%02x", m_vid, m_pid,
|
||||||
|
m_active_interface, cmd->length, cmd->endpoint);
|
||||||
|
|
||||||
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
||||||
libusb_fill_bulk_transfer(transfer, m_handle, cmd->endpoint,
|
libusb_fill_bulk_transfer(transfer, m_handle, cmd->endpoint,
|
||||||
cmd->MakeBuffer(cmd->length).release(), cmd->length, TransferCallback,
|
cmd->MakeBuffer(cmd->length).release(), cmd->length, TransferCallback,
|
||||||
|
@ -244,6 +269,9 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<IntrMessage> cmd)
|
||||||
if (!m_device_attached)
|
if (!m_device_attached)
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
DEBUG_LOG(IOS_USB, "[%04x:%04x %d] Interrupt: length=%04x endpoint=%02x", m_vid, m_pid,
|
||||||
|
m_active_interface, cmd->length, cmd->endpoint);
|
||||||
|
|
||||||
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
libusb_transfer* transfer = libusb_alloc_transfer(0);
|
||||||
libusb_fill_interrupt_transfer(transfer, m_handle, cmd->endpoint,
|
libusb_fill_interrupt_transfer(transfer, m_handle, cmd->endpoint,
|
||||||
cmd->MakeBuffer(cmd->length).release(), cmd->length,
|
cmd->MakeBuffer(cmd->length).release(), cmd->length,
|
||||||
|
@ -258,6 +286,9 @@ int LibusbDevice::SubmitTransfer(std::unique_ptr<IsoMessage> cmd)
|
||||||
if (!m_device_attached)
|
if (!m_device_attached)
|
||||||
return LIBUSB_ERROR_NOT_FOUND;
|
return LIBUSB_ERROR_NOT_FOUND;
|
||||||
|
|
||||||
|
DEBUG_LOG(IOS_USB, "[%04x:%04x %d] Isochronous: length=%04x endpoint=%02x num_packets=%02x",
|
||||||
|
m_vid, m_pid, m_active_interface, cmd->length, cmd->endpoint, cmd->num_packets);
|
||||||
|
|
||||||
libusb_transfer* transfer = libusb_alloc_transfer(cmd->num_packets);
|
libusb_transfer* transfer = libusb_alloc_transfer(cmd->num_packets);
|
||||||
transfer->buffer = cmd->MakeBuffer(cmd->length).release();
|
transfer->buffer = cmd->MakeBuffer(cmd->length).release();
|
||||||
transfer->callback = TransferCallback;
|
transfer->callback = TransferCallback;
|
||||||
|
@ -375,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] Failed to detach kernel driver: %s", m_vid, m_pid,
|
||||||
|
libusb_error_name(ret2));
|
||||||
|
return ret2;
|
||||||
|
}
|
||||||
|
return libusb_claim_interface(m_handle, i);
|
||||||
|
});
|
||||||
|
if (ret < 0)
|
||||||
{
|
{
|
||||||
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 claim all interfaces (configuration %u)", m_vid,
|
||||||
return -1;
|
m_pid, config_num);
|
||||||
}
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
INFO_LOG(IOS_USB, "[%04x:%04x] Detaching interface %d", m_vid, m_pid, m_active_interface);
|
int LibusbDevice::ReleaseAllInterfaces(u8 config_num) const
|
||||||
const int ret = libusb_release_interface(m_handle, m_active_interface);
|
{
|
||||||
if (ret < 0 && ret != LIBUSB_ERROR_NO_DEVICE)
|
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 interface %d: %s", m_vid, m_pid,
|
ERROR_LOG(IOS_USB, "[%04x:%04x] Failed to release all interfaces (configuration %u)", m_vid,
|
||||||
m_active_interface, libusb_error_name(ret));
|
m_pid, config_num);
|
||||||
return ret;
|
|
||||||
}
|
}
|
||||||
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()};
|
||||||
|
|
|
@ -87,7 +87,7 @@ V4IntrMessage::V4IntrMessage(Kernel& ios, const IOCtlRequest& ioctl) : IntrMessa
|
||||||
{
|
{
|
||||||
HIDRequest hid_request;
|
HIDRequest hid_request;
|
||||||
Memory::CopyFromEmu(&hid_request, ioctl.buffer_in, sizeof(hid_request));
|
Memory::CopyFromEmu(&hid_request, ioctl.buffer_in, sizeof(hid_request));
|
||||||
length = static_cast<u16>(Common::swap32(hid_request.interrupt.length));
|
length = Common::swap32(hid_request.interrupt.length);
|
||||||
endpoint = static_cast<u8>(Common::swap32(hid_request.interrupt.endpoint));
|
endpoint = static_cast<u8>(Common::swap32(hid_request.interrupt.endpoint));
|
||||||
data_address = Common::swap32(hid_request.data_addr);
|
data_address = Common::swap32(hid_request.data_addr);
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
#include <cstddef>
|
#include <cstddef>
|
||||||
#include <cstring>
|
#include <cstring>
|
||||||
|
|
||||||
|
#include "Common/Assert.h"
|
||||||
#include "Common/ChunkFile.h"
|
#include "Common/ChunkFile.h"
|
||||||
#include "Common/Logging/Log.h"
|
#include "Common/Logging/Log.h"
|
||||||
#include "Common/Swap.h"
|
#include "Common/Swap.h"
|
||||||
|
@ -31,14 +32,14 @@ V5CtrlMessage::V5CtrlMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
||||||
V5BulkMessage::V5BulkMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
V5BulkMessage::V5BulkMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
||||||
: BulkMessage(ios, ioctlv, ioctlv.GetVector(1)->address)
|
: BulkMessage(ios, ioctlv, ioctlv.GetVector(1)->address)
|
||||||
{
|
{
|
||||||
length = static_cast<u16>(ioctlv.GetVector(1)->size);
|
length = ioctlv.GetVector(1)->size;
|
||||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 18);
|
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 18);
|
||||||
}
|
}
|
||||||
|
|
||||||
V5IntrMessage::V5IntrMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
V5IntrMessage::V5IntrMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
||||||
: IntrMessage(ios, ioctlv, ioctlv.GetVector(1)->address)
|
: IntrMessage(ios, ioctlv, ioctlv.GetVector(1)->address)
|
||||||
{
|
{
|
||||||
length = static_cast<u16>(ioctlv.GetVector(1)->size);
|
length = ioctlv.GetVector(1)->size;
|
||||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 14);
|
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 14);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -48,9 +49,16 @@ V5IsoMessage::V5IsoMessage(Kernel& ios, const IOCtlVRequest& ioctlv)
|
||||||
num_packets = Memory::Read_U8(ioctlv.in_vectors[0].address + 16);
|
num_packets = Memory::Read_U8(ioctlv.in_vectors[0].address + 16);
|
||||||
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 17);
|
endpoint = Memory::Read_U8(ioctlv.in_vectors[0].address + 17);
|
||||||
packet_sizes_addr = ioctlv.GetVector(1)->address;
|
packet_sizes_addr = ioctlv.GetVector(1)->address;
|
||||||
|
u32 total_packet_size = 0;
|
||||||
for (size_t i = 0; i < num_packets; ++i)
|
for (size_t i = 0; i < num_packets; ++i)
|
||||||
packet_sizes.push_back(Memory::Read_U16(static_cast<u32>(packet_sizes_addr + i * sizeof(u16))));
|
{
|
||||||
length = static_cast<u16>(ioctlv.GetVector(2)->size);
|
const u32 packet_size = Memory::Read_U16(static_cast<u32>(packet_sizes_addr + i * sizeof(u16)));
|
||||||
|
packet_sizes.push_back(packet_size);
|
||||||
|
total_packet_size += packet_size;
|
||||||
|
}
|
||||||
|
length = ioctlv.GetVector(2)->size;
|
||||||
|
ASSERT_MSG(IOS_USB, length == total_packet_size, "Wrong buffer size (0x%x != 0x%x)", length,
|
||||||
|
total_packet_size);
|
||||||
}
|
}
|
||||||
} // namespace USB
|
} // namespace USB
|
||||||
|
|
||||||
|
@ -132,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); });
|
||||||
}
|
}
|
||||||
|
@ -104,8 +107,10 @@ s32 USB_VEN::SubmitTransfer(USB::Device& device, const IOCtlVRequest& ioctlv)
|
||||||
|
|
||||||
IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
IPCCommandResult USB_VEN::CancelEndpoint(USBV5Device& device, const IOCtlRequest& request)
|
||||||
{
|
{
|
||||||
const u8 endpoint = static_cast<u8>(Memory::Read_U32(request.buffer_in + 8));
|
const u8 endpoint = Memory::Read_U8(request.buffer_in + 8);
|
||||||
GetDeviceById(device.host_id)->CancelTransfer(endpoint);
|
// IPC_EINVAL (-4) is returned when no transfer was cancelled.
|
||||||
|
if (GetDeviceById(device.host_id)->CancelTransfer(endpoint) < 0)
|
||||||
|
return GetDefaultReply(IPC_EINVAL);
|
||||||
return GetDefaultReply(IPC_SUCCESS);
|
return GetDefaultReply(IPC_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue