diff --git a/Source/Core/Core/CMakeLists.txt b/Source/Core/Core/CMakeLists.txt index 498b430d71..78701af198 100644 --- a/Source/Core/Core/CMakeLists.txt +++ b/Source/Core/Core/CMakeLists.txt @@ -10,6 +10,7 @@ add_library(core GeckoCodeConfig.cpp GeckoCode.cpp HotkeyManager.cpp + LibusbUtils.cpp MemTools.cpp Movie.cpp NetPlayClient.cpp diff --git a/Source/Core/Core/Core.vcxproj b/Source/Core/Core/Core.vcxproj index 62b00d0f70..a08761f0d9 100644 --- a/Source/Core/Core/Core.vcxproj +++ b/Source/Core/Core/Core.vcxproj @@ -231,6 +231,9 @@ 4200;%(DisableSpecificWarnings) + + 4200;%(DisableSpecificWarnings) + 4200;%(DisableSpecificWarnings) @@ -497,6 +500,7 @@ + diff --git a/Source/Core/Core/Core.vcxproj.filters b/Source/Core/Core/Core.vcxproj.filters index 68a8141f87..3064754798 100644 --- a/Source/Core/Core/Core.vcxproj.filters +++ b/Source/Core/Core/Core.vcxproj.filters @@ -173,6 +173,7 @@ + @@ -939,6 +940,7 @@ + diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp index becd2032c8..7ccd5c4fac 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.cpp @@ -24,11 +24,11 @@ #include "Common/Network.h" #include "Common/StringUtil.h" #include "Common/Swap.h" -#include "Common/Thread.h" #include "Core/ConfigManager.h" #include "Core/Core.h" #include "Core/HW/Memmap.h" #include "Core/IOS/Device.h" +#include "Core/LibusbUtils.h" #include "VideoCommon/OnScreenDisplay.h" namespace IOS::HLE::Device @@ -57,11 +57,6 @@ static bool IsBluetoothDevice(const libusb_interface_descriptor& descriptor) BluetoothReal::BluetoothReal(Kernel& ios, const std::string& device_name) : BluetoothBase(ios, device_name) { - const int ret = libusb_init(&m_libusb_context); - if (ret < 0) - { - PanicAlertT("Couldn't initialise libusb for Bluetooth passthrough: %s", libusb_error_name(ret)); - } LoadLinkKeys(); } @@ -72,42 +67,27 @@ BluetoothReal::~BluetoothReal() SendHCIResetCommand(); WaitForHCICommandComplete(HCI_CMD_RESET); libusb_release_interface(m_handle, 0); - // libusb_handle_events() may block the libusb thread indefinitely, so we need to - // call libusb_close() first then immediately stop the thread in StopTransferThread. - StopTransferThread(); + libusb_close(m_handle); libusb_unref_device(m_device); } - - libusb_exit(m_libusb_context); SaveLinkKeys(); } IPCCommandResult BluetoothReal::Open(const OpenRequest& request) { - if (!m_libusb_context) + auto& context = LibusbUtils::GetContext(); + if (!context.IsValid()) return GetDefaultReply(IPC_EACCES); - libusb_device** list; - const ssize_t cnt = libusb_get_device_list(m_libusb_context, &list); - if (cnt < 0) - { - ERROR_LOG(IOS_WIIMOTE, "Couldn't get device list: %s", - libusb_error_name(static_cast(cnt))); - return GetDefaultReply(IPC_ENOENT); - } - - for (ssize_t i = 0; i < cnt; ++i) - { - libusb_device* device = list[i]; + context.GetDeviceList([this](libusb_device* device) { libusb_device_descriptor device_descriptor; - libusb_config_descriptor* config_descriptor; libusb_get_device_descriptor(device, &device_descriptor); - const int ret = libusb_get_config_descriptor(device, 0, &config_descriptor); - if (ret != 0) + auto config_descriptor = LibusbUtils::MakeConfigDescriptor(device); + if (!config_descriptor) { - ERROR_LOG(IOS_WIIMOTE, "Failed to get config descriptor for device %04x:%04x: %s", - device_descriptor.idVendor, device_descriptor.idProduct, libusb_error_name(ret)); - continue; + ERROR_LOG(IOS_WIIMOTE, "Failed to get config descriptor for device %04x:%04x", + device_descriptor.idVendor, device_descriptor.idProduct); + return true; } const libusb_interface& interface = config_descriptor->interface[INTERFACE]; @@ -126,12 +106,10 @@ IPCCommandResult BluetoothReal::Open(const OpenRequest& request) device_descriptor.bcdDevice, manufacturer, product, serial_number); m_is_wii_bt_module = device_descriptor.idVendor == 0x57e && device_descriptor.idProduct == 0x305; - libusb_free_config_descriptor(config_descriptor); - break; + return false; } - libusb_free_config_descriptor(config_descriptor); - } - libusb_free_device_list(list, 1); + return true; + }); if (m_handle == nullptr) { @@ -141,8 +119,6 @@ IPCCommandResult BluetoothReal::Open(const OpenRequest& request) return GetDefaultReply(IPC_ENOENT); } - StartTransferThread(); - return Device::Open(request); } @@ -151,7 +127,7 @@ IPCCommandResult BluetoothReal::Close(u32 fd) if (m_handle) { libusb_release_interface(m_handle, 0); - StopTransferThread(); + libusb_close(m_handle); libusb_unref_device(m_device); m_handle = nullptr; } @@ -595,32 +571,6 @@ bool BluetoothReal::OpenDevice(libusb_device* device) return true; } -void BluetoothReal::StartTransferThread() -{ - if (m_thread_running.IsSet()) - return; - m_thread_running.Set(); - m_thread = std::thread(&BluetoothReal::TransferThread, this); -} - -void BluetoothReal::StopTransferThread() -{ - if (m_thread_running.TestAndClear()) - { - libusb_close(m_handle); - m_thread.join(); - } -} - -void BluetoothReal::TransferThread() -{ - Common::SetCurrentThreadName("BT USB Thread"); - while (m_thread_running.IsSet()) - { - libusb_handle_events_completed(m_libusb_context, nullptr); - } -} - // The callbacks are called from libusb code on a separate thread. void BluetoothReal::HandleCtrlTransfer(libusb_transfer* tr) { diff --git a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.h b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.h index 63f4fcc9ef..5070cbee75 100644 --- a/Source/Core/Core/IOS/USB/Bluetooth/BTReal.h +++ b/Source/Core/Core/IOS/USB/Bluetooth/BTReal.h @@ -11,7 +11,6 @@ #include #include #include -#include #include "Common/CommonTypes.h" #include "Common/Flag.h" @@ -22,7 +21,6 @@ #include "Core/IOS/USB/USBV0.h" class PointerWrap; -struct libusb_context; struct libusb_device; struct libusb_device_handle; struct libusb_transfer; @@ -74,10 +72,6 @@ private: libusb_device* m_device = nullptr; libusb_device_handle* m_handle = nullptr; - libusb_context* m_libusb_context = nullptr; - - Common::Flag m_thread_running; - std::thread m_thread; std::mutex m_transfers_mutex; struct PendingTransfer @@ -122,9 +116,6 @@ private: void SaveLinkKeys(); bool OpenDevice(libusb_device* device); - void StartTransferThread(); - void StopTransferThread(); - void TransferThread(); }; } // namespace Device } // namespace IOS::HLE diff --git a/Source/Core/Core/IOS/USB/Host.cpp b/Source/Core/Core/IOS/USB/Host.cpp index 03b9c30c62..15308d2b4e 100644 --- a/Source/Core/Core/IOS/USB/Host.cpp +++ b/Source/Core/Core/IOS/USB/Host.cpp @@ -24,24 +24,15 @@ #include "Core/Core.h" #include "Core/IOS/USB/Common.h" #include "Core/IOS/USB/LibusbDevice.h" +#include "Core/LibusbUtils.h" namespace IOS::HLE::Device { USBHost::USBHost(Kernel& ios, const std::string& device_name) : Device(ios, device_name) { -#ifdef __LIBUSB__ - const int ret = libusb_init(&m_libusb_context); - DEBUG_ASSERT_MSG(IOS_USB, ret == 0, "Failed to init libusb for USB passthrough."); -#endif } -USBHost::~USBHost() -{ -#ifdef __LIBUSB__ - if (m_libusb_context) - libusb_exit(m_libusb_context); -#endif -} +USBHost::~USBHost() = default; IPCCommandResult USBHost::Open(const OpenRequest& request) { @@ -130,43 +121,26 @@ bool USBHost::AddNewDevices(std::set& new_devices, DeviceChangeHooks& hooks if (SConfig::GetInstance().m_usb_passthrough_devices.empty()) return true; - if (m_libusb_context) + auto& context = LibusbUtils::GetContext(); + if (context.IsValid()) { - libusb_device** list; - const ssize_t count = libusb_get_device_list(m_libusb_context, &list); - if (count < 0) - { - WARN_LOG(IOS_USB, "Failed to get device list: %s", - libusb_error_name(static_cast(count))); - return false; - } - - for (ssize_t i = 0; i < count; ++i) - { - libusb_device* device = list[i]; + context.GetDeviceList([&](libusb_device* device) { libusb_device_descriptor descriptor; libusb_get_device_descriptor(device, &descriptor); - if (!SConfig::GetInstance().IsUSBDeviceWhitelisted( - {descriptor.idVendor, descriptor.idProduct})) - { - libusb_unref_device(device); - continue; - } + const std::pair vid_pid = {descriptor.idVendor, descriptor.idProduct}; + if (!SConfig::GetInstance().IsUSBDeviceWhitelisted(vid_pid)) + return true; auto usb_device = std::make_unique(m_ios, device, descriptor); if (!ShouldAddDevice(*usb_device)) - { - libusb_unref_device(device); - continue; - } + return true; + const u64 id = usb_device->GetId(); new_devices.insert(id); if (AddDevice(std::move(usb_device)) || always_add_hooks) hooks.emplace(GetDeviceById(id), ChangeEvent::Inserted); - else - libusb_unref_device(device); - } - libusb_free_device_list(list, 0); + return true; + }); } #endif return true; @@ -219,27 +193,6 @@ void USBHost::StartThreads() } }); } - -#ifdef __LIBUSB__ - if (!m_event_thread_running.IsSet() && m_libusb_context) - { - m_event_thread_running.Set(); - m_event_thread = std::thread([this] { - Common::SetCurrentThreadName("USB Passthrough Thread"); - while (m_event_thread_running.IsSet()) - { - if (SConfig::GetInstance().m_usb_passthrough_devices.empty()) - { - Common::SleepCurrentThread(50); - continue; - } - - static timeval tv = {0, 50000}; - libusb_handle_events_timeout_completed(m_libusb_context, &tv, nullptr); - } - }); - } -#endif } void USBHost::StopThreads() @@ -251,10 +204,6 @@ void USBHost::StopThreads() DeviceChangeHooks hooks; DetectRemovedDevices(std::set(), hooks); DispatchHooks(hooks); -#ifdef __LIBUSB__ - if (m_event_thread_running.TestAndClear()) - m_event_thread.join(); -#endif } IPCCommandResult USBHost::HandleTransfer(std::shared_ptr device, u32 request, diff --git a/Source/Core/Core/IOS/USB/Host.h b/Source/Core/Core/IOS/USB/Host.h index dc37efe4c6..40e42193d2 100644 --- a/Source/Core/Core/IOS/USB/Host.h +++ b/Source/Core/Core/IOS/USB/Host.h @@ -22,7 +22,6 @@ #include "Core/IOS/USB/Common.h" class PointerWrap; -struct libusb_context; namespace IOS::HLE::Device { @@ -67,13 +66,6 @@ private: void DetectRemovedDevices(const std::set& plugged_devices, DeviceChangeHooks& hooks); void DispatchHooks(const DeviceChangeHooks& hooks); -#ifdef __LIBUSB__ - libusb_context* m_libusb_context = nullptr; - - // Event thread for libusb - Common::Flag m_event_thread_running; - std::thread m_event_thread; -#endif // Device scanning thread Common::Flag m_scan_thread_running; std::thread m_scan_thread; diff --git a/Source/Core/Core/IOS/USB/LibusbDevice.cpp b/Source/Core/Core/IOS/USB/LibusbDevice.cpp index df346ae95b..a1a9dba531 100644 --- a/Source/Core/Core/IOS/USB/LibusbDevice.cpp +++ b/Source/Core/Core/IOS/USB/LibusbDevice.cpp @@ -37,7 +37,7 @@ LibusbDevice::LibusbDevice(Kernel& ios, libusb_device* device, static_cast(libusb_get_device_address(device))); for (u8 i = 0; i < descriptor.bNumConfigurations; ++i) - m_config_descriptors.emplace_back(std::make_unique(m_device, i)); + m_config_descriptors.emplace_back(LibusbUtils::MakeConfigDescriptor(m_device, i)); } LibusbDevice::~LibusbDevice() @@ -65,13 +65,13 @@ std::vector LibusbDevice::GetConfigurations() const std::vector descriptors; for (const auto& config_descriptor : m_config_descriptors) { - if (!config_descriptor->IsValid()) + if (!config_descriptor) { ERROR_LOG(IOS_USB, "Ignoring invalid config descriptor for %04x:%04x", m_vid, m_pid); continue; } ConfigDescriptor descriptor; - std::memcpy(&descriptor, config_descriptor->Get(), sizeof(descriptor)); + std::memcpy(&descriptor, config_descriptor.get(), sizeof(descriptor)); descriptors.push_back(descriptor); } return descriptors; @@ -80,14 +80,14 @@ std::vector LibusbDevice::GetConfigurations() const std::vector LibusbDevice::GetInterfaces(const u8 config) const { std::vector descriptors; - if (config >= m_config_descriptors.size() || !m_config_descriptors[config]->IsValid()) + if (config >= m_config_descriptors.size() || !m_config_descriptors[config]) { ERROR_LOG(IOS_USB, "Invalid config descriptor %u for %04x:%04x", config, m_vid, m_pid); return descriptors; } - for (u8 i = 0; i < m_config_descriptors[config]->Get()->bNumInterfaces; ++i) + for (u8 i = 0; i < m_config_descriptors[config]->bNumInterfaces; ++i) { - const libusb_interface& interface = m_config_descriptors[config]->Get()->interface[i]; + const libusb_interface& interface = m_config_descriptors[config]->interface[i]; for (u8 a = 0; a < interface.num_altsetting; ++a) { InterfaceDescriptor descriptor; @@ -102,13 +102,13 @@ std::vector LibusbDevice::GetEndpoints(const u8 config, const u8 interface_number, const u8 alt_setting) const { std::vector descriptors; - if (config >= m_config_descriptors.size() || !m_config_descriptors[config]->IsValid()) + if (config >= m_config_descriptors.size() || !m_config_descriptors[config]) { ERROR_LOG(IOS_USB, "Invalid config descriptor %u for %04x:%04x", config, m_vid, m_pid); return descriptors; } - ASSERT(interface_number < m_config_descriptors[config]->Get()->bNumInterfaces); - const auto& interface = m_config_descriptors[config]->Get()->interface[interface_number]; + ASSERT(interface_number < m_config_descriptors[config]->bNumInterfaces); + const auto& interface = m_config_descriptors[config]->interface[interface_number]; ASSERT(alt_setting < interface.num_altsetting); const libusb_interface_descriptor& interface_descriptor = interface.altsetting[alt_setting]; for (u8 i = 0; i < interface_descriptor.bNumEndpoints; ++i) @@ -403,16 +403,16 @@ void LibusbDevice::TransferEndpoint::CancelTransfers() int LibusbDevice::GetNumberOfAltSettings(const u8 interface_number) { - return m_config_descriptors[0]->Get()->interface[interface_number].num_altsetting; + return m_config_descriptors[0]->interface[interface_number].num_altsetting; } template static int DoForEachInterface(const Configs& configs, u8 config_num, Function action) { int ret = LIBUSB_ERROR_NOT_FOUND; - if (configs.size() <= config_num || !configs[config_num]->IsValid()) + if (configs.size() <= config_num || !configs[config_num]) return ret; - for (u8 i = 0; i < configs[config_num]->Get()->bNumInterfaces; ++i) + for (u8 i = 0; i < configs[config_num]->bNumInterfaces; ++i) { ret = action(i); if (ret < 0) @@ -462,16 +462,4 @@ int LibusbDevice::ReleaseAllInterfacesForCurrentConfig() const return get_config_ret; return ReleaseAllInterfaces(config_num); } - -LibusbConfigDescriptor::LibusbConfigDescriptor(libusb_device* device, const u8 config_num) -{ - if (libusb_get_config_descriptor(device, config_num, &m_descriptor) != LIBUSB_SUCCESS) - m_descriptor = nullptr; -} - -LibusbConfigDescriptor::~LibusbConfigDescriptor() -{ - if (m_descriptor != nullptr) - libusb_free_config_descriptor(m_descriptor); -} } // namespace IOS::HLE::USB diff --git a/Source/Core/Core/IOS/USB/LibusbDevice.h b/Source/Core/Core/IOS/USB/LibusbDevice.h index a068a6c9e4..5a9700922f 100644 --- a/Source/Core/Core/IOS/USB/LibusbDevice.h +++ b/Source/Core/Core/IOS/USB/LibusbDevice.h @@ -15,8 +15,8 @@ #include "Common/CommonTypes.h" #include "Core/IOS/USB/Common.h" +#include "Core/LibusbUtils.h" -struct libusb_config_descriptor; struct libusb_device; struct libusb_device_descriptor; struct libusb_device_handle; @@ -24,19 +24,6 @@ struct libusb_transfer; namespace IOS::HLE::USB { -// Simple wrapper around libusb_get_config_descriptor and libusb_free_config_descriptor. -class LibusbConfigDescriptor final -{ -public: - explicit LibusbConfigDescriptor(libusb_device* device, u8 config_num = 0); - ~LibusbConfigDescriptor(); - libusb_config_descriptor* Get() const { return m_descriptor; } - bool IsValid() const { return m_descriptor != nullptr; } - -private: - libusb_config_descriptor* m_descriptor = nullptr; -}; - class LibusbDevice final : public Device { public: @@ -62,7 +49,7 @@ public: private: Kernel& m_ios; - std::vector> m_config_descriptors; + std::vector m_config_descriptors; u16 m_vid = 0; u16 m_pid = 0; u8 m_active_interface = 0; diff --git a/Source/Core/Core/LibusbUtils.cpp b/Source/Core/Core/LibusbUtils.cpp new file mode 100644 index 0000000000..2ee7838c33 --- /dev/null +++ b/Source/Core/Core/LibusbUtils.cpp @@ -0,0 +1,127 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#include +#include + +#if defined(__LIBUSB__) +#include +#endif + +#include "Common/Assert.h" +#include "Common/Flag.h" +#include "Common/Thread.h" +#include "Core/LibusbUtils.h" + +namespace LibusbUtils +{ +#if defined(__LIBUSB__) +class Context::Impl +{ +public: + Impl() + { + const int ret = libusb_init(&m_context); + ASSERT_MSG(IOS_USB, ret == LIBUSB_SUCCESS, "Failed to init libusb: %s", libusb_error_name(ret)); + if (ret != LIBUSB_SUCCESS) + return; + +#ifdef _WIN32 + libusb_set_option(m_context, LIBUSB_OPTION_USE_USBDK); +#endif + m_event_thread_running.Set(); + m_event_thread = std::thread(&Impl::EventThread, this); + } + + ~Impl() + { + if (!m_context || !m_event_thread_running.TestAndClear()) + return; +#if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000105 + libusb_interrupt_event_handler(m_context); +#endif + m_event_thread.join(); + libusb_exit(m_context); + } + + libusb_context* GetContext() { return m_context; } + + bool GetDeviceList(GetDeviceListCallback callback) + { + 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; + + for (ssize_t i = 0; i < count; ++i) + { + if (!callback(list[i])) + break; + } + libusb_free_device_list(list, 1); + return true; + } + +private: + void EventThread() + { + Common::SetCurrentThreadName("libusb thread"); + timeval tv{5, 0}; + while (m_event_thread_running.IsSet()) + libusb_handle_events_timeout_completed(m_context, &tv, nullptr); + } + + libusb_context* m_context = nullptr; + 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; } +}; +#endif + +Context::Context() : m_impl{std::make_unique()} +{ +} + +Context::~Context() = default; + +Context::operator libusb_context*() const +{ + return m_impl->GetContext(); +} + +bool Context::IsValid() const +{ + return m_impl->GetContext() != nullptr; +} + +bool Context::GetDeviceList(GetDeviceListCallback callback) +{ + return m_impl->GetDeviceList(std::move(callback)); +} + +Context& GetContext() +{ + static Context s_context; + return s_context; +} + +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}; +#endif + return {nullptr, [](auto) {}}; +} +} // namespace LibusbUtils diff --git a/Source/Core/Core/LibusbUtils.h b/Source/Core/Core/LibusbUtils.h new file mode 100644 index 0000000000..ded3bd9940 --- /dev/null +++ b/Source/Core/Core/LibusbUtils.h @@ -0,0 +1,48 @@ +// Copyright 2019 Dolphin Emulator Project +// Licensed under GPLv2+ +// Refer to the license.txt file included. + +#pragma once + +#include +#include + +#include "Common/CommonTypes.h" + +struct libusb_config_descriptor; +struct libusb_context; +struct libusb_device; + +namespace LibusbUtils +{ +template +using UniquePtr = std::unique_ptr; + +// Return false to stop iterating the device list. +using GetDeviceListCallback = std::function; + +class Context +{ +public: + Context(); + ~Context(); + + operator libusb_context*() const; + bool IsValid() const; + + // Only valid if the context is valid. + bool GetDeviceList(GetDeviceListCallback callback); + +private: + class Impl; + std::unique_ptr m_impl; +}; + +// Use this to get a libusb context. Do *not* use any other context +// because some libusb backends such as UsbDk only work properly with a single context. +// Additionally, device lists must be retrieved using GetDeviceList for thread safety reasons. +Context& GetContext(); + +using ConfigDescriptor = UniquePtr; +ConfigDescriptor MakeConfigDescriptor(libusb_device* device, u8 config_num = 0); +} // namespace LibusbUtils diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 196f693b07..4e008317df 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -15,6 +15,7 @@ #include "Core/CoreTiming.h" #include "Core/HW/SI/SI.h" #include "Core/HW/SystemTimers.h" +#include "Core/LibusbUtils.h" #include "Core/NetPlayProto.h" #include "InputCommon/GCAdapter.h" @@ -54,7 +55,6 @@ static Common::Flag s_adapter_detect_thread_running; static std::function s_detect_callback; static bool s_libusb_driver_not_supported = false; -static libusb_context* s_libusb_context; #if defined(__FreeBSD__) && __FreeBSD__ >= 11 static bool s_libusb_hotplug_enabled = true; #else @@ -127,6 +127,7 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl static void ScanThreadFunc() { + auto& context = LibusbUtils::GetContext(); Common::SetCurrentThreadName("GC Adapter Scanning Thread"); NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread started"); @@ -137,7 +138,7 @@ static void ScanThreadFunc() if (s_libusb_hotplug_enabled) { if (libusb_hotplug_register_callback( - s_libusb_context, + context, (libusb_hotplug_event)(LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED | LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT), LIBUSB_HOTPLUG_ENUMERATE, 0x057e, 0x0337, LIBUSB_HOTPLUG_MATCH_ANY, HotplugCallback, @@ -148,24 +149,19 @@ static void ScanThreadFunc() } #endif + if (s_libusb_hotplug_enabled) + return; + while (s_adapter_detect_thread_running.IsSet()) { - if (s_libusb_hotplug_enabled) + if (s_handle == nullptr) { - static timeval tv = {0, 500000}; - libusb_handle_events_timeout(s_libusb_context, &tv); - } - else - { - if (s_handle == nullptr) - { - std::lock_guard lk(s_init_mutex); - Setup(); - if (s_detected && s_detect_callback != nullptr) - s_detect_callback(); - } - Common::SleepCurrentThread(500); + std::lock_guard lk(s_init_mutex); + Setup(); + if (s_detected && s_detect_callback != nullptr) + s_detect_callback(); } + Common::SleepCurrentThread(500); } NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); } @@ -198,13 +194,8 @@ void StartScanThread() { if (s_adapter_detect_thread_running.IsSet()) return; - - const int ret = libusb_init(&s_libusb_context); - if (ret < 0) - { - ERROR_LOG(SERIALINTERFACE, "libusb_init failed with error: %d", ret); + if (!LibusbUtils::GetContext().IsValid()) return; - } s_adapter_detect_thread_running.Set(true); s_adapter_detect_thread = std::thread(ScanThreadFunc); } @@ -219,27 +210,21 @@ void StopScanThread() static void Setup() { - libusb_device** list; - ssize_t cnt = libusb_get_device_list(s_libusb_context, &list); - for (int i = 0; i < SerialInterface::MAX_SI_CHANNELS; i++) { s_controller_type[i] = ControllerTypes::CONTROLLER_NONE; s_controller_rumble[i] = 0; } - for (int d = 0; d < cnt; d++) - { - libusb_device* device = list[d]; + LibusbUtils::GetContext().GetDeviceList([](libusb_device* device) { if (CheckDeviceAccess(device)) { // Only connect to a single adapter in case the user has multiple connected AddGCAdapter(device); - break; + return false; } - } - - libusb_free_device_list(list, 1); + return true; + }); } static bool CheckDeviceAccess(libusb_device* device) @@ -342,16 +327,11 @@ void Shutdown() { StopScanThread(); #if defined(LIBUSB_API_VERSION) && LIBUSB_API_VERSION >= 0x01000102 - if (s_libusb_context && s_libusb_hotplug_enabled) - libusb_hotplug_deregister_callback(s_libusb_context, s_hotplug_handle); + if (LibusbUtils::GetContext().IsValid() && s_libusb_hotplug_enabled) + libusb_hotplug_deregister_callback(LibusbUtils::GetContext(), s_hotplug_handle); #endif Reset(); - if (s_libusb_context) - { - libusb_exit(s_libusb_context); - s_libusb_context = nullptr; - } s_libusb_driver_not_supported = false; } diff --git a/Source/Core/UICommon/USBUtils.cpp b/Source/Core/UICommon/USBUtils.cpp index 001e1dbbb1..42cf815a12 100644 --- a/Source/Core/UICommon/USBUtils.cpp +++ b/Source/Core/UICommon/USBUtils.cpp @@ -8,6 +8,7 @@ #include "Common/CommonTypes.h" #include "Common/StringUtil.h" +#include "Core/LibusbUtils.h" #include "UICommon/USBUtils.h" // Because opening and getting the device name from devices is slow, especially on Windows @@ -34,21 +35,17 @@ std::map, std::string> GetInsertedDevices() std::map, std::string> devices; #ifdef __LIBUSB__ - libusb_context* context = nullptr; - if (libusb_init(&context) < 0) + auto& context = LibusbUtils::GetContext(); + if (!context.IsValid()) return devices; - libusb_device** list; - const ssize_t cnt = libusb_get_device_list(context, &list); - for (ssize_t i = 0; i < cnt; ++i) - { + context.GetDeviceList([&](libusb_device* device) { libusb_device_descriptor descr; - libusb_get_device_descriptor(list[i], &descr); + libusb_get_device_descriptor(device, &descr); const std::pair vid_pid{descr.idVendor, descr.idProduct}; devices[vid_pid] = GetDeviceName(vid_pid); - } - libusb_free_device_list(list, 1); - libusb_exit(context); + return true; + }); #endif return devices;