37 changes: 23 additions & 14 deletions Source/Core/Core/LibusbUtils.cpp
Expand Up @@ -28,7 +28,9 @@ class Context::Impl
return;

#ifdef _WIN32
libusb_set_option(m_context, LIBUSB_OPTION_USE_USBDK);
const int usbdk_ret = libusb_set_option(m_context, LIBUSB_OPTION_USE_USBDK);
if (usbdk_ret != LIBUSB_SUCCESS && usbdk_ret != LIBUSB_ERROR_NOT_FOUND)
WARN_LOG_FMT(IOS_USB, "Failed to set LIBUSB_OPTION_USE_USBDK: {}", ErrorWrap(usbdk_ret));
#endif
m_event_thread_running.Set();
m_event_thread = std::thread(&Impl::EventThread, this);
Expand All @@ -45,24 +47,24 @@ class Context::Impl
libusb_exit(m_context);
}

libusb_context* GetContext() { return m_context; }
libusb_context* GetContext() const { return m_context; }

bool GetDeviceList(GetDeviceListCallback callback)
int GetDeviceList(GetDeviceListCallback callback) const
{
std::lock_guard lock{m_device_list_mutex};

libusb_device** list;
ssize_t count = libusb_get_device_list(m_context, &list);
if (count < 0)
return false;
return static_cast<int>(count);

for (ssize_t i = 0; i < count; ++i)
{
if (!callback(list[i]))
break;
}
libusb_free_device_list(list, 1);
return true;
return LIBUSB_SUCCESS;
}

private:
Expand All @@ -71,20 +73,24 @@ class Context::Impl
Common::SetCurrentThreadName("libusb thread");
timeval tv{5, 0};
while (m_event_thread_running.IsSet())
libusb_handle_events_timeout_completed(m_context, &tv, nullptr);
{
const int ret = libusb_handle_events_timeout_completed(m_context, &tv, nullptr);
if (ret != LIBUSB_SUCCESS)
WARN_LOG_FMT(IOS_USB, "libusb_handle_events_timeout_completed failed: {}", ErrorWrap(ret));
}
}

libusb_context* m_context = nullptr;
std::mutex m_device_list_mutex;
mutable std::mutex m_device_list_mutex;
Common::Flag m_event_thread_running;
std::thread m_event_thread;
};
#else
class Context::Impl
{
public:
libusb_context* GetContext() { return nullptr; }
bool GetDeviceList(GetDeviceListCallback callback) { return false; }
libusb_context* GetContext() const { return nullptr; }
int GetDeviceList(GetDeviceListCallback callback) const { return -1; }
};
#endif

Expand All @@ -104,19 +110,22 @@ bool Context::IsValid() const
return m_impl->GetContext() != nullptr;
}

bool Context::GetDeviceList(GetDeviceListCallback callback)
int Context::GetDeviceList(GetDeviceListCallback callback) const
{
return m_impl->GetDeviceList(std::move(callback));
}

ConfigDescriptor MakeConfigDescriptor(libusb_device* device, u8 config_num)
std::pair<int, ConfigDescriptor> MakeConfigDescriptor(libusb_device* device, u8 config_num)
{
#if defined(__LIBUSB__)
libusb_config_descriptor* descriptor = nullptr;
if (libusb_get_config_descriptor(device, config_num, &descriptor) == LIBUSB_SUCCESS)
return {descriptor, libusb_free_config_descriptor};
const int ret = libusb_get_config_descriptor(device, config_num, &descriptor);
if (ret == LIBUSB_SUCCESS)
return {ret, ConfigDescriptor{descriptor, libusb_free_config_descriptor}};
#else
const int ret = -1;
#endif
return {nullptr, [](auto) {}};
return {ret, ConfigDescriptor{nullptr, [](auto) {}}};
}

const char* ErrorWrap::GetName() const
Expand Down
5 changes: 3 additions & 2 deletions Source/Core/Core/LibusbUtils.h
Expand Up @@ -6,6 +6,7 @@
#include <fmt/format.h>
#include <functional>
#include <memory>
#include <utility>

#include "Common/CommonTypes.h"

Expand All @@ -31,15 +32,15 @@ class Context
bool IsValid() const;

// Only valid if the context is valid.
bool GetDeviceList(GetDeviceListCallback callback);
int GetDeviceList(GetDeviceListCallback callback) const;

