diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.cpp | 189 | ||||
| -rw-r--r-- | src/input_common/gcadapter/gc_adapter.h | 46 |
2 files changed, 115 insertions, 120 deletions
diff --git a/src/input_common/gcadapter/gc_adapter.cpp b/src/input_common/gcadapter/gc_adapter.cpp index 3c3b6fbde..a2f1bb67c 100644 --- a/src/input_common/gcadapter/gc_adapter.cpp +++ b/src/input_common/gcadapter/gc_adapter.cpp | |||
| @@ -14,73 +14,15 @@ | |||
| 14 | 14 | ||
| 15 | namespace GCAdapter { | 15 | namespace GCAdapter { |
| 16 | 16 | ||
| 17 | class LibUSBContext { | ||
| 18 | public: | ||
| 19 | explicit LibUSBContext() { | ||
| 20 | init_result = libusb_init(&ctx); | ||
| 21 | } | ||
| 22 | |||
| 23 | ~LibUSBContext() { | ||
| 24 | libusb_exit(ctx); | ||
| 25 | } | ||
| 26 | |||
| 27 | LibUSBContext& operator=(const LibUSBContext&) = delete; | ||
| 28 | LibUSBContext(const LibUSBContext&) = delete; | ||
| 29 | |||
| 30 | LibUSBContext& operator=(LibUSBContext&&) noexcept = delete; | ||
| 31 | LibUSBContext(LibUSBContext&&) noexcept = delete; | ||
| 32 | |||
| 33 | [[nodiscard]] int InitResult() const noexcept { | ||
| 34 | return init_result; | ||
| 35 | } | ||
| 36 | |||
| 37 | [[nodiscard]] libusb_context* get() noexcept { | ||
| 38 | return ctx; | ||
| 39 | } | ||
| 40 | |||
| 41 | private: | ||
| 42 | libusb_context* ctx; | ||
| 43 | int init_result{}; | ||
| 44 | }; | ||
| 45 | |||
| 46 | class LibUSBDeviceHandle { | ||
| 47 | public: | ||
| 48 | explicit LibUSBDeviceHandle(libusb_context* ctx, uint16_t vid, uint16_t pid) noexcept { | ||
| 49 | handle = libusb_open_device_with_vid_pid(ctx, vid, pid); | ||
| 50 | } | ||
| 51 | |||
| 52 | ~LibUSBDeviceHandle() noexcept { | ||
| 53 | if (handle) { | ||
| 54 | libusb_release_interface(handle, 1); | ||
| 55 | libusb_close(handle); | ||
| 56 | } | ||
| 57 | } | ||
| 58 | |||
| 59 | LibUSBDeviceHandle& operator=(const LibUSBDeviceHandle&) = delete; | ||
| 60 | LibUSBDeviceHandle(const LibUSBDeviceHandle&) = delete; | ||
| 61 | |||
| 62 | LibUSBDeviceHandle& operator=(LibUSBDeviceHandle&&) noexcept = delete; | ||
| 63 | LibUSBDeviceHandle(LibUSBDeviceHandle&&) noexcept = delete; | ||
| 64 | |||
| 65 | [[nodiscard]] libusb_device_handle* get() noexcept { | ||
| 66 | return handle; | ||
| 67 | } | ||
| 68 | |||
| 69 | private: | ||
| 70 | libusb_device_handle* handle{}; | ||
| 71 | }; | ||
| 72 | |||
| 73 | Adapter::Adapter() { | 17 | Adapter::Adapter() { |
| 74 | if (usb_adapter_handle) { | 18 | if (usb_adapter_handle != nullptr) { |
| 75 | return; | 19 | return; |
| 76 | } | 20 | } |
| 77 | LOG_INFO(Input, "GC Adapter Initialization started"); | 21 | LOG_INFO(Input, "GC Adapter Initialization started"); |
| 78 | 22 | ||
| 79 | libusb_ctx = std::make_unique<LibUSBContext>(); | 23 | const int init_res = libusb_init(&libusb_ctx); |
| 80 | const int init_res = libusb_ctx->InitResult(); | ||
| 81 | if (init_res == LIBUSB_SUCCESS) { | 24 | if (init_res == LIBUSB_SUCCESS) { |
| 82 | adapter_scan_thread = | 25 | adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); |
| 83 | std::jthread([this](std::stop_token stop_token) { AdapterScanThread(stop_token); }); | ||
| 84 | } else { | 26 | } else { |
| 85 | LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); | 27 | LOG_ERROR(Input, "libusb could not be initialized. failed with error = {}", init_res); |
| 86 | } | 28 | } |
| @@ -90,15 +32,17 @@ Adapter::~Adapter() { | |||
| 90 | Reset(); | 32 | Reset(); |
| 91 | } | 33 | } |
| 92 | 34 | ||
| 93 | void Adapter::AdapterInputThread(std::stop_token stop_token) { | 35 | void Adapter::AdapterInputThread() { |
| 94 | LOG_DEBUG(Input, "GC Adapter input thread started"); | 36 | LOG_DEBUG(Input, "GC Adapter input thread started"); |
| 95 | s32 payload_size{}; | 37 | s32 payload_size{}; |
| 96 | AdapterPayload adapter_payload{}; | 38 | AdapterPayload adapter_payload{}; |
| 97 | 39 | ||
| 98 | adapter_scan_thread = {}; | 40 | if (adapter_scan_thread.joinable()) { |
| 41 | adapter_scan_thread.join(); | ||
| 42 | } | ||
| 99 | 43 | ||
| 100 | while (!stop_token.stop_requested()) { | 44 | while (adapter_input_thread_running) { |
| 101 | libusb_interrupt_transfer(usb_adapter_handle->get(), input_endpoint, adapter_payload.data(), | 45 | libusb_interrupt_transfer(usb_adapter_handle, input_endpoint, adapter_payload.data(), |
| 102 | static_cast<s32>(adapter_payload.size()), &payload_size, 16); | 46 | static_cast<s32>(adapter_payload.size()), &payload_size, 16); |
| 103 | if (IsPayloadCorrect(adapter_payload, payload_size)) { | 47 | if (IsPayloadCorrect(adapter_payload, payload_size)) { |
| 104 | UpdateControllers(adapter_payload); | 48 | UpdateControllers(adapter_payload); |
| @@ -108,8 +52,7 @@ void Adapter::AdapterInputThread(std::stop_token stop_token) { | |||
| 108 | } | 52 | } |
| 109 | 53 | ||
| 110 | if (restart_scan_thread) { | 54 | if (restart_scan_thread) { |
| 111 | adapter_scan_thread = | 55 | adapter_scan_thread = std::thread(&Adapter::AdapterScanThread, this); |
| 112 | std::jthread([this](std::stop_token token) { AdapterScanThread(token); }); | ||
| 113 | restart_scan_thread = false; | 56 | restart_scan_thread = false; |
| 114 | } | 57 | } |
| 115 | } | 58 | } |
| @@ -121,7 +64,7 @@ bool Adapter::IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payloa | |||
| 121 | adapter_payload[0]); | 64 | adapter_payload[0]); |
| 122 | if (input_error_counter++ > 20) { | 65 | if (input_error_counter++ > 20) { |
| 123 | LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); | 66 | LOG_ERROR(Input, "GC adapter timeout, Is the adapter connected?"); |
| 124 | adapter_input_thread.request_stop(); | 67 | adapter_input_thread_running = false; |
| 125 | restart_scan_thread = true; | 68 | restart_scan_thread = true; |
| 126 | } | 69 | } |
| 127 | return false; | 70 | return false; |
| @@ -153,7 +96,7 @@ void Adapter::UpdatePadType(std::size_t port, ControllerTypes pad_type) { | |||
| 153 | return; | 96 | return; |
| 154 | } | 97 | } |
| 155 | // Device changed reset device and set new type | 98 | // Device changed reset device and set new type |
| 156 | pads[port] = {}; | 99 | ResetDevice(port); |
| 157 | pads[port].type = pad_type; | 100 | pads[port].type = pad_type; |
| 158 | } | 101 | } |
| 159 | 102 | ||
| @@ -270,9 +213,8 @@ void Adapter::SendVibrations() { | |||
| 270 | const u8 p3 = pads[2].enable_vibration; | 213 | const u8 p3 = pads[2].enable_vibration; |
| 271 | const u8 p4 = pads[3].enable_vibration; | 214 | const u8 p4 = pads[3].enable_vibration; |
| 272 | std::array<u8, 5> payload = {rumble_command, p1, p2, p3, p4}; | 215 | std::array<u8, 5> payload = {rumble_command, p1, p2, p3, p4}; |
| 273 | const int err = | 216 | const int err = libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, payload.data(), |
| 274 | libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, payload.data(), | 217 | static_cast<s32>(payload.size()), &size, 16); |
| 275 | static_cast<s32>(payload.size()), &size, 16); | ||
| 276 | if (err) { | 218 | if (err) { |
| 277 | LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); | 219 | LOG_DEBUG(Input, "Adapter libusb write failed: {}", libusb_error_name(err)); |
| 278 | if (output_error_counter++ > 5) { | 220 | if (output_error_counter++ > 5) { |
| @@ -291,53 +233,56 @@ bool Adapter::RumblePlay(std::size_t port, u8 amplitude) { | |||
| 291 | return rumble_enabled; | 233 | return rumble_enabled; |
| 292 | } | 234 | } |
| 293 | 235 | ||
| 294 | void Adapter::AdapterScanThread(std::stop_token stop_token) { | 236 | void Adapter::AdapterScanThread() { |
| 295 | usb_adapter_handle = nullptr; | 237 | adapter_scan_thread_running = true; |
| 296 | pads = {}; | 238 | adapter_input_thread_running = false; |
| 297 | while (!stop_token.stop_requested() && !Setup()) { | 239 | if (adapter_input_thread.joinable()) { |
| 298 | std::this_thread::sleep_for(std::chrono::seconds(2)); | 240 | adapter_input_thread.join(); |
| 241 | } | ||
| 242 | ClearLibusbHandle(); | ||
| 243 | ResetDevices(); | ||
| 244 | while (adapter_scan_thread_running && !adapter_input_thread_running) { | ||
| 245 | Setup(); | ||
| 246 | std::this_thread::sleep_for(std::chrono::seconds(1)); | ||
| 299 | } | 247 | } |
| 300 | } | 248 | } |
| 301 | 249 | ||
| 302 | bool Adapter::Setup() { | 250 | void Adapter::Setup() { |
| 303 | constexpr u16 nintendo_vid = 0x057e; | 251 | usb_adapter_handle = libusb_open_device_with_vid_pid(libusb_ctx, 0x057e, 0x0337); |
| 304 | constexpr u16 gc_adapter_pid = 0x0337; | 252 | |
| 305 | usb_adapter_handle = | 253 | if (usb_adapter_handle == NULL) { |
| 306 | std::make_unique<LibUSBDeviceHandle>(libusb_ctx->get(), nintendo_vid, gc_adapter_pid); | 254 | return; |
| 307 | if (!usb_adapter_handle->get()) { | ||
| 308 | return false; | ||
| 309 | } | 255 | } |
| 310 | if (!CheckDeviceAccess()) { | 256 | if (!CheckDeviceAccess()) { |
| 311 | usb_adapter_handle = nullptr; | 257 | ClearLibusbHandle(); |
| 312 | return false; | 258 | return; |
| 313 | } | 259 | } |
| 314 | 260 | ||
| 315 | libusb_device* const device = libusb_get_device(usb_adapter_handle->get()); | 261 | libusb_device* device = libusb_get_device(usb_adapter_handle); |
| 316 | 262 | ||
| 317 | LOG_INFO(Input, "GC adapter is now connected"); | 263 | LOG_INFO(Input, "GC adapter is now connected"); |
| 318 | // GC Adapter found and accessible, registering it | 264 | // GC Adapter found and accessible, registering it |
| 319 | if (GetGCEndpoint(device)) { | 265 | if (GetGCEndpoint(device)) { |
| 266 | adapter_scan_thread_running = false; | ||
| 267 | adapter_input_thread_running = true; | ||
| 320 | rumble_enabled = true; | 268 | rumble_enabled = true; |
| 321 | input_error_counter = 0; | 269 | input_error_counter = 0; |
| 322 | output_error_counter = 0; | 270 | output_error_counter = 0; |
| 323 | adapter_input_thread = | 271 | adapter_input_thread = std::thread(&Adapter::AdapterInputThread, this); |
| 324 | std::jthread([this](std::stop_token stop_token) { AdapterInputThread(stop_token); }); | ||
| 325 | return true; | ||
| 326 | } | 272 | } |
| 327 | return false; | ||
| 328 | } | 273 | } |
| 329 | 274 | ||
| 330 | bool Adapter::CheckDeviceAccess() { | 275 | bool Adapter::CheckDeviceAccess() { |
| 331 | // This fixes payload problems from offbrand GCAdapters | 276 | // This fixes payload problems from offbrand GCAdapters |
| 332 | const s32 control_transfer_error = | 277 | const s32 control_transfer_error = |
| 333 | libusb_control_transfer(usb_adapter_handle->get(), 0x21, 11, 0x0001, 0, nullptr, 0, 1000); | 278 | libusb_control_transfer(usb_adapter_handle, 0x21, 11, 0x0001, 0, nullptr, 0, 1000); |
| 334 | if (control_transfer_error < 0) { | 279 | if (control_transfer_error < 0) { |
| 335 | LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); | 280 | LOG_ERROR(Input, "libusb_control_transfer failed with error= {}", control_transfer_error); |
| 336 | } | 281 | } |
| 337 | 282 | ||
| 338 | s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle->get(), 0); | 283 | s32 kernel_driver_error = libusb_kernel_driver_active(usb_adapter_handle, 0); |
| 339 | if (kernel_driver_error == 1) { | 284 | if (kernel_driver_error == 1) { |
| 340 | kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle->get(), 0); | 285 | kernel_driver_error = libusb_detach_kernel_driver(usb_adapter_handle, 0); |
| 341 | if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { | 286 | if (kernel_driver_error != 0 && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { |
| 342 | LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", | 287 | LOG_ERROR(Input, "libusb_detach_kernel_driver failed with error = {}", |
| 343 | kernel_driver_error); | 288 | kernel_driver_error); |
| @@ -345,13 +290,15 @@ bool Adapter::CheckDeviceAccess() { | |||
| 345 | } | 290 | } |
| 346 | 291 | ||
| 347 | if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { | 292 | if (kernel_driver_error && kernel_driver_error != LIBUSB_ERROR_NOT_SUPPORTED) { |
| 293 | libusb_close(usb_adapter_handle); | ||
| 348 | usb_adapter_handle = nullptr; | 294 | usb_adapter_handle = nullptr; |
| 349 | return false; | 295 | return false; |
| 350 | } | 296 | } |
| 351 | 297 | ||
| 352 | const int interface_claim_error = libusb_claim_interface(usb_adapter_handle->get(), 0); | 298 | const int interface_claim_error = libusb_claim_interface(usb_adapter_handle, 0); |
| 353 | if (interface_claim_error) { | 299 | if (interface_claim_error) { |
| 354 | LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); | 300 | LOG_ERROR(Input, "libusb_claim_interface failed with error = {}", interface_claim_error); |
| 301 | libusb_close(usb_adapter_handle); | ||
| 355 | usb_adapter_handle = nullptr; | 302 | usb_adapter_handle = nullptr; |
| 356 | return false; | 303 | return false; |
| 357 | } | 304 | } |
| @@ -385,17 +332,57 @@ bool Adapter::GetGCEndpoint(libusb_device* device) { | |||
| 385 | // This transfer seems to be responsible for clearing the state of the adapter | 332 | // This transfer seems to be responsible for clearing the state of the adapter |
| 386 | // Used to clear the "busy" state of when the device is unexpectedly unplugged | 333 | // Used to clear the "busy" state of when the device is unexpectedly unplugged |
| 387 | unsigned char clear_payload = 0x13; | 334 | unsigned char clear_payload = 0x13; |
| 388 | libusb_interrupt_transfer(usb_adapter_handle->get(), output_endpoint, &clear_payload, | 335 | libusb_interrupt_transfer(usb_adapter_handle, output_endpoint, &clear_payload, |
| 389 | sizeof(clear_payload), nullptr, 16); | 336 | sizeof(clear_payload), nullptr, 16); |
| 390 | return true; | 337 | return true; |
| 391 | } | 338 | } |
| 392 | 339 | ||
| 340 | void Adapter::JoinThreads() { | ||
| 341 | restart_scan_thread = false; | ||
| 342 | adapter_input_thread_running = false; | ||
| 343 | adapter_scan_thread_running = false; | ||
| 344 | |||
| 345 | if (adapter_scan_thread.joinable()) { | ||
| 346 | adapter_scan_thread.join(); | ||
| 347 | } | ||
| 348 | |||
| 349 | if (adapter_input_thread.joinable()) { | ||
| 350 | adapter_input_thread.join(); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | |||
| 354 | void Adapter::ClearLibusbHandle() { | ||
| 355 | if (usb_adapter_handle) { | ||
| 356 | libusb_release_interface(usb_adapter_handle, 1); | ||
| 357 | libusb_close(usb_adapter_handle); | ||
| 358 | usb_adapter_handle = nullptr; | ||
| 359 | } | ||
| 360 | } | ||
| 361 | |||
| 362 | void Adapter::ResetDevices() { | ||
| 363 | for (std::size_t i = 0; i < pads.size(); ++i) { | ||
| 364 | ResetDevice(i); | ||
| 365 | } | ||
| 366 | } | ||
| 367 | |||
| 368 | void Adapter::ResetDevice(std::size_t port) { | ||
| 369 | pads[port].type = ControllerTypes::None; | ||
| 370 | pads[port].enable_vibration = false; | ||
| 371 | pads[port].rumble_amplitude = 0; | ||
| 372 | pads[port].buttons = 0; | ||
| 373 | pads[port].last_button = PadButton::Undefined; | ||
| 374 | pads[port].axis_values.fill(0); | ||
| 375 | pads[port].reset_origin_counter = 0; | ||
| 376 | } | ||
| 377 | |||
| 393 | void Adapter::Reset() { | 378 | void Adapter::Reset() { |
| 394 | adapter_scan_thread = {}; | 379 | JoinThreads(); |
| 395 | adapter_input_thread = {}; | 380 | ClearLibusbHandle(); |
| 396 | usb_adapter_handle = nullptr; | 381 | ResetDevices(); |
| 397 | pads = {}; | 382 | |
| 398 | libusb_ctx = nullptr; | 383 | if (libusb_ctx) { |
| 384 | libusb_exit(libusb_ctx); | ||
| 385 | } | ||
| 399 | } | 386 | } |
| 400 | 387 | ||
| 401 | std::vector<Common::ParamPackage> Adapter::GetInputDevices() const { | 388 | std::vector<Common::ParamPackage> Adapter::GetInputDevices() const { |
diff --git a/src/input_common/gcadapter/gc_adapter.h b/src/input_common/gcadapter/gc_adapter.h index 28dbcbe05..e5de5e94f 100644 --- a/src/input_common/gcadapter/gc_adapter.h +++ b/src/input_common/gcadapter/gc_adapter.h | |||
| @@ -3,14 +3,11 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | |||
| 7 | #include <algorithm> | 6 | #include <algorithm> |
| 8 | #include <functional> | 7 | #include <functional> |
| 9 | #include <mutex> | 8 | #include <mutex> |
| 10 | #include <stop_token> | ||
| 11 | #include <thread> | 9 | #include <thread> |
| 12 | #include <unordered_map> | 10 | #include <unordered_map> |
| 13 | |||
| 14 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 15 | #include "common/threadsafe_queue.h" | 12 | #include "common/threadsafe_queue.h" |
| 16 | #include "input_common/main.h" | 13 | #include "input_common/main.h" |
| @@ -21,9 +18,6 @@ struct libusb_device_handle; | |||
| 21 | 18 | ||
| 22 | namespace GCAdapter { | 19 | namespace GCAdapter { |
| 23 | 20 | ||
| 24 | class LibUSBContext; | ||
| 25 | class LibUSBDeviceHandle; | ||
| 26 | |||
| 27 | enum class PadButton { | 21 | enum class PadButton { |
| 28 | Undefined = 0x0000, | 22 | Undefined = 0x0000, |
| 29 | ButtonLeft = 0x0001, | 23 | ButtonLeft = 0x0001, |
| @@ -69,11 +63,11 @@ struct GCPadStatus { | |||
| 69 | }; | 63 | }; |
| 70 | 64 | ||
| 71 | struct GCController { | 65 | struct GCController { |
| 72 | ControllerTypes type = ControllerTypes::None; | 66 | ControllerTypes type{}; |
| 73 | bool enable_vibration = false; | 67 | bool enable_vibration{}; |
| 74 | u8 rumble_amplitude = 0; | 68 | u8 rumble_amplitude{}; |
| 75 | u16 buttons = 0; | 69 | u16 buttons{}; |
| 76 | PadButton last_button = PadButton::Undefined; | 70 | PadButton last_button{}; |
| 77 | std::array<s16, 6> axis_values{}; | 71 | std::array<s16, 6> axis_values{}; |
| 78 | std::array<u8, 6> axis_origin{}; | 72 | std::array<u8, 6> axis_origin{}; |
| 79 | u8 reset_origin_counter{}; | 73 | u8 reset_origin_counter{}; |
| @@ -115,9 +109,9 @@ private: | |||
| 115 | void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); | 109 | void UpdateStateAxes(std::size_t port, const AdapterPayload& adapter_payload); |
| 116 | void UpdateVibrations(); | 110 | void UpdateVibrations(); |
| 117 | 111 | ||
| 118 | void AdapterInputThread(std::stop_token stop_token); | 112 | void AdapterInputThread(); |
| 119 | 113 | ||
| 120 | void AdapterScanThread(std::stop_token stop_token); | 114 | void AdapterScanThread(); |
| 121 | 115 | ||
| 122 | bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); | 116 | bool IsPayloadCorrect(const AdapterPayload& adapter_payload, s32 payload_size); |
| 123 | 117 | ||
| @@ -125,7 +119,13 @@ private: | |||
| 125 | void SendVibrations(); | 119 | void SendVibrations(); |
| 126 | 120 | ||
| 127 | /// For use in initialization, querying devices to find the adapter | 121 | /// For use in initialization, querying devices to find the adapter |
| 128 | bool Setup(); | 122 | void Setup(); |
| 123 | |||
| 124 | /// Resets status of all GC controller devices to a disconnected state | ||
| 125 | void ResetDevices(); | ||
| 126 | |||
| 127 | /// Resets status of device connected to a disconnected state | ||
| 128 | void ResetDevice(std::size_t port); | ||
| 129 | 129 | ||
| 130 | /// Returns true if we successfully gain access to GC Adapter | 130 | /// Returns true if we successfully gain access to GC Adapter |
| 131 | bool CheckDeviceAccess(); | 131 | bool CheckDeviceAccess(); |
| @@ -137,15 +137,23 @@ private: | |||
| 137 | /// For shutting down, clear all data, join all threads, release usb | 137 | /// For shutting down, clear all data, join all threads, release usb |
| 138 | void Reset(); | 138 | void Reset(); |
| 139 | 139 | ||
| 140 | std::unique_ptr<LibUSBDeviceHandle> usb_adapter_handle; | 140 | // Join all threads |
| 141 | void JoinThreads(); | ||
| 142 | |||
| 143 | // Release usb handles | ||
| 144 | void ClearLibusbHandle(); | ||
| 145 | |||
| 146 | libusb_device_handle* usb_adapter_handle = nullptr; | ||
| 141 | std::array<GCController, 4> pads; | 147 | std::array<GCController, 4> pads; |
| 142 | Common::SPSCQueue<GCPadStatus> pad_queue; | 148 | Common::SPSCQueue<GCPadStatus> pad_queue; |
| 143 | 149 | ||
| 144 | std::jthread adapter_input_thread; | 150 | std::thread adapter_input_thread; |
| 145 | std::jthread adapter_scan_thread; | 151 | std::thread adapter_scan_thread; |
| 146 | bool restart_scan_thread{}; | 152 | bool adapter_input_thread_running; |
| 153 | bool adapter_scan_thread_running; | ||
| 154 | bool restart_scan_thread; | ||
| 147 | 155 | ||
| 148 | std::unique_ptr<LibUSBContext> libusb_ctx; | 156 | libusb_context* libusb_ctx; |
| 149 | 157 | ||
| 150 | u8 input_endpoint{0}; | 158 | u8 input_endpoint{0}; |
| 151 | u8 output_endpoint{0}; | 159 | u8 output_endpoint{0}; |