1 /*
2 Simple DirectMedia Layer
3 Copyright (C) 1997-2021 Sam Lantinga <slouken@libsdl.org>
4
5 This software is provided 'as-is', without any express or implied
6 warranty. In no event will the authors be held liable for any damages
7 arising from the use of this software.
8
9 Permission is granted to anyone to use this software for any purpose,
10 including commercial applications, and to alter it and redistribute it
11 freely, subject to the following restrictions:
12
13 1. The origin of this software must not be misrepresented; you must not
14 claim that you wrote the original software. If you use this software
15 in a product, an acknowledgment in the product documentation would be
16 appreciated but is not required.
17 2. Altered source versions must be plainly marked as such, and must not be
18 misrepresented as being the original software.
19 3. This notice may not be removed or altered from any source distribution.
20 */
21
22 /* Original hybrid wrapper for Linux by Valve Software. Their original notes:
23 *
24 * The libusb version doesn't support Bluetooth, but not all Linux
25 * distributions allow access to /dev/hidraw*
26 *
27 * This merges the two, at a small performance cost, until distributions
28 * have granted access to /dev/hidraw*
29 */
30 #include "../SDL_internal.h"
31
32 #include "SDL_loadso.h"
33 #include "SDL_hidapi.h"
34 #include "SDL_thread.h"
35 #include "SDL_timer.h"
36 #include "SDL_hidapi_c.h"
37
38 #if !SDL_HIDAPI_DISABLED
39
40 #if defined(__WIN32__)
41 #include "../core/windows/SDL_windows.h"
42 #endif
43
44 #if defined(__MACOSX__)
45 #include <CoreFoundation/CoreFoundation.h>
46 #include <mach/mach.h>
47 #include <IOKit/IOKitLib.h>
48 #include <IOKit/hid/IOHIDDevice.h>
49 #include <IOKit/usb/USBSpec.h>
50 #endif
51
52 #include "../core/linux/SDL_udev.h"
53 #ifdef SDL_USE_LIBUDEV
54 #include <poll.h>
55 #include <unistd.h>
56 #endif
57
58 #ifdef HAVE_INOTIFY
59 #include <unistd.h> /* just in case we didn't use that SDL_USE_LIBUDEV block... */
60 #include <errno.h> /* errno, strerror */
61 #include <fcntl.h>
62 #include <limits.h> /* For the definition of NAME_MAX */
63 #include <sys/inotify.h>
64 #endif
65
66 #if defined(SDL_USE_LIBUDEV)
67 typedef enum
68 {
69 ENUMERATION_UNSET,
70 ENUMERATION_LIBUDEV,
71 ENUMERATION_FALLBACK
72 } LinuxEnumerationMethod;
73
74 static LinuxEnumerationMethod linux_enumeration_method = ENUMERATION_UNSET;
75 #endif
76
77 #if defined(HAVE_INOTIFY)
78 static int inotify_fd = -1;
79 #endif
80
81 #if defined(SDL_USE_LIBUDEV)
82 static const SDL_UDEV_Symbols * usyms = NULL;
83 #endif
84
85 static struct
86 {
87 SDL_bool m_bInitialized;
88 Uint32 m_unDeviceChangeCounter;
89 SDL_bool m_bCanGetNotifications;
90 Uint32 m_unLastDetect;
91
92 #if defined(__WIN32__)
93 SDL_threadID m_nThreadID;
94 WNDCLASSEXA m_wndClass;
95 HWND m_hwndMsg;
96 HDEVNOTIFY m_hNotify;
97 double m_flLastWin32MessageCheck;
98 #endif
99
100 #if defined(__MACOSX__)
101 IONotificationPortRef m_notificationPort;
102 mach_port_t m_notificationMach;
103 #endif
104
105 #if defined(SDL_USE_LIBUDEV)
106 struct udev *m_pUdev;
107 struct udev_monitor *m_pUdevMonitor;
108 int m_nUdevFd;
109 #endif
110 } SDL_HIDAPI_discovery;
111
112
113 #ifdef __WIN32__
114 struct _DEV_BROADCAST_HDR
115 {
116 DWORD dbch_size;
117 DWORD dbch_devicetype;
118 DWORD dbch_reserved;
119 };
120
121 typedef struct _DEV_BROADCAST_DEVICEINTERFACE_A
122 {
123 DWORD dbcc_size;
124 DWORD dbcc_devicetype;
125 DWORD dbcc_reserved;
126 GUID dbcc_classguid;
127 char dbcc_name[ 1 ];
128 } DEV_BROADCAST_DEVICEINTERFACE_A, *PDEV_BROADCAST_DEVICEINTERFACE_A;
129
130 typedef struct _DEV_BROADCAST_HDR DEV_BROADCAST_HDR;
131 #define DBT_DEVICEARRIVAL 0x8000 /* system detected a new device */
132 #define DBT_DEVICEREMOVECOMPLETE 0x8004 /* device was removed from the system */
133 #define DBT_DEVTYP_DEVICEINTERFACE 0x00000005 /* device interface class */
134 #define DBT_DEVNODES_CHANGED 0x0007
135 #define DBT_CONFIGCHANGED 0x0018
136 #define DBT_DEVICETYPESPECIFIC 0x8005 /* type specific event */
137 #define DBT_DEVINSTSTARTED 0x8008 /* device installed and started */
138
139 #include <initguid.h>
140 DEFINE_GUID(GUID_DEVINTERFACE_USB_DEVICE, 0xA5DCBF10L, 0x6530, 0x11D2, 0x90, 0x1F, 0x00, 0xC0, 0x4F, 0xB9, 0x51, 0xED);
141
ControllerWndProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)142 static LRESULT CALLBACK ControllerWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
143 {
144 switch (message) {
145 case WM_DEVICECHANGE:
146 switch (wParam) {
147 case DBT_DEVICEARRIVAL:
148 case DBT_DEVICEREMOVECOMPLETE:
149 if (((DEV_BROADCAST_HDR*)lParam)->dbch_devicetype == DBT_DEVTYP_DEVICEINTERFACE) {
150 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
151 }
152 break;
153 }
154 return TRUE;
155 }
156
157 return DefWindowProc(hwnd, message, wParam, lParam);
158 }
159 #endif /* __WIN32__ */
160
161
162 #if defined(__MACOSX__)
CallbackIOServiceFunc(void * context,io_iterator_t portIterator)163 static void CallbackIOServiceFunc(void *context, io_iterator_t portIterator)
164 {
165 /* Must drain the iterator, or we won't receive new notifications */
166 io_object_t entry;
167 while ((entry = IOIteratorNext(portIterator)) != 0) {
168 IOObjectRelease(entry);
169 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
170 }
171 }
172 #endif /* __MACOSX__ */
173
174 #ifdef HAVE_INOTIFY
175 #ifdef HAVE_INOTIFY_INIT1
SDL_inotify_init1(void)176 static int SDL_inotify_init1(void) {
177 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
178 }
179 #else
SDL_inotify_init1(void)180 static int SDL_inotify_init1(void) {
181 int fd = inotify_init();
182 if (fd < 0) return -1;
183 fcntl(fd, F_SETFL, O_NONBLOCK);
184 fcntl(fd, F_SETFD, FD_CLOEXEC);
185 return fd;
186 }
187 #endif
188
189 static int
StrHasPrefix(const char * string,const char * prefix)190 StrHasPrefix(const char *string, const char *prefix)
191 {
192 return (SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0);
193 }
194
195 static int
StrIsInteger(const char * string)196 StrIsInteger(const char *string)
197 {
198 const char *p;
199
200 if (*string == '\0') {
201 return 0;
202 }
203
204 for (p = string; *p != '\0'; p++) {
205 if (*p < '0' || *p > '9') {
206 return 0;
207 }
208 }
209
210 return 1;
211 }
212 #endif /* HAVE_INOTIFY */
213
214 static void
HIDAPI_InitializeDiscovery()215 HIDAPI_InitializeDiscovery()
216 {
217 SDL_HIDAPI_discovery.m_bInitialized = SDL_TRUE;
218 SDL_HIDAPI_discovery.m_unDeviceChangeCounter = 1;
219 SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_FALSE;
220 SDL_HIDAPI_discovery.m_unLastDetect = 0;
221
222 #if defined(__WIN32__)
223 SDL_HIDAPI_discovery.m_nThreadID = SDL_ThreadID();
224
225 SDL_zero(SDL_HIDAPI_discovery.m_wndClass);
226 SDL_HIDAPI_discovery.m_wndClass.hInstance = GetModuleHandle(NULL);
227 SDL_HIDAPI_discovery.m_wndClass.lpszClassName = "SDL_HIDAPI_DEVICE_DETECTION";
228 SDL_HIDAPI_discovery.m_wndClass.lpfnWndProc = ControllerWndProc; /* This function is called by windows */
229 SDL_HIDAPI_discovery.m_wndClass.cbSize = sizeof(WNDCLASSEX);
230
231 RegisterClassExA(&SDL_HIDAPI_discovery.m_wndClass);
232 SDL_HIDAPI_discovery.m_hwndMsg = CreateWindowExA(0, "SDL_HIDAPI_DEVICE_DETECTION", NULL, 0, 0, 0, 0, 0, HWND_MESSAGE, NULL, NULL, NULL);
233
234 {
235 DEV_BROADCAST_DEVICEINTERFACE_A devBroadcast;
236
237 SDL_zero(devBroadcast);
238 devBroadcast.dbcc_size = sizeof( devBroadcast );
239 devBroadcast.dbcc_devicetype = DBT_DEVTYP_DEVICEINTERFACE;
240 devBroadcast.dbcc_classguid = GUID_DEVINTERFACE_USB_DEVICE;
241
242 /* DEVICE_NOTIFY_ALL_INTERFACE_CLASSES is important, makes GUID_DEVINTERFACE_USB_DEVICE ignored,
243 * but that seems to be necessary to get a notice after each individual usb input device actually
244 * installs, rather than just as the composite device is seen.
245 */
246 SDL_HIDAPI_discovery.m_hNotify = RegisterDeviceNotification( SDL_HIDAPI_discovery.m_hwndMsg, &devBroadcast, DEVICE_NOTIFY_WINDOW_HANDLE | DEVICE_NOTIFY_ALL_INTERFACE_CLASSES );
247 SDL_HIDAPI_discovery.m_bCanGetNotifications = ( SDL_HIDAPI_discovery.m_hNotify != 0 );
248 }
249 #endif /* __WIN32__ */
250
251 #if defined(__MACOSX__)
252 SDL_HIDAPI_discovery.m_notificationPort = IONotificationPortCreate(kIOMasterPortDefault);
253 if (SDL_HIDAPI_discovery.m_notificationPort) {
254 {
255 io_iterator_t portIterator = 0;
256 io_object_t entry;
257 IOReturn result = IOServiceAddMatchingNotification(
258 SDL_HIDAPI_discovery.m_notificationPort,
259 kIOFirstMatchNotification,
260 IOServiceMatching(kIOHIDDeviceKey),
261 CallbackIOServiceFunc, NULL, &portIterator);
262
263 if (result == 0) {
264 /* Must drain the existing iterator, or we won't receive new notifications */
265 while ((entry = IOIteratorNext(portIterator)) != 0) {
266 IOObjectRelease(entry);
267 }
268 } else {
269 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
270 SDL_HIDAPI_discovery.m_notificationPort = nil;
271 }
272 }
273 {
274 io_iterator_t portIterator = 0;
275 io_object_t entry;
276 IOReturn result = IOServiceAddMatchingNotification(
277 SDL_HIDAPI_discovery.m_notificationPort,
278 kIOTerminatedNotification,
279 IOServiceMatching(kIOHIDDeviceKey),
280 CallbackIOServiceFunc, NULL, &portIterator);
281
282 if (result == 0) {
283 /* Must drain the existing iterator, or we won't receive new notifications */
284 while ((entry = IOIteratorNext(portIterator)) != 0) {
285 IOObjectRelease(entry);
286 }
287 } else {
288 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
289 SDL_HIDAPI_discovery.m_notificationPort = nil;
290 }
291 }
292 }
293
294 SDL_HIDAPI_discovery.m_notificationMach = MACH_PORT_NULL;
295 if (SDL_HIDAPI_discovery.m_notificationPort) {
296 SDL_HIDAPI_discovery.m_notificationMach = IONotificationPortGetMachPort(SDL_HIDAPI_discovery.m_notificationPort);
297 }
298
299 SDL_HIDAPI_discovery.m_bCanGetNotifications = (SDL_HIDAPI_discovery.m_notificationMach != MACH_PORT_NULL);
300
301 #endif /* __MACOSX__ */
302
303 #if defined(SDL_USE_LIBUDEV)
304 if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
305 SDL_HIDAPI_discovery.m_pUdev = NULL;
306 SDL_HIDAPI_discovery.m_pUdevMonitor = NULL;
307 SDL_HIDAPI_discovery.m_nUdevFd = -1;
308
309 usyms = SDL_UDEV_GetUdevSyms();
310 if (usyms) {
311 SDL_HIDAPI_discovery.m_pUdev = usyms->udev_new();
312 }
313 if (SDL_HIDAPI_discovery.m_pUdev) {
314 SDL_HIDAPI_discovery.m_pUdevMonitor = usyms->udev_monitor_new_from_netlink(SDL_HIDAPI_discovery.m_pUdev, "udev");
315 if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
316 usyms->udev_monitor_enable_receiving(SDL_HIDAPI_discovery.m_pUdevMonitor);
317 SDL_HIDAPI_discovery.m_nUdevFd = usyms->udev_monitor_get_fd(SDL_HIDAPI_discovery.m_pUdevMonitor);
318 SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
319 }
320 }
321 }
322 else
323 #endif /* SDL_USE_LIBUDEV */
324 {
325 #if defined(HAVE_INOTIFY)
326 inotify_fd = SDL_inotify_init1();
327
328 if (inotify_fd < 0) {
329 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
330 "Unable to initialize inotify, falling back to polling: %s",
331 strerror(errno));
332 return;
333 }
334
335 /* We need to watch for attribute changes in addition to
336 * creation, because when a device is first created, it has
337 * permissions that we can't read. When udev chmods it to
338 * something that we maybe *can* read, we'll get an
339 * IN_ATTRIB event to tell us. */
340 if (inotify_add_watch(inotify_fd, "/dev",
341 IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
342 close(inotify_fd);
343 inotify_fd = -1;
344 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
345 "Unable to add inotify watch, falling back to polling: %s",
346 strerror (errno));
347 return;
348 }
349
350 SDL_HIDAPI_discovery.m_bCanGetNotifications = SDL_TRUE;
351 #endif /* HAVE_INOTIFY */
352 }
353 }
354
355 static void
HIDAPI_UpdateDiscovery()356 HIDAPI_UpdateDiscovery()
357 {
358 if (!SDL_HIDAPI_discovery.m_bInitialized) {
359 HIDAPI_InitializeDiscovery();
360 }
361
362 if (!SDL_HIDAPI_discovery.m_bCanGetNotifications) {
363 const Uint32 SDL_HIDAPI_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
364 Uint32 now = SDL_GetTicks();
365 if (!SDL_HIDAPI_discovery.m_unLastDetect || SDL_TICKS_PASSED(now, SDL_HIDAPI_discovery.m_unLastDetect + SDL_HIDAPI_DETECT_INTERVAL_MS)) {
366 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
367 SDL_HIDAPI_discovery.m_unLastDetect = now;
368 }
369 return;
370 }
371
372 #if defined(__WIN32__)
373 #if 0 /* just let the usual SDL_PumpEvents loop dispatch these, fixing bug 4286. --ryan. */
374 /* We'll only get messages on the same thread that created the window */
375 if (SDL_ThreadID() == SDL_HIDAPI_discovery.m_nThreadID) {
376 MSG msg;
377 while (PeekMessage(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0, PM_NOREMOVE)) {
378 if (GetMessageA(&msg, SDL_HIDAPI_discovery.m_hwndMsg, 0, 0) != 0) {
379 TranslateMessage(&msg);
380 DispatchMessage(&msg);
381 }
382 }
383 }
384 #endif
385 #endif /* __WIN32__ */
386
387 #if defined(__MACOSX__)
388 if (SDL_HIDAPI_discovery.m_notificationPort) {
389 struct { mach_msg_header_t hdr; char payload[ 4096 ]; } msg;
390 while (mach_msg(&msg.hdr, MACH_RCV_MSG | MACH_RCV_TIMEOUT, 0, sizeof(msg), SDL_HIDAPI_discovery.m_notificationMach, 0, MACH_PORT_NULL) == KERN_SUCCESS) {
391 IODispatchCalloutFromMessage(NULL, &msg.hdr, SDL_HIDAPI_discovery.m_notificationPort);
392 }
393 }
394 #endif
395
396 #if defined(SDL_USE_LIBUDEV)
397 if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
398 if (SDL_HIDAPI_discovery.m_nUdevFd >= 0) {
399 /* Drain all notification events.
400 * We don't expect a lot of device notifications so just
401 * do a new discovery on any kind or number of notifications.
402 * This could be made more restrictive if necessary.
403 */
404 for (;;) {
405 struct pollfd PollUdev;
406 struct udev_device *pUdevDevice;
407
408 PollUdev.fd = SDL_HIDAPI_discovery.m_nUdevFd;
409 PollUdev.events = POLLIN;
410 if (poll(&PollUdev, 1, 0) != 1) {
411 break;
412 }
413
414 pUdevDevice = usyms->udev_monitor_receive_device(SDL_HIDAPI_discovery.m_pUdevMonitor);
415 if (pUdevDevice) {
416 const char *action = NULL;
417 action = usyms->udev_device_get_action(pUdevDevice);
418 if (!action || SDL_strcmp(action, "add") == 0 || SDL_strcmp(action, "remove") == 0) {
419 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
420 }
421 usyms->udev_device_unref(pUdevDevice);
422 }
423 }
424 }
425 }
426 else
427 #endif /* SDL_USE_LIBUDEV */
428 {
429 #if defined(HAVE_INOTIFY)
430 if (inotify_fd >= 0) {
431 union
432 {
433 struct inotify_event event;
434 char storage[4096];
435 char enough_for_inotify[sizeof (struct inotify_event) + NAME_MAX + 1];
436 } buf;
437 ssize_t bytes;
438 size_t remain = 0;
439 size_t len;
440
441 bytes = read(inotify_fd, &buf, sizeof (buf));
442
443 if (bytes > 0) {
444 remain = (size_t) bytes;
445 }
446
447 while (remain > 0) {
448 if (buf.event.len > 0) {
449 if (StrHasPrefix(buf.event.name, "hidraw") &&
450 StrIsInteger(buf.event.name + SDL_strlen ("hidraw"))) {
451 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
452 /* We found an hidraw change. We still continue to
453 * drain the inotify fd to avoid leaving old
454 * notifications in the queue. */
455 }
456 }
457
458 len = sizeof (struct inotify_event) + buf.event.len;
459 remain -= len;
460
461 if (remain != 0) {
462 SDL_memmove(&buf.storage[0], &buf.storage[len], remain);
463 }
464 }
465 }
466 #endif /* HAVE_INOTIFY */
467 }
468 }
469
470 static void
HIDAPI_ShutdownDiscovery()471 HIDAPI_ShutdownDiscovery()
472 {
473 if (!SDL_HIDAPI_discovery.m_bInitialized) {
474 return;
475 }
476
477 #if defined(__WIN32__)
478 if (SDL_HIDAPI_discovery.m_hNotify)
479 UnregisterDeviceNotification(SDL_HIDAPI_discovery.m_hNotify);
480
481 if (SDL_HIDAPI_discovery.m_hwndMsg) {
482 DestroyWindow(SDL_HIDAPI_discovery.m_hwndMsg);
483 }
484
485 UnregisterClassA(SDL_HIDAPI_discovery.m_wndClass.lpszClassName, SDL_HIDAPI_discovery.m_wndClass.hInstance);
486 #endif
487
488 #if defined(__MACOSX__)
489 if (SDL_HIDAPI_discovery.m_notificationPort) {
490 IONotificationPortDestroy(SDL_HIDAPI_discovery.m_notificationPort);
491 }
492 #endif
493
494 #if defined(SDL_USE_LIBUDEV)
495 if (linux_enumeration_method == ENUMERATION_LIBUDEV) {
496 if (usyms) {
497 if (SDL_HIDAPI_discovery.m_pUdevMonitor) {
498 usyms->udev_monitor_unref(SDL_HIDAPI_discovery.m_pUdevMonitor);
499 }
500 if (SDL_HIDAPI_discovery.m_pUdev) {
501 usyms->udev_unref(SDL_HIDAPI_discovery.m_pUdev);
502 }
503 SDL_UDEV_ReleaseUdevSyms();
504 usyms = NULL;
505 }
506 }
507 else
508 #endif /* SDL_USE_LIBUDEV */
509 {
510 #if defined(HAVE_INOTIFY)
511 if (inotify_fd >= 0) {
512 close(inotify_fd);
513 inotify_fd = -1;
514 }
515 #endif
516 }
517
518 SDL_HIDAPI_discovery.m_bInitialized = SDL_FALSE;
519 }
520
521 /* Platform HIDAPI Implementation */
522
523 #define hid_device PLATFORM_hid_device
524 #define hid_device_ PLATFORM_hid_device_
525 #define hid_init PLATFORM_hid_init
526 #define hid_exit PLATFORM_hid_exit
527 #define hid_enumerate PLATFORM_hid_enumerate
528 #define hid_free_enumeration PLATFORM_hid_free_enumeration
529 #define hid_open PLATFORM_hid_open
530 #define hid_open_path PLATFORM_hid_open_path
531 #define hid_write PLATFORM_hid_write
532 #define hid_read_timeout PLATFORM_hid_read_timeout
533 #define hid_read PLATFORM_hid_read
534 #define hid_set_nonblocking PLATFORM_hid_set_nonblocking
535 #define hid_send_feature_report PLATFORM_hid_send_feature_report
536 #define hid_get_feature_report PLATFORM_hid_get_feature_report
537 #define hid_close PLATFORM_hid_close
538 #define hid_get_manufacturer_string PLATFORM_hid_get_manufacturer_string
539 #define hid_get_product_string PLATFORM_hid_get_product_string
540 #define hid_get_serial_number_string PLATFORM_hid_get_serial_number_string
541 #define hid_get_indexed_string PLATFORM_hid_get_indexed_string
542 #define hid_error PLATFORM_hid_error
543 #define new_hid_device PLATFORM_new_hid_device
544 #define free_hid_device PLATFORM_free_hid_device
545 #define input_report PLATFORM_input_report
546 #define return_data PLATFORM_return_data
547 #define make_path PLATFORM_make_path
548 #define read_thread PLATFORM_read_thread
549
550 #undef HIDAPI_H__
551 #if __LINUX__
552
553 #include "../core/linux/SDL_udev.h"
554 #if SDL_USE_LIBUDEV
555 static const SDL_UDEV_Symbols *udev_ctx = NULL;
556
557 #define udev_device_get_sysattr_value udev_ctx->udev_device_get_sysattr_value
558 #define udev_new udev_ctx->udev_new
559 #define udev_unref udev_ctx->udev_unref
560 #define udev_device_new_from_devnum udev_ctx->udev_device_new_from_devnum
561 #define udev_device_get_parent_with_subsystem_devtype udev_ctx->udev_device_get_parent_with_subsystem_devtype
562 #define udev_device_unref udev_ctx->udev_device_unref
563 #define udev_enumerate_new udev_ctx->udev_enumerate_new
564 #define udev_enumerate_add_match_subsystem udev_ctx->udev_enumerate_add_match_subsystem
565 #define udev_enumerate_scan_devices udev_ctx->udev_enumerate_scan_devices
566 #define udev_enumerate_get_list_entry udev_ctx->udev_enumerate_get_list_entry
567 #define udev_list_entry_get_name udev_ctx->udev_list_entry_get_name
568 #define udev_device_new_from_syspath udev_ctx->udev_device_new_from_syspath
569 #define udev_device_get_devnode udev_ctx->udev_device_get_devnode
570 #define udev_list_entry_get_next udev_ctx->udev_list_entry_get_next
571 #define udev_enumerate_unref udev_ctx->udev_enumerate_unref
572
573 #include "linux/hid.c"
574 #define HAVE_PLATFORM_BACKEND 1
575 #endif /* SDL_USE_LIBUDEV */
576
577 #elif __MACOSX__
578 #include "mac/hid.c"
579 #define HAVE_PLATFORM_BACKEND 1
580 #define udev_ctx 1
581 #elif __WINDOWS__
582 #include "windows/hid.c"
583 #define HAVE_PLATFORM_BACKEND 1
584 #define udev_ctx 1
585 #elif __ANDROID__
586 /* The implementation for Android is in a separate .cpp file */
587 #include "hidapi/hidapi.h"
588 #define HAVE_PLATFORM_BACKEND 1
589 #define udev_ctx 1
590 #elif __IPHONEOS__ || __TVOS__
591 /* The implementation for iOS and tvOS is in a separate .m file */
592 #include "hidapi/hidapi.h"
593 #define HAVE_PLATFORM_BACKEND 1
594 #define udev_ctx 1
595 #endif
596
597 #undef hid_device
598 #undef hid_device_
599 #undef hid_init
600 #undef hid_exit
601 #undef hid_enumerate
602 #undef hid_free_enumeration
603 #undef hid_open
604 #undef hid_open_path
605 #undef hid_write
606 #undef hid_read_timeout
607 #undef hid_read
608 #undef hid_set_nonblocking
609 #undef hid_send_feature_report
610 #undef hid_get_feature_report
611 #undef hid_close
612 #undef hid_get_manufacturer_string
613 #undef hid_get_product_string
614 #undef hid_get_serial_number_string
615 #undef hid_get_indexed_string
616 #undef hid_error
617 #undef new_hid_device
618 #undef free_hid_device
619 #undef input_report
620 #undef return_data
621 #undef make_path
622 #undef read_thread
623
624 #ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX
625 #define HAVE_DRIVER_BACKEND 1
626 #endif
627
628 #ifdef HAVE_DRIVER_BACKEND
629
630 /* DRIVER HIDAPI Implementation */
631
632 #define hid_device DRIVER_hid_device
633 #define hid_device_ DRIVER_hid_device_
634 #define hid_init DRIVER_hid_init
635 #define hid_exit DRIVER_hid_exit
636 #define hid_enumerate DRIVER_hid_enumerate
637 #define hid_free_enumeration DRIVER_hid_free_enumeration
638 #define hid_open DRIVER_hid_open
639 #define hid_open_path DRIVER_hid_open_path
640 #define hid_write DRIVER_hid_write
641 #define hid_read_timeout DRIVER_hid_read_timeout
642 #define hid_read DRIVER_hid_read
643 #define hid_set_nonblocking DRIVER_hid_set_nonblocking
644 #define hid_send_feature_report DRIVER_hid_send_feature_report
645 #define hid_get_feature_report DRIVER_hid_get_feature_report
646 #define hid_close DRIVER_hid_close
647 #define hid_get_manufacturer_string DRIVER_hid_get_manufacturer_string
648 #define hid_get_product_string DRIVER_hid_get_product_string
649 #define hid_get_serial_number_string DRIVER_hid_get_serial_number_string
650 #define hid_get_indexed_string DRIVER_hid_get_indexed_string
651 #define hid_error DRIVER_hid_error
652
653 #ifdef SDL_JOYSTICK_HIDAPI_STEAMXBOX
654 #undef HIDAPI_H__
655 #include "steamxbox/hid.c"
656 #else
657 #error Need a driver hid.c for this platform!
658 #endif
659
660 #undef hid_device
661 #undef hid_device_
662 #undef hid_init
663 #undef hid_exit
664 #undef hid_enumerate
665 #undef hid_free_enumeration
666 #undef hid_open
667 #undef hid_open_path
668 #undef hid_write
669 #undef hid_read_timeout
670 #undef hid_read
671 #undef hid_set_nonblocking
672 #undef hid_send_feature_report
673 #undef hid_get_feature_report
674 #undef hid_close
675 #undef hid_get_manufacturer_string
676 #undef hid_get_product_string
677 #undef hid_get_serial_number_string
678 #undef hid_get_indexed_string
679 #undef hid_error
680
681 #endif /* HAVE_DRIVER_BACKEND */
682
683
684 #ifdef SDL_LIBUSB_DYNAMIC
685 /* libusb HIDAPI Implementation */
686
687 /* Include this now, for our dynamically-loaded libusb context */
688 #include <libusb.h>
689
690 static struct
691 {
692 void* libhandle;
693
694 int (LIBUSB_CALL *init)(libusb_context **ctx);
695 void (LIBUSB_CALL *exit)(libusb_context *ctx);
696 ssize_t (LIBUSB_CALL *get_device_list)(libusb_context *ctx, libusb_device ***list);
697 void (LIBUSB_CALL *free_device_list)(libusb_device **list, int unref_devices);
698 int (LIBUSB_CALL *get_device_descriptor)(libusb_device *dev, struct libusb_device_descriptor *desc);
699 int (LIBUSB_CALL *get_active_config_descriptor)(libusb_device *dev, struct libusb_config_descriptor **config);
700 int (LIBUSB_CALL *get_config_descriptor)(
701 libusb_device *dev,
702 uint8_t config_index,
703 struct libusb_config_descriptor **config
704 );
705 void (LIBUSB_CALL *free_config_descriptor)(struct libusb_config_descriptor *config);
706 uint8_t (LIBUSB_CALL *get_bus_number)(libusb_device *dev);
707 uint8_t (LIBUSB_CALL *get_device_address)(libusb_device *dev);
708 int (LIBUSB_CALL *open)(libusb_device *dev, libusb_device_handle **dev_handle);
709 void (LIBUSB_CALL *close)(libusb_device_handle *dev_handle);
710 int (LIBUSB_CALL *claim_interface)(libusb_device_handle *dev_handle, int interface_number);
711 int (LIBUSB_CALL *release_interface)(libusb_device_handle *dev_handle, int interface_number);
712 int (LIBUSB_CALL *kernel_driver_active)(libusb_device_handle *dev_handle, int interface_number);
713 int (LIBUSB_CALL *detach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number);
714 int (LIBUSB_CALL *attach_kernel_driver)(libusb_device_handle *dev_handle, int interface_number);
715 int (LIBUSB_CALL *set_interface_alt_setting)(libusb_device_handle *dev, int interface_number, int alternate_setting);
716 struct libusb_transfer * (LIBUSB_CALL *alloc_transfer)(int iso_packets);
717 int (LIBUSB_CALL *submit_transfer)(struct libusb_transfer *transfer);
718 int (LIBUSB_CALL *cancel_transfer)(struct libusb_transfer *transfer);
719 void (LIBUSB_CALL *free_transfer)(struct libusb_transfer *transfer);
720 int (LIBUSB_CALL *control_transfer)(
721 libusb_device_handle *dev_handle,
722 uint8_t request_type,
723 uint8_t bRequest,
724 uint16_t wValue,
725 uint16_t wIndex,
726 unsigned char *data,
727 uint16_t wLength,
728 unsigned int timeout
729 );
730 int (LIBUSB_CALL *interrupt_transfer)(
731 libusb_device_handle *dev_handle,
732 unsigned char endpoint,
733 unsigned char *data,
734 int length,
735 int *actual_length,
736 unsigned int timeout
737 );
738 int (LIBUSB_CALL *handle_events)(libusb_context *ctx);
739 int (LIBUSB_CALL *handle_events_completed)(libusb_context *ctx, int *completed);
740 } libusb_ctx;
741
742 #define libusb_init libusb_ctx.init
743 #define libusb_exit libusb_ctx.exit
744 #define libusb_get_device_list libusb_ctx.get_device_list
745 #define libusb_free_device_list libusb_ctx.free_device_list
746 #define libusb_get_device_descriptor libusb_ctx.get_device_descriptor
747 #define libusb_get_active_config_descriptor libusb_ctx.get_active_config_descriptor
748 #define libusb_get_config_descriptor libusb_ctx.get_config_descriptor
749 #define libusb_free_config_descriptor libusb_ctx.free_config_descriptor
750 #define libusb_get_bus_number libusb_ctx.get_bus_number
751 #define libusb_get_device_address libusb_ctx.get_device_address
752 #define libusb_open libusb_ctx.open
753 #define libusb_close libusb_ctx.close
754 #define libusb_claim_interface libusb_ctx.claim_interface
755 #define libusb_release_interface libusb_ctx.release_interface
756 #define libusb_kernel_driver_active libusb_ctx.kernel_driver_active
757 #define libusb_detach_kernel_driver libusb_ctx.detach_kernel_driver
758 #define libusb_attach_kernel_driver libusb_ctx.attach_kernel_driver
759 #define libusb_set_interface_alt_setting libusb_ctx.set_interface_alt_setting
760 #define libusb_alloc_transfer libusb_ctx.alloc_transfer
761 #define libusb_submit_transfer libusb_ctx.submit_transfer
762 #define libusb_cancel_transfer libusb_ctx.cancel_transfer
763 #define libusb_free_transfer libusb_ctx.free_transfer
764 #define libusb_control_transfer libusb_ctx.control_transfer
765 #define libusb_interrupt_transfer libusb_ctx.interrupt_transfer
766 #define libusb_handle_events libusb_ctx.handle_events
767 #define libusb_handle_events_completed libusb_ctx.handle_events_completed
768
769 #define hid_device LIBUSB_hid_device
770 #define hid_device_ LIBUSB_hid_device_
771 #define hid_init LIBUSB_hid_init
772 #define hid_exit LIBUSB_hid_exit
773 #define hid_enumerate LIBUSB_hid_enumerate
774 #define hid_free_enumeration LIBUSB_hid_free_enumeration
775 #define hid_open LIBUSB_hid_open
776 #define hid_open_path LIBUSB_hid_open_path
777 #define hid_write LIBUSB_hid_write
778 #define hid_read_timeout LIBUSB_hid_read_timeout
779 #define hid_read LIBUSB_hid_read
780 #define hid_set_nonblocking LIBUSB_hid_set_nonblocking
781 #define hid_send_feature_report LIBUSB_hid_send_feature_report
782 #define hid_get_feature_report LIBUSB_hid_get_feature_report
783 #define hid_close LIBUSB_hid_close
784 #define hid_get_manufacturer_string LIBUSB_hid_get_manufacturer_string
785 #define hid_get_product_string LIBUSB_hid_get_product_string
786 #define hid_get_serial_number_string LIBUSB_hid_get_serial_number_string
787 #define hid_get_indexed_string LIBUSB_hid_get_indexed_string
788 #define hid_error LIBUSB_hid_error
789 #define new_hid_device LIBUSB_new_hid_device
790 #define free_hid_device LIBUSB_free_hid_device
791 #define input_report LIBUSB_input_report
792 #define return_data LIBUSB_return_data
793 #define make_path LIBUSB_make_path
794 #define read_thread LIBUSB_read_thread
795
796 #ifndef __FreeBSD__
797 /* this is awkwardly inlined, so we need to re-implement it here
798 * so we can override the libusb_control_transfer call */
799 static int
SDL_libusb_get_string_descriptor(libusb_device_handle * dev,uint8_t descriptor_index,uint16_t lang_id,unsigned char * data,int length)800 SDL_libusb_get_string_descriptor(libusb_device_handle *dev,
801 uint8_t descriptor_index, uint16_t lang_id,
802 unsigned char *data, int length)
803 {
804 return libusb_control_transfer(dev,
805 LIBUSB_ENDPOINT_IN | 0x0, /* Endpoint 0 IN */
806 LIBUSB_REQUEST_GET_DESCRIPTOR,
807 (LIBUSB_DT_STRING << 8) | descriptor_index,
808 lang_id,
809 data,
810 (uint16_t) length,
811 1000);
812 }
813 #define libusb_get_string_descriptor SDL_libusb_get_string_descriptor
814 #endif /* __FreeBSD__ */
815
816 #undef HIDAPI_H__
817 #include "libusb/hid.c"
818
819 #undef hid_device
820 #undef hid_device_
821 #undef hid_init
822 #undef hid_exit
823 #undef hid_enumerate
824 #undef hid_free_enumeration
825 #undef hid_open
826 #undef hid_open_path
827 #undef hid_write
828 #undef hid_read_timeout
829 #undef hid_read
830 #undef hid_set_nonblocking
831 #undef hid_send_feature_report
832 #undef hid_get_feature_report
833 #undef hid_close
834 #undef hid_get_manufacturer_string
835 #undef hid_get_product_string
836 #undef hid_get_serial_number_string
837 #undef hid_get_indexed_string
838 #undef hid_error
839 #undef new_hid_device
840 #undef free_hid_device
841 #undef input_report
842 #undef return_data
843 #undef make_path
844 #undef read_thread
845
846 #endif /* SDL_LIBUSB_DYNAMIC */
847
848 #endif /* !SDL_HIDAPI_DISABLED */
849
850 /* Shared HIDAPI Implementation */
851
852 struct hidapi_backend {
853 int (*hid_write)(void* device, const unsigned char* data, size_t length);
854 int (*hid_read_timeout)(void* device, unsigned char* data, size_t length, int milliseconds);
855 int (*hid_read)(void* device, unsigned char* data, size_t length);
856 int (*hid_set_nonblocking)(void* device, int nonblock);
857 int (*hid_send_feature_report)(void* device, const unsigned char* data, size_t length);
858 int (*hid_get_feature_report)(void* device, unsigned char* data, size_t length);
859 void (*hid_close)(void* device);
860 int (*hid_get_manufacturer_string)(void* device, wchar_t* string, size_t maxlen);
861 int (*hid_get_product_string)(void* device, wchar_t* string, size_t maxlen);
862 int (*hid_get_serial_number_string)(void* device, wchar_t* string, size_t maxlen);
863 int (*hid_get_indexed_string)(void* device, int string_index, wchar_t* string, size_t maxlen);
864 const wchar_t* (*hid_error)(void* device);
865 };
866
867 #if HAVE_PLATFORM_BACKEND
868 static const struct hidapi_backend PLATFORM_Backend = {
869 (void*)PLATFORM_hid_write,
870 (void*)PLATFORM_hid_read_timeout,
871 (void*)PLATFORM_hid_read,
872 (void*)PLATFORM_hid_set_nonblocking,
873 (void*)PLATFORM_hid_send_feature_report,
874 (void*)PLATFORM_hid_get_feature_report,
875 (void*)PLATFORM_hid_close,
876 (void*)PLATFORM_hid_get_manufacturer_string,
877 (void*)PLATFORM_hid_get_product_string,
878 (void*)PLATFORM_hid_get_serial_number_string,
879 (void*)PLATFORM_hid_get_indexed_string,
880 (void*)PLATFORM_hid_error
881 };
882 #endif /* HAVE_PLATFORM_BACKEND */
883
884 #if HAVE_DRIVER_BACKEND
885 static const struct hidapi_backend DRIVER_Backend = {
886 (void*)DRIVER_hid_write,
887 (void*)DRIVER_hid_read_timeout,
888 (void*)DRIVER_hid_read,
889 (void*)DRIVER_hid_set_nonblocking,
890 (void*)DRIVER_hid_send_feature_report,
891 (void*)DRIVER_hid_get_feature_report,
892 (void*)DRIVER_hid_close,
893 (void*)DRIVER_hid_get_manufacturer_string,
894 (void*)DRIVER_hid_get_product_string,
895 (void*)DRIVER_hid_get_serial_number_string,
896 (void*)DRIVER_hid_get_indexed_string,
897 (void*)DRIVER_hid_error
898 };
899 #endif /* HAVE_DRIVER_BACKEND */
900
901 #ifdef SDL_LIBUSB_DYNAMIC
902 static const struct hidapi_backend LIBUSB_Backend = {
903 (void*)LIBUSB_hid_write,
904 (void*)LIBUSB_hid_read_timeout,
905 (void*)LIBUSB_hid_read,
906 (void*)LIBUSB_hid_set_nonblocking,
907 (void*)LIBUSB_hid_send_feature_report,
908 (void*)LIBUSB_hid_get_feature_report,
909 (void*)LIBUSB_hid_close,
910 (void*)LIBUSB_hid_get_manufacturer_string,
911 (void*)LIBUSB_hid_get_product_string,
912 (void*)LIBUSB_hid_get_serial_number_string,
913 (void*)LIBUSB_hid_get_indexed_string,
914 (void*)LIBUSB_hid_error
915 };
916 #endif /* SDL_LIBUSB_DYNAMIC */
917
918 struct SDL_hid_device_
919 {
920 const void *magic;
921 void *device;
922 const struct hidapi_backend *backend;
923 };
924 static char device_magic;
925
926 #if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC)
927
928 static SDL_hid_device *
CreateHIDDeviceWrapper(void * device,const struct hidapi_backend * backend)929 CreateHIDDeviceWrapper(void *device, const struct hidapi_backend *backend)
930 {
931 SDL_hid_device *wrapper = (SDL_hid_device *)SDL_malloc(sizeof(*wrapper));
932 wrapper->magic = &device_magic;
933 wrapper->device = device;
934 wrapper->backend = backend;
935 return wrapper;
936 }
937
938 #endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */
939
940 static void
DeleteHIDDeviceWrapper(SDL_hid_device * device)941 DeleteHIDDeviceWrapper(SDL_hid_device *device)
942 {
943 device->magic = NULL;
944 SDL_free(device);
945 }
946
947 #define CHECK_DEVICE_MAGIC(device, retval) \
948 if (!device || device->magic != &device_magic) { \
949 SDL_SetError("Invalid device"); \
950 return retval; \
951 }
952
953 #if !SDL_HIDAPI_DISABLED
954
955 #define COPY_IF_EXISTS(var) \
956 if (pSrc->var != NULL) { \
957 pDst->var = SDL_strdup(pSrc->var); \
958 } else { \
959 pDst->var = NULL; \
960 }
961 #define WCOPY_IF_EXISTS(var) \
962 if (pSrc->var != NULL) { \
963 pDst->var = SDL_wcsdup(pSrc->var); \
964 } else { \
965 pDst->var = NULL; \
966 }
967
968 static void
CopyHIDDeviceInfo(struct SDL_hid_device_info * pSrc,struct SDL_hid_device_info * pDst)969 CopyHIDDeviceInfo(struct SDL_hid_device_info *pSrc, struct SDL_hid_device_info *pDst)
970 {
971 COPY_IF_EXISTS(path)
972 pDst->vendor_id = pSrc->vendor_id;
973 pDst->product_id = pSrc->product_id;
974 WCOPY_IF_EXISTS(serial_number)
975 pDst->release_number = pSrc->release_number;
976 WCOPY_IF_EXISTS(manufacturer_string)
977 WCOPY_IF_EXISTS(product_string)
978 pDst->usage_page = pSrc->usage_page;
979 pDst->usage = pSrc->usage;
980 pDst->interface_number = pSrc->interface_number;
981 pDst->interface_class = pSrc->interface_class;
982 pDst->interface_subclass = pSrc->interface_subclass;
983 pDst->interface_protocol = pSrc->interface_protocol;
984 pDst->next = NULL;
985 }
986
987 #undef COPY_IF_EXISTS
988 #undef WCOPY_IF_EXISTS
989
990 #endif /* !SDL_HIDAPI_DISABLED */
991
992 static int SDL_hidapi_refcount = 0;
993
SDL_SetHIDAPIError(const wchar_t * error)994 static void SDL_SetHIDAPIError( const wchar_t *error )
995 {
996 if (error) {
997 char *error_utf8 = SDL_iconv_wchar_utf8(error);
998 if (error_utf8) {
999 SDL_SetError("%s", error_utf8);
1000 SDL_free(error_utf8);
1001 }
1002 }
1003 }
1004
SDL_hid_init(void)1005 int SDL_hid_init(void)
1006 {
1007 int attempts = 0, success = 0;
1008
1009 if (SDL_hidapi_refcount > 0) {
1010 ++SDL_hidapi_refcount;
1011 return 0;
1012 }
1013
1014 #ifdef SDL_LIBUSB_DYNAMIC
1015 ++attempts;
1016 libusb_ctx.libhandle = SDL_LoadObject(SDL_LIBUSB_DYNAMIC);
1017 if (libusb_ctx.libhandle != NULL) {
1018 SDL_bool loaded = SDL_TRUE;
1019 #define LOAD_LIBUSB_SYMBOL(func) \
1020 if (!(libusb_ctx.func = SDL_LoadFunction(libusb_ctx.libhandle, "libusb_" #func))) {loaded = SDL_FALSE;}
1021 LOAD_LIBUSB_SYMBOL(init)
1022 LOAD_LIBUSB_SYMBOL(exit)
1023 LOAD_LIBUSB_SYMBOL(get_device_list)
1024 LOAD_LIBUSB_SYMBOL(free_device_list)
1025 LOAD_LIBUSB_SYMBOL(get_device_descriptor)
1026 LOAD_LIBUSB_SYMBOL(get_active_config_descriptor)
1027 LOAD_LIBUSB_SYMBOL(get_config_descriptor)
1028 LOAD_LIBUSB_SYMBOL(free_config_descriptor)
1029 LOAD_LIBUSB_SYMBOL(get_bus_number)
1030 LOAD_LIBUSB_SYMBOL(get_device_address)
1031 LOAD_LIBUSB_SYMBOL(open)
1032 LOAD_LIBUSB_SYMBOL(close)
1033 LOAD_LIBUSB_SYMBOL(claim_interface)
1034 LOAD_LIBUSB_SYMBOL(release_interface)
1035 LOAD_LIBUSB_SYMBOL(kernel_driver_active)
1036 LOAD_LIBUSB_SYMBOL(detach_kernel_driver)
1037 LOAD_LIBUSB_SYMBOL(attach_kernel_driver)
1038 LOAD_LIBUSB_SYMBOL(set_interface_alt_setting)
1039 LOAD_LIBUSB_SYMBOL(alloc_transfer)
1040 LOAD_LIBUSB_SYMBOL(submit_transfer)
1041 LOAD_LIBUSB_SYMBOL(cancel_transfer)
1042 LOAD_LIBUSB_SYMBOL(free_transfer)
1043 LOAD_LIBUSB_SYMBOL(control_transfer)
1044 LOAD_LIBUSB_SYMBOL(interrupt_transfer)
1045 LOAD_LIBUSB_SYMBOL(handle_events)
1046 LOAD_LIBUSB_SYMBOL(handle_events_completed)
1047 #undef LOAD_LIBUSB_SYMBOL
1048
1049 if (!loaded) {
1050 SDL_UnloadObject(libusb_ctx.libhandle);
1051 libusb_ctx.libhandle = NULL;
1052 /* SDL_LogWarn(SDL_LOG_CATEGORY_INPUT, SDL_LIBUSB_DYNAMIC " found but could not load function"); */
1053 } else if (LIBUSB_hid_init() < 0) {
1054 SDL_UnloadObject(libusb_ctx.libhandle);
1055 libusb_ctx.libhandle = NULL;
1056 } else {
1057 ++success;
1058 }
1059 }
1060 #endif /* SDL_LIBUSB_DYNAMIC */
1061
1062 #if HAVE_PLATFORM_BACKEND
1063 ++attempts;
1064 #if __LINUX__
1065 udev_ctx = SDL_UDEV_GetUdevSyms();
1066 #endif /* __LINUX __ */
1067 if (udev_ctx && PLATFORM_hid_init() == 0) {
1068 ++success;
1069 }
1070 #endif /* HAVE_PLATFORM_BACKEND */
1071
1072 if (attempts > 0 && success == 0) {
1073 return -1;
1074 }
1075
1076 ++SDL_hidapi_refcount;
1077 return 0;
1078 }
1079
SDL_hid_exit(void)1080 int SDL_hid_exit(void)
1081 {
1082 int result = 0;
1083
1084 if (SDL_hidapi_refcount == 0) {
1085 return 0;
1086 }
1087 --SDL_hidapi_refcount;
1088 if (SDL_hidapi_refcount > 0) {
1089 return 0;
1090 }
1091 SDL_hidapi_refcount = 0;
1092
1093 #if !SDL_HIDAPI_DISABLED
1094 HIDAPI_ShutdownDiscovery();
1095 #endif
1096
1097 #if HAVE_PLATFORM_BACKEND
1098 if (udev_ctx) {
1099 result |= PLATFORM_hid_exit();
1100 }
1101 #if __LINUX__
1102 SDL_UDEV_ReleaseUdevSyms();
1103 #endif /* __LINUX __ */
1104 #endif /* HAVE_PLATFORM_BACKEND */
1105
1106 #ifdef SDL_LIBUSB_DYNAMIC
1107 if (libusb_ctx.libhandle) {
1108 result |= LIBUSB_hid_exit();
1109 SDL_UnloadObject(libusb_ctx.libhandle);
1110 libusb_ctx.libhandle = NULL;
1111 }
1112 #endif /* SDL_LIBUSB_DYNAMIC */
1113
1114 return result;
1115 }
1116
SDL_hid_device_change_count(void)1117 Uint32 SDL_hid_device_change_count(void)
1118 {
1119 Uint32 counter = 0;
1120
1121 #if !SDL_HIDAPI_DISABLED
1122 if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
1123 return 0;
1124 }
1125
1126 HIDAPI_UpdateDiscovery();
1127
1128 if (SDL_HIDAPI_discovery.m_unDeviceChangeCounter == 0) {
1129 /* Counter wrapped! */
1130 ++SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
1131 }
1132 counter = SDL_HIDAPI_discovery.m_unDeviceChangeCounter;
1133
1134 #endif /* !SDL_HIDAPI_DISABLED */
1135
1136 return counter;
1137 }
1138
SDL_hid_enumerate(unsigned short vendor_id,unsigned short product_id)1139 struct SDL_hid_device_info *SDL_hid_enumerate(unsigned short vendor_id, unsigned short product_id)
1140 {
1141 #if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC)
1142 #ifdef SDL_LIBUSB_DYNAMIC
1143 struct SDL_hid_device_info *usb_devs = NULL;
1144 struct SDL_hid_device_info *usb_dev;
1145 #endif
1146 #if HAVE_DRIVER_BACKEND
1147 struct SDL_hid_device_info* driver_devs = NULL;
1148 struct SDL_hid_device_info* driver_dev;
1149 #endif
1150 #if HAVE_PLATFORM_BACKEND
1151 struct SDL_hid_device_info *raw_devs = NULL;
1152 struct SDL_hid_device_info *raw_dev;
1153 #endif
1154 struct SDL_hid_device_info *devs = NULL, *last = NULL, *new_dev;
1155
1156 if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
1157 return NULL;
1158 }
1159
1160 #ifdef SDL_LIBUSB_DYNAMIC
1161 if (libusb_ctx.libhandle) {
1162 usb_devs = LIBUSB_hid_enumerate(vendor_id, product_id);
1163 #ifdef DEBUG_HIDAPI
1164 SDL_Log("libusb devices found:");
1165 #endif
1166 for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
1167 new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info));
1168 if (!new_dev) {
1169 LIBUSB_hid_free_enumeration(usb_devs);
1170 SDL_hid_free_enumeration(devs);
1171 SDL_OutOfMemory();
1172 return NULL;
1173 }
1174 CopyHIDDeviceInfo(usb_dev, new_dev);
1175 #ifdef DEBUG_HIDAPI
1176 SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
1177 usb_dev->manufacturer_string, usb_dev->product_string,
1178 usb_dev->vendor_id, usb_dev->product_id);
1179 #endif
1180
1181 if (last != NULL) {
1182 last->next = new_dev;
1183 } else {
1184 devs = new_dev;
1185 }
1186 last = new_dev;
1187 }
1188 }
1189 #endif /* SDL_LIBUSB_DYNAMIC */
1190
1191 #ifdef HAVE_DRIVER_BACKEND
1192 driver_devs = DRIVER_hid_enumerate(vendor_id, product_id);
1193 for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
1194 new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info));
1195 CopyHIDDeviceInfo(driver_dev, new_dev);
1196
1197 if (last != NULL) {
1198 last->next = new_dev;
1199 } else {
1200 devs = new_dev;
1201 }
1202 last = new_dev;
1203 }
1204 #endif /* HAVE_DRIVER_BACKEND */
1205
1206 #if HAVE_PLATFORM_BACKEND
1207 if (udev_ctx) {
1208 raw_devs = PLATFORM_hid_enumerate(vendor_id, product_id);
1209 #ifdef DEBUG_HIDAPI
1210 SDL_Log("hidraw devices found:");
1211 #endif
1212 for (raw_dev = raw_devs; raw_dev; raw_dev = raw_dev->next) {
1213 SDL_bool bFound = SDL_FALSE;
1214 #ifdef DEBUG_HIDAPI
1215 SDL_Log(" - %ls %ls 0x%.4hx 0x%.4hx",
1216 raw_dev->manufacturer_string, raw_dev->product_string,
1217 raw_dev->vendor_id, raw_dev->product_id);
1218 #endif
1219 #ifdef SDL_LIBUSB_DYNAMIC
1220 for (usb_dev = usb_devs; usb_dev; usb_dev = usb_dev->next) {
1221 if (raw_dev->vendor_id == usb_dev->vendor_id &&
1222 raw_dev->product_id == usb_dev->product_id &&
1223 (raw_dev->interface_number < 0 || raw_dev->interface_number == usb_dev->interface_number)) {
1224 bFound = SDL_TRUE;
1225 break;
1226 }
1227 }
1228 #endif
1229 #ifdef HAVE_DRIVER_BACKEND
1230 for (driver_dev = driver_devs; driver_dev; driver_dev = driver_dev->next) {
1231 if (raw_dev->vendor_id == driver_dev->vendor_id &&
1232 raw_dev->product_id == driver_dev->product_id &&
1233 (raw_dev->interface_number < 0 || raw_dev->interface_number == driver_dev->interface_number)) {
1234 bFound = SDL_TRUE;
1235 break;
1236 }
1237 }
1238 #endif
1239 if (!bFound) {
1240 new_dev = (struct SDL_hid_device_info*) SDL_malloc(sizeof(struct SDL_hid_device_info));
1241 if (!new_dev) {
1242 #ifdef SDL_LIBUSB_DYNAMIC
1243 if (libusb_ctx.libhandle) {
1244 LIBUSB_hid_free_enumeration(usb_devs);
1245 }
1246 #endif
1247 PLATFORM_hid_free_enumeration(raw_devs);
1248 SDL_hid_free_enumeration(devs);
1249 SDL_OutOfMemory();
1250 return NULL;
1251 }
1252 CopyHIDDeviceInfo(raw_dev, new_dev);
1253 new_dev->next = NULL;
1254
1255 if (last != NULL) {
1256 last->next = new_dev;
1257 } else {
1258 devs = new_dev;
1259 }
1260 last = new_dev;
1261 }
1262 }
1263 PLATFORM_hid_free_enumeration(raw_devs);
1264 }
1265 #endif /* HAVE_PLATFORM_BACKEND */
1266
1267 #ifdef SDL_LIBUSB_DYNAMIC
1268 if (libusb_ctx.libhandle) {
1269 LIBUSB_hid_free_enumeration(usb_devs);
1270 }
1271 #endif
1272 return devs;
1273
1274 #else
1275 return NULL;
1276 #endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */
1277 }
1278
SDL_hid_free_enumeration(struct SDL_hid_device_info * devs)1279 void SDL_hid_free_enumeration(struct SDL_hid_device_info *devs)
1280 {
1281 while (devs) {
1282 struct SDL_hid_device_info *next = devs->next;
1283 SDL_free(devs->path);
1284 SDL_free(devs->serial_number);
1285 SDL_free(devs->manufacturer_string);
1286 SDL_free(devs->product_string);
1287 SDL_free(devs);
1288 devs = next;
1289 }
1290 }
1291
SDL_hid_open(unsigned short vendor_id,unsigned short product_id,const wchar_t * serial_number)1292 SDL_hid_device *SDL_hid_open(unsigned short vendor_id, unsigned short product_id, const wchar_t *serial_number)
1293 {
1294 #if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC)
1295 void *pDevice = NULL;
1296
1297 if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
1298 return NULL;
1299 }
1300
1301 #if HAVE_PLATFORM_BACKEND
1302 if (udev_ctx &&
1303 (pDevice = PLATFORM_hid_open(vendor_id, product_id, serial_number)) != NULL) {
1304 return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend);
1305 }
1306 #endif /* HAVE_PLATFORM_BACKEND */
1307
1308 #if HAVE_DRIVER_BACKEND
1309 if ((pDevice = DRIVER_hid_open(vendor_id, product_id, serial_number)) != NULL) {
1310 return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend);
1311 }
1312 #endif /* HAVE_DRIVER_BACKEND */
1313
1314 #ifdef SDL_LIBUSB_DYNAMIC
1315 if (libusb_ctx.libhandle &&
1316 (pDevice = LIBUSB_hid_open(vendor_id, product_id, serial_number)) != NULL) {
1317 return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend);
1318 }
1319 #endif /* SDL_LIBUSB_DYNAMIC */
1320
1321 #endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */
1322
1323 return NULL;
1324 }
1325
SDL_hid_open_path(const char * path,int bExclusive)1326 SDL_hid_device *SDL_hid_open_path(const char *path, int bExclusive /* = false */)
1327 {
1328 #if HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || defined(SDL_LIBUSB_DYNAMIC)
1329 void *pDevice = NULL;
1330
1331 if (SDL_hidapi_refcount == 0 && SDL_hid_init() != 0) {
1332 return NULL;
1333 }
1334
1335 #if HAVE_PLATFORM_BACKEND
1336 if (udev_ctx &&
1337 (pDevice = PLATFORM_hid_open_path(path, bExclusive)) != NULL) {
1338 return CreateHIDDeviceWrapper(pDevice, &PLATFORM_Backend);
1339 }
1340 #endif /* HAVE_PLATFORM_BACKEND */
1341
1342 #if HAVE_DRIVER_BACKEND
1343 if ((pDevice = DRIVER_hid_open_path(path, bExclusive)) != NULL) {
1344 return CreateHIDDeviceWrapper(pDevice, &DRIVER_Backend);
1345 }
1346 #endif /* HAVE_DRIVER_BACKEND */
1347
1348 #ifdef SDL_LIBUSB_DYNAMIC
1349 if (libusb_ctx.libhandle &&
1350 (pDevice = LIBUSB_hid_open_path(path, bExclusive)) != NULL) {
1351 return CreateHIDDeviceWrapper(pDevice, &LIBUSB_Backend);
1352 }
1353 #endif /* SDL_LIBUSB_DYNAMIC */
1354
1355 #endif /* HAVE_PLATFORM_BACKEND || HAVE_DRIVER_BACKEND || SDL_LIBUSB_DYNAMIC */
1356
1357 return NULL;
1358 }
1359
SDL_hid_write(SDL_hid_device * device,const unsigned char * data,size_t length)1360 int SDL_hid_write(SDL_hid_device *device, const unsigned char *data, size_t length)
1361 {
1362 int result;
1363
1364 CHECK_DEVICE_MAGIC(device, -1);
1365
1366 result = device->backend->hid_write(device->device, data, length);
1367 if (result < 0) {
1368 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1369 }
1370 return result;
1371 }
1372
SDL_hid_read_timeout(SDL_hid_device * device,unsigned char * data,size_t length,int milliseconds)1373 int SDL_hid_read_timeout(SDL_hid_device *device, unsigned char *data, size_t length, int milliseconds)
1374 {
1375 int result;
1376
1377 CHECK_DEVICE_MAGIC(device, -1);
1378
1379 result = device->backend->hid_read_timeout(device->device, data, length, milliseconds);
1380 if (result < 0) {
1381 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1382 }
1383 return result;
1384 }
1385
SDL_hid_read(SDL_hid_device * device,unsigned char * data,size_t length)1386 int SDL_hid_read(SDL_hid_device *device, unsigned char *data, size_t length)
1387 {
1388 int result;
1389
1390 CHECK_DEVICE_MAGIC(device, -1);
1391
1392 result = device->backend->hid_read(device->device, data, length);
1393 if (result < 0) {
1394 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1395 }
1396 return result;
1397 }
1398
SDL_hid_set_nonblocking(SDL_hid_device * device,int nonblock)1399 int SDL_hid_set_nonblocking(SDL_hid_device *device, int nonblock)
1400 {
1401 int result;
1402
1403 CHECK_DEVICE_MAGIC(device, -1);
1404
1405 result = device->backend->hid_set_nonblocking(device->device, nonblock);
1406 if (result < 0) {
1407 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1408 }
1409 return result;
1410 }
1411
SDL_hid_send_feature_report(SDL_hid_device * device,const unsigned char * data,size_t length)1412 int SDL_hid_send_feature_report(SDL_hid_device *device, const unsigned char *data, size_t length)
1413 {
1414 int result;
1415
1416 CHECK_DEVICE_MAGIC(device, -1);
1417
1418 result = device->backend->hid_send_feature_report(device->device, data, length);
1419 if (result < 0) {
1420 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1421 }
1422 return result;
1423 }
1424
SDL_hid_get_feature_report(SDL_hid_device * device,unsigned char * data,size_t length)1425 int SDL_hid_get_feature_report(SDL_hid_device *device, unsigned char *data, size_t length)
1426 {
1427 int result;
1428
1429 CHECK_DEVICE_MAGIC(device, -1);
1430
1431 result = device->backend->hid_get_feature_report(device->device, data, length);
1432 if (result < 0) {
1433 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1434 }
1435 return result;
1436 }
1437
SDL_hid_close(SDL_hid_device * device)1438 void SDL_hid_close(SDL_hid_device *device)
1439 {
1440 CHECK_DEVICE_MAGIC(device,);
1441
1442 device->backend->hid_close(device->device);
1443 DeleteHIDDeviceWrapper(device);
1444 }
1445
SDL_hid_get_manufacturer_string(SDL_hid_device * device,wchar_t * string,size_t maxlen)1446 int SDL_hid_get_manufacturer_string(SDL_hid_device *device, wchar_t *string, size_t maxlen)
1447 {
1448 int result;
1449
1450 CHECK_DEVICE_MAGIC(device, -1);
1451
1452 result = device->backend->hid_get_manufacturer_string(device->device, string, maxlen);
1453 if (result < 0) {
1454 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1455 }
1456 return result;
1457 }
1458
SDL_hid_get_product_string(SDL_hid_device * device,wchar_t * string,size_t maxlen)1459 int SDL_hid_get_product_string(SDL_hid_device *device, wchar_t *string, size_t maxlen)
1460 {
1461 int result;
1462
1463 CHECK_DEVICE_MAGIC(device, -1);
1464
1465 result = device->backend->hid_get_product_string(device->device, string, maxlen);
1466 if (result < 0) {
1467 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1468 }
1469 return result;
1470 }
1471
SDL_hid_get_serial_number_string(SDL_hid_device * device,wchar_t * string,size_t maxlen)1472 int SDL_hid_get_serial_number_string(SDL_hid_device *device, wchar_t *string, size_t maxlen)
1473 {
1474 int result;
1475
1476 CHECK_DEVICE_MAGIC(device, -1);
1477
1478 result = device->backend->hid_get_serial_number_string(device->device, string, maxlen);
1479 if (result < 0) {
1480 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1481 }
1482 return result;
1483 }
1484
SDL_hid_get_indexed_string(SDL_hid_device * device,int string_index,wchar_t * string,size_t maxlen)1485 int SDL_hid_get_indexed_string(SDL_hid_device *device, int string_index, wchar_t *string, size_t maxlen)
1486 {
1487 int result;
1488
1489 CHECK_DEVICE_MAGIC(device, -1);
1490
1491 result = device->backend->hid_get_indexed_string(device->device, string_index, string, maxlen);
1492 if (result < 0) {
1493 SDL_SetHIDAPIError(device->backend->hid_error(device->device));
1494 }
1495 return result;
1496 }
1497
SDL_hid_ble_scan(SDL_bool active)1498 void SDL_hid_ble_scan(SDL_bool active)
1499 {
1500 #if __IPHONEOS__ || __TVOS__
1501 hid_ble_scan(active);
1502 #endif
1503 }
1504
1505 #ifdef HAVE_ENABLE_GAMECUBE_ADAPTORS
1506 /* This is needed to enable input for Nyko and EVORETRO GameCube adaptors */
SDL_EnableGameCubeAdaptors(void)1507 void SDL_EnableGameCubeAdaptors(void)
1508 {
1509 #ifdef SDL_LIBUSB_DYNAMIC
1510 libusb_context *context = NULL;
1511 libusb_device **devs = NULL;
1512 libusb_device_handle *handle = NULL;
1513 struct libusb_device_descriptor desc;
1514 ssize_t i, num_devs;
1515 int kernel_detached = 0;
1516
1517 if (libusb_ctx.libhandle == NULL) {
1518 return;
1519 }
1520
1521 if (libusb_init(&context) == 0) {
1522 num_devs = libusb_get_device_list(context, &devs);
1523 for (i = 0; i < num_devs; ++i) {
1524 if (libusb_get_device_descriptor(devs[i], &desc) != 0) {
1525 continue;
1526 }
1527
1528 if (desc.idVendor != 0x057e || desc.idProduct != 0x0337) {
1529 continue;
1530 }
1531
1532 if (libusb_open(devs[i], &handle) != 0) {
1533 continue;
1534 }
1535
1536 if (libusb_kernel_driver_active(handle, 0)) {
1537 if (libusb_detach_kernel_driver(handle, 0) == 0) {
1538 kernel_detached = 1;
1539 }
1540 }
1541
1542 if (libusb_claim_interface(handle, 0) == 0) {
1543 libusb_control_transfer(handle, 0x21, 11, 0x0001, 0, NULL, 0, 1000);
1544 libusb_release_interface(handle, 0);
1545 }
1546
1547 if (kernel_detached) {
1548 libusb_attach_kernel_driver(handle, 0);
1549 }
1550
1551 libusb_close(handle);
1552 }
1553
1554 libusb_free_device_list(devs, 1);
1555
1556 libusb_exit(context);
1557 }
1558 #endif /* SDL_LIBUSB_DYNAMIC */
1559 }
1560 #endif /* HAVE_ENABLE_GAMECUBE_ADAPTORS */
1561
1562 /* vi: set sts=4 ts=4 sw=4 expandtab: */
1563