diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 5172000dda..3b8e823b24 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -38,7 +38,7 @@ enum }; // Current adapter status: detected/not detected/in error (holds the error code) -static int s_status = NO_ADAPTER_DETECTED; +static std::atomic s_status = NO_ADAPTER_DETECTED; static libusb_device_handle* s_handle = nullptr; static u8 s_controller_type[SerialInterface::MAX_SI_CHANNELS] = { ControllerTypes::CONTROLLER_NONE, ControllerTypes::CONTROLLER_NONE, @@ -60,6 +60,7 @@ static Common::Event s_rumble_data_available; static std::mutex s_init_mutex; static std::thread s_adapter_detect_thread; static Common::Flag s_adapter_detect_thread_running; +static Common::Event s_hotplug_event; static std::function s_detect_callback; @@ -125,15 +126,8 @@ static int HotplugCallback(libusb_context* ctx, libusb_device* dev, libusb_hotpl { if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_ARRIVED) { - if (s_handle == nullptr && CheckDeviceAccess(dev)) - { - std::lock_guard lk(s_init_mutex); - AddGCAdapter(dev); - } - else if (s_status < 0 && s_detect_callback != nullptr) - { - s_detect_callback(); - } + if (s_handle == nullptr) + s_hotplug_event.Set(); } else if (event == LIBUSB_HOTPLUG_EVENT_DEVICE_LEFT) { @@ -175,9 +169,6 @@ static void ScanThreadFunc() } #endif - if (s_libusb_hotplug_enabled) - return; - while (s_adapter_detect_thread_running.IsSet()) { if (s_handle == nullptr) @@ -185,7 +176,11 @@ static void ScanThreadFunc() std::lock_guard lk(s_init_mutex); Setup(); } - Common::SleepCurrentThread(500); + + if (s_libusb_hotplug_enabled) + s_hotplug_event.Wait(); + else + Common::SleepCurrentThread(500); } NOTICE_LOG(SERIALINTERFACE, "GC Adapter scanning thread stopped"); } @@ -228,6 +223,7 @@ void StopScanThread() { if (s_adapter_detect_thread_running.TestAndClear()) { + s_hotplug_event.Set(); s_adapter_detect_thread.join(); } } @@ -307,6 +303,10 @@ static bool CheckDeviceAccess(libusb_device* device) ERROR_LOG(SERIALINTERFACE, "libusb_detach_kernel_driver failed with error: %d", ret); } + ret = libusb_control_transfer(s_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 10000); + if (ret < 0) + ERROR_LOG(SERIALINTERFACE, "libusb_control_transfer failed with error: %d", ret); + // this split is needed so that we don't avoid claiming the interface when // detaching the kernel driver is successful if (ret != 0 && ret != LIBUSB_ERROR_NOT_SUPPORTED) @@ -431,9 +431,9 @@ GCPadStatus Input(int chan) if (payload_size != sizeof(controller_payload_copy) || controller_payload_copy[0] != LIBUSB_DT_HID) { + // This can occur for a few frames on initialization. ERROR_LOG(SERIALINTERFACE, "error reading payload (size: %d, type: %02x)", payload_size, controller_payload_copy[0]); - Reset(); } else { @@ -575,7 +575,7 @@ bool IsDetected(const char** error_message) } if (error_message) - *error_message = libusb_strerror(static_cast(s_status)); + *error_message = libusb_strerror(static_cast(s_status.load())); return false; }