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