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