private:
class Impl;
std::unique_ptr<Impl> m_impl;
};

using ConfigDescriptor = UniquePtr<libusb_config_descriptor>;
ConfigDescriptor MakeConfigDescriptor(libusb_device* device, u8 config_num = 0);
std::pair<int, ConfigDescriptor> MakeConfigDescriptor(libusb_device* device, u8 config_num = 0);

// Wrapper for libusb_error to be used with fmt. Note that we can't create a fmt::formatter
// directly for libusb_error as it is a plain enum and most libusb functions actually return an
Expand Down
11 changes: 7 additions & 4 deletions Source/Core/InputCommon/GCAdapter.cpp
Expand Up @@ -71,7 +71,7 @@ enum
ADAPTER_DETECTED = 1,
};

// Current adapter status: detected/not detected/in error (holds the error code)
// Current adapter status: detected/not detected/in error (libusb error codes are negative)
static std::atomic<int> s_status = NO_ADAPTER_DETECTED;
static libusb_device_handle* s_handle = nullptr;
#elif GCADAPTER_USE_ANDROID_IMPLEMENTATION
Expand Down Expand Up @@ -462,7 +462,7 @@ static void Setup()
s_controller_type.fill(ControllerType::None);
s_controller_rumble.fill(0);

s_libusb_context->GetDeviceList([](libusb_device* device) {
const int ret = s_libusb_context->GetDeviceList([](libusb_device* device) {
if (CheckDeviceAccess(device))
{
// Only connect to a single adapter in case the user has multiple connected
Expand All @@ -471,6 +471,8 @@ static void Setup()
}
return true;
});
if (ret != LIBUSB_SUCCESS)
WARN_LOG_FMT(CONTROLLERINTERFACE, "Failed to get device list: {}", LibusbUtils::ErrorWrap(ret));

if (s_status != ADAPTER_DETECTED && prev_status != s_status && s_detect_callback != nullptr)
s_detect_callback();
Expand Down Expand Up @@ -537,7 +539,8 @@ static bool CheckDeviceAccess(libusb_device* device)
// We assume user is using GCAdapterDriver and therefor don't want to detach anything
#if !defined(__APPLE__)
ret = libusb_detach_kernel_driver(s_handle, 0);
detach_failed = ret < 0 && ret != LIBUSB_ERROR_NOT_FOUND && ret != LIBUSB_ERROR_NOT_SUPPORTED;
detach_failed =
ret < LIBUSB_SUCCESS && ret != LIBUSB_ERROR_NOT_FOUND && ret != LIBUSB_ERROR_NOT_SUPPORTED;
#endif
if (detach_failed)
{
Expand All @@ -555,7 +558,7 @@ static bool CheckDeviceAccess(libusb_device* device)
// This call makes Nyko-brand (and perhaps other) adapters work.
// However it returns LIBUSB_ERROR_PIPE with Mayflash adapters.
const int transfer = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000);
if (transfer < 0)
if (transfer < LIBUSB_SUCCESS)
{
WARN_LOG_FMT(CONTROLLERINTERFACE, "libusb_control_transfer failed: {}",
LibusbUtils::ErrorWrap(transfer));
Expand Down
5 changes: 4 additions & 1 deletion Source/Core/UICommon/USBUtils.cpp
Expand Up @@ -11,6 +11,7 @@
#endif

#include "Common/CommonTypes.h"
#include "Common/Logging/Log.h"
#include "Core/LibusbUtils.h"

// Because opening and getting the device name from devices is slow, especially on Windows
Expand Down Expand Up @@ -45,13 +46,15 @@ std::map<std::pair<u16, u16>, std::string> GetInsertedDevices()
if (!context.IsValid())
return devices;

context.GetDeviceList([&](libusb_device* device) {
const int ret = context.GetDeviceList([&](libusb_device* device) {
libusb_device_descriptor descr;
libusb_get_device_descriptor(device, &descr);
const std::pair<u16, u16> vid_pid{descr.idVendor, descr.idProduct};
devices[vid_pid] = GetDeviceName(vid_pid);
return true;
});
if (ret != LIBUSB_SUCCESS)
WARN_LOG_FMT(COMMON, "GetDeviceList failed: {}", LibusbUtils::ErrorWrap(ret));
#endif

return devices;
Expand Down