From 54850e936c4fb3d78d6dfc627822a2c495262c1b Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 18 Jun 2023 14:31:01 -0700 Subject: [PATCH 1/6] Fix memory leak in libusb code --- Source/Core/InputCommon/GCAdapter.cpp | 1 + 1 file changed, 1 insertion(+) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index a3853e9e6c..21a1255fb0 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -636,6 +636,7 @@ static void AddGCAdapter(libusb_device* device) } } } + libusb_free_config_descriptor(config); int size = 0; std::array payload = {0x13}; From afb5eff42685a0b5f2a91ed64237aaf7e2aa9468 Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 18 Jun 2023 14:28:26 -0700 Subject: [PATCH 2/6] Don't burn a CPU core and spam logs when GC Adapter fails --- Source/Core/InputCommon/GCAdapter.cpp | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 21a1255fb0..cacb73bc79 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -211,6 +211,10 @@ static void ReadThreadFunc() ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_interrupt_transfer failed: {}", LibusbUtils::ErrorWrap(error)); } + if (error == LIBUSB_ERROR_IO) + { + break; + } ProcessInputPayload(input_buffer.data(), payload_size); From 559a16da4999c1159bb4d594a969f13e77100a1c Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 18 Jun 2023 14:28:26 -0700 Subject: [PATCH 3/6] Reset GC adapter upon IO error after sleep-wake Fixes GC adapter breaking on sleep-wake on Linux and burning a full CPU core. This is cleaner than alternative approaches. --- Source/Core/InputCommon/GCAdapter.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index cacb73bc79..6088256a55 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -203,9 +203,8 @@ static void ReadThreadFunc() std::array input_buffer; int payload_size = 0; - const int error = - libusb_interrupt_transfer(s_handle, s_endpoint_in, input_buffer.data(), - int(input_buffer.size()), &payload_size, USB_TIMEOUT_MS); + int error = libusb_interrupt_transfer(s_handle, s_endpoint_in, input_buffer.data(), + int(input_buffer.size()), &payload_size, USB_TIMEOUT_MS); if (error != LIBUSB_SUCCESS) { ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_interrupt_transfer failed: {}", @@ -213,7 +212,16 @@ static void ReadThreadFunc() } if (error == LIBUSB_ERROR_IO) { - break; + // s_read_adapter_thread_running is cleared by the joiner, not the stopper. + + // Reset the device, which may trigger a replug. + error = libusb_reset_device(s_handle); + ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_reset_device: {}", + LibusbUtils::ErrorWrap(error)); + if (error != 0) + { + break; + } } ProcessInputPayload(input_buffer.data(), payload_size); From c893ccca58cb504b003b100880cc5074faf9e822 Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 2 Jul 2023 22:24:08 -0700 Subject: [PATCH 4/6] Workaround GC adapter detection breaking when reset fails --- Source/Core/InputCommon/GCAdapter.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index 6088256a55..bb1542988e 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -218,10 +218,9 @@ static void ReadThreadFunc() error = libusb_reset_device(s_handle); ERROR_LOG_FMT(CONTROLLERINTERFACE, "Read: libusb_reset_device: {}", LibusbUtils::ErrorWrap(error)); - if (error != 0) - { - break; - } + + // If error is nonzero, try fixing it next loop iteration. We can't easily return + // and cleanup program state without getting another thread to call Reset(). } ProcessInputPayload(input_buffer.data(), payload_size); From 5d0f1bd10b1af825a80ab78160fe7c9924e835e9 Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Sun, 2 Jul 2023 20:07:37 -0700 Subject: [PATCH 5/6] Switch libusb_config_descriptor to RAII type --- Source/Core/InputCommon/GCAdapter.cpp | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/Source/Core/InputCommon/GCAdapter.cpp b/Source/Core/InputCommon/GCAdapter.cpp index bb1542988e..ec3c3a1fb3 100644 --- a/Source/Core/InputCommon/GCAdapter.cpp +++ b/Source/Core/InputCommon/GCAdapter.cpp @@ -625,8 +625,8 @@ static bool CheckDeviceAccess(libusb_device* device) static void AddGCAdapter(libusb_device* device) { - libusb_config_descriptor* config = nullptr; - if (const int error = libusb_get_config_descriptor(device, 0, &config); error != LIBUSB_SUCCESS) + auto [error, config] = LibusbUtils::MakeConfigDescriptor(device); + if (error != LIBUSB_SUCCESS) { WARN_LOG_FMT(CONTROLLERINTERFACE, "libusb_get_config_descriptor failed: {}", LibusbUtils::ErrorWrap(error)); @@ -647,13 +647,12 @@ static void AddGCAdapter(libusb_device* device) } } } - libusb_free_config_descriptor(config); + config.reset(); int size = 0; std::array payload = {0x13}; - const int error = - libusb_interrupt_transfer(s_handle, s_endpoint_out, payload.data(), - CONTROLER_OUTPUT_INIT_PAYLOAD_SIZE, &size, USB_TIMEOUT_MS); + error = libusb_interrupt_transfer(s_handle, s_endpoint_out, payload.data(), + CONTROLER_OUTPUT_INIT_PAYLOAD_SIZE, &size, USB_TIMEOUT_MS); if (error != LIBUSB_SUCCESS) { WARN_LOG_FMT(CONTROLLERINTERFACE, "AddGCAdapter: libusb_interrupt_transfer failed: {}", From c8df26554bc5433bff13aaff934d1539226577d7 Mon Sep 17 00:00:00 2001 From: nyanpasu64 Date: Thu, 29 Jun 2023 22:50:01 -0700 Subject: [PATCH 6/6] Fix GC adapter not being detected when you enable controller in settings GCAdapter::UseAdapter() reads s_is_adapter_wanted, which gets initialized by config_guard.~ConfigChangeCallbackGuard(). So we must wait until after destroying the config guard to know whether we have any controllers set to GC Adapter. --- .../Core/DolphinQt/Config/GamecubeControllersWidget.cpp | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp b/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp index c27ab2e99f..38ea1e4e7f 100644 --- a/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp +++ b/Source/Core/DolphinQt/Config/GamecubeControllersWidget.cpp @@ -198,12 +198,11 @@ void GamecubeControllersWidget::SaveSettings() static_cast(i)); } } - - if (GCAdapter::UseAdapter()) - GCAdapter::StartScanThread(); - else - GCAdapter::StopScanThread(); } + if (GCAdapter::UseAdapter()) + GCAdapter::StartScanThread(); + else + GCAdapter::StopScanThread(); SConfig::GetInstance().SaveSettings(); }