summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/input_common/gcadapter/gc_adapter.cpp189
-rw-r--r--src/input_common/gcadapter/gc_adapter.h46
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
15namespace GCAdapter { 15namespace GCAdapter {
16 16
17class LibUSBContext {
18public:
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
41private:
42 libusb_context* ctx;
43 int init_result{};
44};
45
46class LibUSBDeviceHandle {
47public:
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
69private:
70 libusb_device_handle* handle{};
71};
72
73Adapter::Adapter() { 17Adapter::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
93void Adapter::AdapterInputThread(std::stop_token stop_token) { 35void 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
294void Adapter::AdapterScanThread(std::stop_token stop_token) { 236void 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
302bool Adapter::Setup() { 250void 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
330bool Adapter::CheckDeviceAccess() { 275bool 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
340void 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
354void 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
362void Adapter::ResetDevices() {
363 for (std::size_t i = 0; i < pads.size(); ++i) {
364 ResetDevice(i);
365 }
366}
367
368void 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
393void Adapter::Reset() { 378void 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
401std::vector<Common::ParamPackage> Adapter::GetInputDevices() const { 388std::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
22namespace GCAdapter { 19namespace GCAdapter {
23 20
24class LibUSBContext;
25class LibUSBDeviceHandle;
26
27enum class PadButton { 21enum class PadButton {
28 Undefined = 0x0000, 22 Undefined = 0x0000,
29 ButtonLeft = 0x0001, 23 ButtonLeft = 0x0001,
@@ -69,11 +63,11 @@ struct GCPadStatus {
69}; 63};
70 64
71struct GCController { 65struct 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};