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 #include "../../SDL_internal.h"
22
23 #ifdef SDL_JOYSTICK_LINUX
24
25 #ifndef SDL_INPUT_LINUXEV
26 #error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
27 #endif
28
29 /* This is the Linux implementation of the SDL joystick API */
30
31 #include <sys/stat.h>
32 #include <errno.h> /* errno, strerror */
33 #include <fcntl.h>
34 #include <limits.h> /* For the definition of PATH_MAX */
35 #ifdef HAVE_INOTIFY
36 #include <sys/inotify.h>
37 #endif
38 #include <sys/ioctl.h>
39 #include <unistd.h>
40 #include <dirent.h>
41 #include <linux/joystick.h>
42
43 #include "SDL_hints.h"
44 #include "SDL_joystick.h"
45 #include "SDL_log.h"
46 #include "SDL_endian.h"
47 #include "SDL_timer.h"
48 #include "../../events/SDL_events_c.h"
49 #include "../SDL_sysjoystick.h"
50 #include "../SDL_joystick_c.h"
51 #include "../steam/SDL_steamcontroller.h"
52 #include "SDL_sysjoystick_c.h"
53 #include "../hidapi/SDL_hidapijoystick_c.h"
54
55 /* This isn't defined in older Linux kernel headers */
56 #ifndef SYN_DROPPED
57 #define SYN_DROPPED 3
58 #endif
59 #ifndef BTN_NORTH
60 #define BTN_NORTH 0x133
61 #endif
62 #ifndef BTN_WEST
63 #define BTN_WEST 0x134
64 #endif
65 #ifndef BTN_DPAD_UP
66 #define BTN_DPAD_UP 0x220
67 #endif
68 #ifndef BTN_DPAD_DOWN
69 #define BTN_DPAD_DOWN 0x221
70 #endif
71 #ifndef BTN_DPAD_LEFT
72 #define BTN_DPAD_LEFT 0x222
73 #endif
74 #ifndef BTN_DPAD_RIGHT
75 #define BTN_DPAD_RIGHT 0x223
76 #endif
77
78 #include "../../core/linux/SDL_evdev_capabilities.h"
79 #include "../../core/linux/SDL_udev.h"
80
81 #if 0
82 #define DEBUG_INPUT_EVENTS 1
83 #endif
84
85 typedef enum
86 {
87 ENUMERATION_UNSET,
88 ENUMERATION_LIBUDEV,
89 ENUMERATION_FALLBACK
90 } EnumerationMethod;
91
92 static EnumerationMethod enumeration_method = ENUMERATION_UNSET;
93
94 static SDL_bool IsJoystickJSNode(const char *node);
95 static int MaybeAddDevice(const char *path);
96 static int MaybeRemoveDevice(const char *path);
97
98 /* A linked list of available joysticks */
99 typedef struct SDL_joylist_item
100 {
101 int device_instance;
102 char *path; /* "/dev/input/event2" or whatever */
103 char *name; /* "SideWinder 3D Pro" or whatever */
104 SDL_JoystickGUID guid;
105 dev_t devnum;
106 struct joystick_hwdata *hwdata;
107 struct SDL_joylist_item *next;
108
109 /* Steam Controller support */
110 SDL_bool m_bSteamController;
111
112 SDL_GamepadMapping *mapping;
113 } SDL_joylist_item;
114
115 static SDL_bool SDL_classic_joysticks = SDL_FALSE;
116 static SDL_joylist_item *SDL_joylist = NULL;
117 static SDL_joylist_item *SDL_joylist_tail = NULL;
118 static int numjoysticks = 0;
119 static int inotify_fd = -1;
120
121 static Uint32 last_joy_detect_time;
122 static time_t last_input_dir_mtime;
123
124 static void
FixupDeviceInfoForMapping(int fd,struct input_id * inpid)125 FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
126 {
127 if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
128 /* This is a Microsoft Xbox One Elite Series 2 controller */
129 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
130
131 /* The first version of the firmware duplicated all the inputs */
132 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
133 test_bit(0x2c0, keybit)) {
134 /* Change the version to 0x0902, so we can map it differently */
135 inpid->version = 0x0902;
136 }
137 }
138
139 /* For Atari vcs modern and classic controllers have the version reflecting
140 * firmware version, but the mapping stays stable so ignore
141 * version information */
142 if (inpid->vendor == 0x3250
143 && (inpid->product == 0x1001 || inpid->product == 0x1002)) {
144 inpid->version = 0;
145 }
146 }
147
148 #ifdef SDL_JOYSTICK_HIDAPI
149 static SDL_bool
IsVirtualJoystick(Uint16 vendor,Uint16 product,Uint16 version,const char * name)150 IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
151 {
152 if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 &&
153 SDL_strcmp(name, "Xbox One S Controller") == 0) {
154 /* This is the virtual device created by the xow driver */
155 return SDL_TRUE;
156 }
157 return SDL_FALSE;
158 }
159 #endif /* SDL_JOYSTICK_HIDAPI */
160
161 static int
GuessIsJoystick(int fd)162 GuessIsJoystick(int fd)
163 {
164 unsigned long evbit[NBITS(EV_MAX)] = { 0 };
165 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
166 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
167 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
168 int devclass;
169
170 if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
171 (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
172 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) < 0) ||
173 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
174 return (0);
175 }
176
177 devclass = SDL_EVDEV_GuessDeviceClass(evbit, absbit, keybit, relbit);
178
179 if (devclass & SDL_UDEV_DEVICE_JOYSTICK) {
180 return 1;
181 }
182
183 return 0;
184 }
185
186 static int
IsJoystick(const char * path,int fd,char ** name_return,SDL_JoystickGUID * guid)187 IsJoystick(const char *path, int fd, char **name_return, SDL_JoystickGUID *guid)
188 {
189 struct input_id inpid;
190 Uint16 *guid16 = (Uint16 *)guid->data;
191 char *name;
192 char product_string[128];
193
194 if (ioctl(fd, JSIOCGNAME(sizeof(product_string)), product_string) >= 0) {
195 SDL_zero(inpid);
196 #if SDL_USE_LIBUDEV
197 SDL_UDEV_GetProductInfo(path, &inpid.vendor, &inpid.product, &inpid.version);
198 #endif
199 } else {
200 /* When udev is enabled we only get joystick devices here, so there's no need to test them */
201 if (enumeration_method != ENUMERATION_LIBUDEV && !GuessIsJoystick(fd)) {
202 return 0;
203 }
204
205 if (ioctl(fd, EVIOCGID, &inpid) < 0) {
206 return 0;
207 }
208
209 if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
210 return 0;
211 }
212 }
213
214 name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
215 if (!name) {
216 return 0;
217 }
218
219 #ifdef SDL_JOYSTICK_HIDAPI
220 if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
221 HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, name)) {
222 /* The HIDAPI driver is taking care of this device */
223 SDL_free(name);
224 return 0;
225 }
226 #endif
227
228 FixupDeviceInfoForMapping(fd, &inpid);
229
230 #ifdef DEBUG_JOYSTICK
231 SDL_Log("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
232 #endif
233
234 SDL_memset(guid->data, 0, sizeof(guid->data));
235
236 /* We only need 16 bits for each of these; space them out to fill 128. */
237 /* Byteswap so devices get same GUID on little/big endian platforms. */
238 *guid16++ = SDL_SwapLE16(inpid.bustype);
239 *guid16++ = 0;
240
241 if (inpid.vendor && inpid.product) {
242 *guid16++ = SDL_SwapLE16(inpid.vendor);
243 *guid16++ = 0;
244 *guid16++ = SDL_SwapLE16(inpid.product);
245 *guid16++ = 0;
246 *guid16++ = SDL_SwapLE16(inpid.version);
247 *guid16++ = 0;
248 } else {
249 SDL_strlcpy((char*)guid16, name, sizeof(guid->data) - 4);
250 }
251
252 if (SDL_ShouldIgnoreJoystick(name, *guid)) {
253 SDL_free(name);
254 return 0;
255 }
256 *name_return = name;
257 return 1;
258 }
259
260 #if SDL_USE_LIBUDEV
joystick_udev_callback(SDL_UDEV_deviceevent udev_type,int udev_class,const char * devpath)261 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
262 {
263 if (devpath == NULL) {
264 return;
265 }
266
267 switch (udev_type) {
268 case SDL_UDEV_DEVICEADDED:
269 if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
270 return;
271 }
272 if (SDL_classic_joysticks) {
273 if (!IsJoystickJSNode(devpath)) {
274 return;
275 }
276 } else {
277 if (IsJoystickJSNode(devpath)) {
278 return;
279 }
280 }
281 MaybeAddDevice(devpath);
282 break;
283
284 case SDL_UDEV_DEVICEREMOVED:
285 MaybeRemoveDevice(devpath);
286 break;
287
288 default:
289 break;
290 }
291
292 }
293 #endif /* SDL_USE_LIBUDEV */
294
295 static void
FreeJoylistItem(SDL_joylist_item * item)296 FreeJoylistItem(SDL_joylist_item *item)
297 {
298 SDL_free(item->mapping);
299 SDL_free(item->path);
300 SDL_free(item->name);
301 SDL_free(item);
302 }
303
304 static int
MaybeAddDevice(const char * path)305 MaybeAddDevice(const char *path)
306 {
307 struct stat sb;
308 int fd = -1;
309 int isstick = 0;
310 char *name = NULL;
311 SDL_JoystickGUID guid;
312 SDL_joylist_item *item;
313
314 if (path == NULL) {
315 return -1;
316 }
317
318 if (stat(path, &sb) == -1) {
319 return -1;
320 }
321
322 /* Check to make sure it's not already in list. */
323 for (item = SDL_joylist; item != NULL; item = item->next) {
324 if (sb.st_rdev == item->devnum) {
325 return -1; /* already have this one */
326 }
327 }
328
329 fd = open(path, O_RDONLY | O_CLOEXEC, 0);
330 if (fd < 0) {
331 return -1;
332 }
333
334 #ifdef DEBUG_INPUT_EVENTS
335 SDL_Log("Checking %s\n", path);
336 #endif
337
338 isstick = IsJoystick(path, fd, &name, &guid);
339 close(fd);
340 if (!isstick) {
341 return -1;
342 }
343
344 item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
345 if (item == NULL) {
346 return -1;
347 }
348
349 item->devnum = sb.st_rdev;
350 item->path = SDL_strdup(path);
351 item->name = name;
352 item->guid = guid;
353
354 if ((item->path == NULL) || (item->name == NULL)) {
355 FreeJoylistItem(item);
356 return -1;
357 }
358
359 item->device_instance = SDL_GetNextJoystickInstanceID();
360 if (SDL_joylist_tail == NULL) {
361 SDL_joylist = SDL_joylist_tail = item;
362 } else {
363 SDL_joylist_tail->next = item;
364 SDL_joylist_tail = item;
365 }
366
367 /* Need to increment the joystick count before we post the event */
368 ++numjoysticks;
369
370 SDL_PrivateJoystickAdded(item->device_instance);
371
372 return numjoysticks;
373 }
374
375 static void
RemoveJoylistItem(SDL_joylist_item * item,SDL_joylist_item * prev)376 RemoveJoylistItem(SDL_joylist_item *item, SDL_joylist_item *prev)
377 {
378 if (item->hwdata) {
379 item->hwdata->item = NULL;
380 }
381
382 if (prev != NULL) {
383 prev->next = item->next;
384 } else {
385 SDL_assert(SDL_joylist == item);
386 SDL_joylist = item->next;
387 }
388
389 if (item == SDL_joylist_tail) {
390 SDL_joylist_tail = prev;
391 }
392
393 /* Need to decrement the joystick count before we post the event */
394 --numjoysticks;
395
396 SDL_PrivateJoystickRemoved(item->device_instance);
397 FreeJoylistItem(item);
398 }
399
400 static int
MaybeRemoveDevice(const char * path)401 MaybeRemoveDevice(const char *path)
402 {
403 SDL_joylist_item *item;
404 SDL_joylist_item *prev = NULL;
405
406 if (path == NULL) {
407 return -1;
408 }
409
410 for (item = SDL_joylist; item != NULL; item = item->next) {
411 /* found it, remove it. */
412 if (SDL_strcmp(path, item->path) == 0) {
413 const int retval = item->device_instance;
414 RemoveJoylistItem(item, prev);
415 return retval;
416 }
417 prev = item;
418 }
419
420 return -1;
421 }
422
423 static void
HandlePendingRemovals(void)424 HandlePendingRemovals(void)
425 {
426 SDL_joylist_item *prev = NULL;
427 SDL_joylist_item *item = SDL_joylist;
428
429 while (item != NULL) {
430 if (item->hwdata && item->hwdata->gone) {
431 RemoveJoylistItem(item, prev);
432
433 if (prev != NULL) {
434 item = prev->next;
435 } else {
436 item = SDL_joylist;
437 }
438 } else {
439 prev = item;
440 item = item->next;
441 }
442 }
443 }
444
SteamControllerConnectedCallback(const char * name,SDL_JoystickGUID guid,int * device_instance)445 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
446 {
447 SDL_joylist_item *item;
448
449 item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
450 if (item == NULL) {
451 return SDL_FALSE;
452 }
453
454 item->path = SDL_strdup("");
455 item->name = SDL_strdup(name);
456 item->guid = guid;
457 item->m_bSteamController = SDL_TRUE;
458
459 if ((item->path == NULL) || (item->name == NULL)) {
460 FreeJoylistItem(item);
461 return SDL_FALSE;
462 }
463
464 *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
465 if (SDL_joylist_tail == NULL) {
466 SDL_joylist = SDL_joylist_tail = item;
467 } else {
468 SDL_joylist_tail->next = item;
469 SDL_joylist_tail = item;
470 }
471
472 /* Need to increment the joystick count before we post the event */
473 ++numjoysticks;
474
475 SDL_PrivateJoystickAdded(item->device_instance);
476
477 return SDL_TRUE;
478 }
479
SteamControllerDisconnectedCallback(int device_instance)480 static void SteamControllerDisconnectedCallback(int device_instance)
481 {
482 SDL_joylist_item *item;
483 SDL_joylist_item *prev = NULL;
484
485 for (item = SDL_joylist; item != NULL; item = item->next) {
486 /* found it, remove it. */
487 if (item->device_instance == device_instance) {
488 RemoveJoylistItem(item, prev);
489 return;
490 }
491 prev = item;
492 }
493 }
494
495 #ifdef HAVE_INOTIFY
496 #ifdef HAVE_INOTIFY_INIT1
SDL_inotify_init1(void)497 static int SDL_inotify_init1(void) {
498 return inotify_init1(IN_NONBLOCK | IN_CLOEXEC);
499 }
500 #else
SDL_inotify_init1(void)501 static int SDL_inotify_init1(void) {
502 int fd = inotify_init();
503 if (fd < 0) return -1;
504 fcntl(fd, F_SETFL, O_NONBLOCK);
505 fcntl(fd, F_SETFD, FD_CLOEXEC);
506 return fd;
507 }
508 #endif
509 #endif
510
511 static int
StrHasPrefix(const char * string,const char * prefix)512 StrHasPrefix(const char *string, const char *prefix)
513 {
514 return (SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0);
515 }
516
517 static int
StrIsInteger(const char * string)518 StrIsInteger(const char *string)
519 {
520 const char *p;
521
522 if (*string == '\0') {
523 return 0;
524 }
525
526 for (p = string; *p != '\0'; p++) {
527 if (*p < '0' || *p > '9') {
528 return 0;
529 }
530 }
531
532 return 1;
533 }
534
535 static SDL_bool
IsJoystickJSNode(const char * node)536 IsJoystickJSNode(const char *node)
537 {
538 const char *last_slash = SDL_strrchr(node, '/');
539 if (last_slash) {
540 node = last_slash + 1;
541 }
542 return (StrHasPrefix(node, "js") && StrIsInteger(node + 2));
543 }
544
545 static SDL_bool
IsJoystickEventNode(const char * node)546 IsJoystickEventNode(const char *node)
547 {
548 const char *last_slash = SDL_strrchr(node, '/');
549 if (last_slash) {
550 node = last_slash + 1;
551 }
552 return (StrHasPrefix(node, "event") && StrIsInteger(node + 5));
553 }
554
555 static SDL_bool
IsJoystickDeviceNode(const char * node)556 IsJoystickDeviceNode(const char *node)
557 {
558 if (SDL_classic_joysticks) {
559 return IsJoystickJSNode(node);
560 } else {
561 return IsJoystickEventNode(node);
562 }
563 }
564
565 #ifdef HAVE_INOTIFY
566 static void
LINUX_InotifyJoystickDetect(void)567 LINUX_InotifyJoystickDetect(void)
568 {
569 union
570 {
571 struct inotify_event event;
572 char storage[4096];
573 char enough_for_inotify[sizeof (struct inotify_event) + NAME_MAX + 1];
574 } buf;
575 ssize_t bytes;
576 size_t remain = 0;
577 size_t len;
578 char path[PATH_MAX];
579
580 bytes = read(inotify_fd, &buf, sizeof (buf));
581
582 if (bytes > 0) {
583 remain = (size_t) bytes;
584 }
585
586 while (remain > 0) {
587 if (buf.event.len > 0) {
588 if (IsJoystickDeviceNode(buf.event.name)) {
589 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", buf.event.name);
590
591 if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) {
592 MaybeAddDevice(path);
593 }
594 else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) {
595 MaybeRemoveDevice(path);
596 }
597 }
598 }
599
600 len = sizeof (struct inotify_event) + buf.event.len;
601 remain -= len;
602
603 if (remain != 0) {
604 SDL_memmove (&buf.storage[0], &buf.storage[len], remain);
605 }
606 }
607 }
608 #endif /* HAVE_INOTIFY */
609
610 /* Detect devices by reading /dev/input. In the inotify code path we
611 * have to do this the first time, to detect devices that already existed
612 * before we started; in the non-inotify code path we do this repeatedly
613 * (polling). */
614 static int
filter_entries(const struct dirent * entry)615 filter_entries(const struct dirent *entry)
616 {
617 return IsJoystickDeviceNode(entry->d_name);
618 }
619 static int
sort_entries(const struct dirent ** a,const struct dirent ** b)620 sort_entries(const struct dirent **a, const struct dirent **b)
621 {
622 int numA = SDL_atoi((*a)->d_name+5);
623 int numB = SDL_atoi((*b)->d_name+5);
624 return (numA - numB);
625 }
626 static void
LINUX_FallbackJoystickDetect(void)627 LINUX_FallbackJoystickDetect(void)
628 {
629 const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
630 Uint32 now = SDL_GetTicks();
631
632 if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
633 struct stat sb;
634
635 /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
636 if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
637 int i, count;
638 struct dirent **entries;
639 char path[PATH_MAX];
640
641 count = scandir("/dev/input", &entries, filter_entries, sort_entries);
642 for (i = 0; i < count; ++i) {
643 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
644 MaybeAddDevice(path);
645
646 free(entries[i]); /* This should NOT be SDL_free() */
647 }
648 free(entries); /* This should NOT be SDL_free() */
649
650 last_input_dir_mtime = sb.st_mtime;
651 }
652
653 last_joy_detect_time = now;
654 }
655 }
656
657 static void
LINUX_JoystickDetect(void)658 LINUX_JoystickDetect(void)
659 {
660 #if SDL_USE_LIBUDEV
661 if (enumeration_method == ENUMERATION_LIBUDEV) {
662 SDL_UDEV_Poll();
663 }
664 else
665 #endif
666 #ifdef HAVE_INOTIFY
667 if (inotify_fd >= 0 && last_joy_detect_time != 0) {
668 LINUX_InotifyJoystickDetect();
669 }
670 else
671 #endif
672 {
673 LINUX_FallbackJoystickDetect();
674 }
675
676 HandlePendingRemovals();
677
678 SDL_UpdateSteamControllers();
679 }
680
681 static int
LINUX_JoystickInit(void)682 LINUX_JoystickInit(void)
683 {
684 const char *devices = SDL_GetHint(SDL_HINT_JOYSTICK_DEVICE);
685
686 SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_CLASSIC, SDL_FALSE);
687
688 #if SDL_USE_LIBUDEV
689 if (enumeration_method == ENUMERATION_UNSET) {
690 if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) {
691 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
692 "udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
693 enumeration_method = ENUMERATION_FALLBACK;
694
695 } else if (access("/.flatpak-info", F_OK) == 0
696 || access("/run/host/container-manager", F_OK) == 0) {
697 /* Explicitly check `/.flatpak-info` because, for old versions of
698 * Flatpak, this was the only available way to tell if we were in
699 * a Flatpak container. */
700 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
701 "Container detected, disabling udev integration");
702 enumeration_method = ENUMERATION_FALLBACK;
703
704 } else {
705 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
706 "Using udev for joystick device discovery");
707 enumeration_method = ENUMERATION_LIBUDEV;
708 }
709 }
710 #endif
711
712 /* First see if the user specified one or more joysticks to use */
713 if (devices != NULL) {
714 char *envcopy, *envpath, *delim;
715 envcopy = SDL_strdup(devices);
716 envpath = envcopy;
717 while (envpath != NULL) {
718 delim = SDL_strchr(envpath, ':');
719 if (delim != NULL) {
720 *delim++ = '\0';
721 }
722 MaybeAddDevice(envpath);
723 envpath = delim;
724 }
725 SDL_free(envcopy);
726 }
727
728 SDL_InitSteamControllers(SteamControllerConnectedCallback,
729 SteamControllerDisconnectedCallback);
730
731 /* Force immediate joystick detection if using fallback */
732 last_joy_detect_time = 0;
733 last_input_dir_mtime = 0;
734
735 /* Manually scan first, since we sort by device number and udev doesn't */
736 LINUX_JoystickDetect();
737
738 #if SDL_USE_LIBUDEV
739 if (enumeration_method == ENUMERATION_LIBUDEV) {
740 if (SDL_UDEV_Init() < 0) {
741 return SDL_SetError("Could not initialize UDEV");
742 }
743
744 /* Set up the udev callback */
745 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
746 SDL_UDEV_Quit();
747 return SDL_SetError("Could not set up joystick <-> udev callback");
748 }
749
750 /* Force a scan to build the initial device list */
751 SDL_UDEV_Scan();
752 }
753 else
754 #endif
755 {
756 #if defined(HAVE_INOTIFY)
757 inotify_fd = SDL_inotify_init1();
758
759 if (inotify_fd < 0) {
760 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
761 "Unable to initialize inotify, falling back to polling: %s",
762 strerror (errno));
763 } else {
764 /* We need to watch for attribute changes in addition to
765 * creation, because when a device is first created, it has
766 * permissions that we can't read. When udev chmods it to
767 * something that we maybe *can* read, we'll get an
768 * IN_ATTRIB event to tell us. */
769 if (inotify_add_watch(inotify_fd, "/dev/input",
770 IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
771 close(inotify_fd);
772 inotify_fd = -1;
773 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
774 "Unable to add inotify watch, falling back to polling: %s",
775 strerror (errno));
776 }
777 }
778 #endif /* HAVE_INOTIFY */
779 }
780
781 return 0;
782 }
783
784 static int
LINUX_JoystickGetCount(void)785 LINUX_JoystickGetCount(void)
786 {
787 return numjoysticks;
788 }
789
790 static SDL_joylist_item *
JoystickByDevIndex(int device_index)791 JoystickByDevIndex(int device_index)
792 {
793 SDL_joylist_item *item = SDL_joylist;
794
795 if ((device_index < 0) || (device_index >= numjoysticks)) {
796 return NULL;
797 }
798
799 while (device_index > 0) {
800 SDL_assert(item != NULL);
801 device_index--;
802 item = item->next;
803 }
804
805 return item;
806 }
807
808 /* Function to get the device-dependent name of a joystick */
809 static const char *
LINUX_JoystickGetDeviceName(int device_index)810 LINUX_JoystickGetDeviceName(int device_index)
811 {
812 return JoystickByDevIndex(device_index)->name;
813 }
814
815 static int
LINUX_JoystickGetDevicePlayerIndex(int device_index)816 LINUX_JoystickGetDevicePlayerIndex(int device_index)
817 {
818 return -1;
819 }
820
821 static void
LINUX_JoystickSetDevicePlayerIndex(int device_index,int player_index)822 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
823 {
824 }
825
826 static SDL_JoystickGUID
LINUX_JoystickGetDeviceGUID(int device_index)827 LINUX_JoystickGetDeviceGUID( int device_index )
828 {
829 return JoystickByDevIndex(device_index)->guid;
830 }
831
832 /* Function to perform the mapping from device index to the instance id for this index */
833 static SDL_JoystickID
LINUX_JoystickGetDeviceInstanceID(int device_index)834 LINUX_JoystickGetDeviceInstanceID(int device_index)
835 {
836 return JoystickByDevIndex(device_index)->device_instance;
837 }
838
839 static int
allocate_hatdata(SDL_Joystick * joystick)840 allocate_hatdata(SDL_Joystick *joystick)
841 {
842 int i;
843
844 joystick->hwdata->hats =
845 (struct hwdata_hat *) SDL_malloc(joystick->nhats *
846 sizeof(struct hwdata_hat));
847 if (joystick->hwdata->hats == NULL) {
848 return (-1);
849 }
850 for (i = 0; i < joystick->nhats; ++i) {
851 joystick->hwdata->hats[i].axis[0] = 1;
852 joystick->hwdata->hats[i].axis[1] = 1;
853 }
854 return (0);
855 }
856
857 static int
allocate_balldata(SDL_Joystick * joystick)858 allocate_balldata(SDL_Joystick *joystick)
859 {
860 int i;
861
862 joystick->hwdata->balls =
863 (struct hwdata_ball *) SDL_malloc(joystick->nballs *
864 sizeof(struct hwdata_ball));
865 if (joystick->hwdata->balls == NULL) {
866 return (-1);
867 }
868 for (i = 0; i < joystick->nballs; ++i) {
869 joystick->hwdata->balls[i].axis[0] = 0;
870 joystick->hwdata->balls[i].axis[1] = 0;
871 }
872 return (0);
873 }
874
875 static void
ConfigJoystick(SDL_Joystick * joystick,int fd)876 ConfigJoystick(SDL_Joystick *joystick, int fd)
877 {
878 int i, t;
879 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
880 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
881 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
882 unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
883 Uint8 key_pam_size, abs_pam_size;
884 SDL_bool use_deadzones = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_DEADZONES, SDL_FALSE);
885
886 /* See if this device uses the new unified event API */
887 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
888 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
889 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
890
891 /* Get the number of buttons, axes, and other thingamajigs */
892 for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
893 if (test_bit(i, keybit)) {
894 #ifdef DEBUG_INPUT_EVENTS
895 SDL_Log("Joystick has button: 0x%x\n", i);
896 #endif
897 joystick->hwdata->key_map[i] = joystick->nbuttons;
898 joystick->hwdata->has_key[i] = SDL_TRUE;
899 ++joystick->nbuttons;
900 }
901 }
902 for (i = 0; i < BTN_JOYSTICK; ++i) {
903 if (test_bit(i, keybit)) {
904 #ifdef DEBUG_INPUT_EVENTS
905 SDL_Log("Joystick has button: 0x%x\n", i);
906 #endif
907 joystick->hwdata->key_map[i] = joystick->nbuttons;
908 joystick->hwdata->has_key[i] = SDL_TRUE;
909 ++joystick->nbuttons;
910 }
911 }
912 for (i = 0; i < ABS_MAX; ++i) {
913 /* Skip hats */
914 if (i == ABS_HAT0X) {
915 i = ABS_HAT3Y;
916 continue;
917 }
918 if (test_bit(i, absbit)) {
919 struct input_absinfo absinfo;
920 struct axis_correct *correct = &joystick->hwdata->abs_correct[i];
921
922 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
923 continue;
924 }
925 #ifdef DEBUG_INPUT_EVENTS
926 SDL_Log("Joystick has absolute axis: 0x%.2x\n", i);
927 SDL_Log("Values = { %d, %d, %d, %d, %d }\n",
928 absinfo.value, absinfo.minimum, absinfo.maximum,
929 absinfo.fuzz, absinfo.flat);
930 #endif /* DEBUG_INPUT_EVENTS */
931 joystick->hwdata->abs_map[i] = joystick->naxes;
932 joystick->hwdata->has_abs[i] = SDL_TRUE;
933
934 correct->minimum = absinfo.minimum;
935 correct->maximum = absinfo.maximum;
936 if (correct->minimum != correct->maximum) {
937 if (use_deadzones) {
938 correct->use_deadzones = SDL_TRUE;
939 correct->coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
940 correct->coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
941 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
942 if (t != 0) {
943 correct->coef[2] = (1 << 28) / t;
944 } else {
945 correct->coef[2] = 0;
946 }
947 } else {
948 float value_range = (correct->maximum - correct->minimum);
949 float output_range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN);
950
951 correct->scale = (output_range / value_range);
952 }
953 }
954 ++joystick->naxes;
955 }
956 }
957 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
958 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
959 struct input_absinfo absinfo;
960 int hat_index = (i - ABS_HAT0X) / 2;
961
962 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
963 continue;
964 }
965 #ifdef DEBUG_INPUT_EVENTS
966 SDL_Log("Joystick has hat %d\n", hat_index);
967 SDL_Log("Values = { %d, %d, %d, %d, %d }\n",
968 absinfo.value, absinfo.minimum, absinfo.maximum,
969 absinfo.fuzz, absinfo.flat);
970 #endif /* DEBUG_INPUT_EVENTS */
971 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
972 joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
973 }
974 }
975 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
976 ++joystick->nballs;
977 }
978
979 } else if ((ioctl(fd, JSIOCGBUTTONS, &key_pam_size, sizeof(key_pam_size)) >= 0) &&
980 (ioctl(fd, JSIOCGAXES, &abs_pam_size, sizeof(abs_pam_size)) >= 0)) {
981 size_t len;
982
983 joystick->hwdata->classic = SDL_TRUE;
984
985 len = (KEY_MAX - BTN_MISC + 1) * sizeof(*joystick->hwdata->key_pam);
986 joystick->hwdata->key_pam = (Uint16 *)SDL_calloc(1, len);
987 if (joystick->hwdata->key_pam) {
988 if (ioctl(fd, JSIOCGBTNMAP, joystick->hwdata->key_pam, len) < 0) {
989 SDL_free(joystick->hwdata->key_pam);
990 joystick->hwdata->key_pam = NULL;
991 key_pam_size = 0;
992 }
993 } else {
994 key_pam_size = 0;
995 }
996 for (i = 0; i < key_pam_size; ++i) {
997 Uint16 code = joystick->hwdata->key_pam[i];
998 #ifdef DEBUG_INPUT_EVENTS
999 SDL_Log("Joystick has button: 0x%x\n", code);
1000 #endif
1001 joystick->hwdata->key_map[code] = joystick->nbuttons;
1002 joystick->hwdata->has_key[code] = SDL_TRUE;
1003 ++joystick->nbuttons;
1004 }
1005
1006 len = ABS_CNT * sizeof(*joystick->hwdata->abs_pam);
1007 joystick->hwdata->abs_pam = (Uint8 *)SDL_calloc(1, len);
1008 if (joystick->hwdata->abs_pam) {
1009 if (ioctl(fd, JSIOCGAXMAP, joystick->hwdata->abs_pam, len) < 0) {
1010 SDL_free(joystick->hwdata->abs_pam);
1011 joystick->hwdata->abs_pam = NULL;
1012 abs_pam_size = 0;
1013 }
1014 } else {
1015 abs_pam_size = 0;
1016 }
1017 for (i = 0; i < abs_pam_size; ++i) {
1018 Uint8 code = joystick->hwdata->abs_pam[i];
1019
1020 if (code >= ABS_HAT0X && code <= ABS_HAT3Y) {
1021 int hat_index = (code - ABS_HAT0X) / 2;
1022 if (!joystick->hwdata->has_hat[hat_index]) {
1023 #ifdef DEBUG_INPUT_EVENTS
1024 SDL_Log("Joystick has hat %d\n", hat_index);
1025 #endif
1026 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
1027 joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
1028 }
1029 } else {
1030 #ifdef DEBUG_INPUT_EVENTS
1031 SDL_Log("Joystick has absolute axis: 0x%.2x\n", code);
1032 #endif
1033 joystick->hwdata->abs_map[code] = joystick->naxes;
1034 joystick->hwdata->has_abs[code] = SDL_TRUE;
1035 ++joystick->naxes;
1036 }
1037 }
1038 }
1039
1040 /* Allocate data to keep track of these thingamajigs */
1041 if (joystick->nhats > 0) {
1042 if (allocate_hatdata(joystick) < 0) {
1043 joystick->nhats = 0;
1044 }
1045 }
1046 if (joystick->nballs > 0) {
1047 if (allocate_balldata(joystick) < 0) {
1048 joystick->nballs = 0;
1049 }
1050 }
1051
1052 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
1053 if (test_bit(FF_RUMBLE, ffbit)) {
1054 joystick->hwdata->ff_rumble = SDL_TRUE;
1055 }
1056 if (test_bit(FF_SINE, ffbit)) {
1057 joystick->hwdata->ff_sine = SDL_TRUE;
1058 }
1059 }
1060 }
1061
1062
1063 /* This is used to do the heavy lifting for LINUX_JoystickOpen and
1064 also LINUX_JoystickGetGamepadMapping, so we can query the hardware
1065 without adding an opened SDL_Joystick object to the system.
1066 This expects `joystick->hwdata` to be allocated and will not free it
1067 on error. Returns -1 on error, 0 on success. */
1068 static int
PrepareJoystickHwdata(SDL_Joystick * joystick,SDL_joylist_item * item)1069 PrepareJoystickHwdata(SDL_Joystick *joystick, SDL_joylist_item *item)
1070 {
1071 joystick->hwdata->item = item;
1072 joystick->hwdata->guid = item->guid;
1073 joystick->hwdata->effect.id = -1;
1074 joystick->hwdata->m_bSteamController = item->m_bSteamController;
1075 SDL_memset(joystick->hwdata->key_map, 0xFF, sizeof(joystick->hwdata->key_map));
1076 SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
1077
1078 if (item->m_bSteamController) {
1079 joystick->hwdata->fd = -1;
1080 SDL_GetSteamControllerInputs(&joystick->nbuttons,
1081 &joystick->naxes,
1082 &joystick->nhats);
1083 } else {
1084 /* Try read-write first, so we can do rumble */
1085 int fd = open(item->path, O_RDWR | O_CLOEXEC, 0);
1086 if (fd < 0) {
1087 /* Try read-only again, at least we'll get events in this case */
1088 fd = open(item->path, O_RDONLY | O_CLOEXEC, 0);
1089 }
1090 if (fd < 0) {
1091 return SDL_SetError("Unable to open %s", item->path);
1092 }
1093
1094 joystick->hwdata->fd = fd;
1095 joystick->hwdata->fname = SDL_strdup(item->path);
1096 if (joystick->hwdata->fname == NULL) {
1097 close(fd);
1098 return SDL_OutOfMemory();
1099 }
1100
1101 /* Set the joystick to non-blocking read mode */
1102 fcntl(fd, F_SETFL, O_NONBLOCK);
1103
1104 /* Get the number of buttons and axes on the joystick */
1105 ConfigJoystick(joystick, fd);
1106 }
1107 return 0;
1108 }
1109
1110
1111 /* Function to open a joystick for use.
1112 The joystick to open is specified by the device index.
1113 This should fill the nbuttons and naxes fields of the joystick structure.
1114 It returns 0, or -1 if there is an error.
1115 */
1116 static int
LINUX_JoystickOpen(SDL_Joystick * joystick,int device_index)1117 LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
1118 {
1119 SDL_joylist_item *item = JoystickByDevIndex(device_index);
1120
1121 if (item == NULL) {
1122 return SDL_SetError("No such device");
1123 }
1124
1125 joystick->instance_id = item->device_instance;
1126 joystick->hwdata = (struct joystick_hwdata *)
1127 SDL_calloc(1, sizeof(*joystick->hwdata));
1128 if (joystick->hwdata == NULL) {
1129 return SDL_OutOfMemory();
1130 }
1131
1132 if (PrepareJoystickHwdata(joystick, item) == -1) {
1133 SDL_free(joystick->hwdata);
1134 joystick->hwdata = NULL;
1135 return -1; /* SDL_SetError will already have been called */
1136 }
1137
1138 SDL_assert(item->hwdata == NULL);
1139 item->hwdata = joystick->hwdata;
1140
1141 /* mark joystick as fresh and ready */
1142 joystick->hwdata->fresh = SDL_TRUE;
1143
1144 return 0;
1145 }
1146
1147 static int
LINUX_JoystickRumble(SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1148 LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1149 {
1150 struct input_event event;
1151
1152 if (joystick->hwdata->ff_rumble) {
1153 struct ff_effect *effect = &joystick->hwdata->effect;
1154
1155 effect->type = FF_RUMBLE;
1156 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1157 effect->u.rumble.strong_magnitude = low_frequency_rumble;
1158 effect->u.rumble.weak_magnitude = high_frequency_rumble;
1159 } else if (joystick->hwdata->ff_sine) {
1160 /* Scale and average the two rumble strengths */
1161 Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
1162 struct ff_effect *effect = &joystick->hwdata->effect;
1163
1164 effect->type = FF_PERIODIC;
1165 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1166 effect->u.periodic.waveform = FF_SINE;
1167 effect->u.periodic.magnitude = magnitude;
1168 } else {
1169 return SDL_Unsupported();
1170 }
1171
1172 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1173 /* The kernel may have lost this effect, try to allocate a new one */
1174 joystick->hwdata->effect.id = -1;
1175 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1176 return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
1177 }
1178 }
1179
1180 event.type = EV_FF;
1181 event.code = joystick->hwdata->effect.id;
1182 event.value = 1;
1183 if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
1184 return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
1185 }
1186 return 0;
1187 }
1188
1189 static int
LINUX_JoystickRumbleTriggers(SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)1190 LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1191 {
1192 return SDL_Unsupported();
1193 }
1194
1195 static Uint32
LINUX_JoystickGetCapabilities(SDL_Joystick * joystick)1196 LINUX_JoystickGetCapabilities(SDL_Joystick *joystick)
1197 {
1198 Uint32 result = 0;
1199
1200 if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) {
1201 result |= SDL_JOYCAP_RUMBLE;
1202 }
1203
1204 return result;
1205 }
1206
1207 static int
LINUX_JoystickSetLED(SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)1208 LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1209 {
1210 return SDL_Unsupported();
1211 }
1212
1213 static int
LINUX_JoystickSendEffect(SDL_Joystick * joystick,const void * data,int size)1214 LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
1215 {
1216 return SDL_Unsupported();
1217 }
1218
1219 static int
LINUX_JoystickSetSensorsEnabled(SDL_Joystick * joystick,SDL_bool enabled)1220 LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
1221 {
1222 return SDL_Unsupported();
1223 }
1224
1225 static void
HandleHat(SDL_Joystick * stick,Uint8 hat,int axis,int value)1226 HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
1227 {
1228 struct hwdata_hat *the_hat;
1229 const Uint8 position_map[3][3] = {
1230 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
1231 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
1232 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
1233 };
1234
1235 the_hat = &stick->hwdata->hats[hat];
1236 if (value < 0) {
1237 value = 0;
1238 } else if (value == 0) {
1239 value = 1;
1240 } else if (value > 0) {
1241 value = 2;
1242 }
1243 if (value != the_hat->axis[axis]) {
1244 the_hat->axis[axis] = value;
1245 SDL_PrivateJoystickHat(stick, hat,
1246 position_map[the_hat->axis[1]][the_hat->axis[0]]);
1247 }
1248 }
1249
1250 static void
HandleBall(SDL_Joystick * stick,Uint8 ball,int axis,int value)1251 HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
1252 {
1253 stick->hwdata->balls[ball].axis[axis] += value;
1254 }
1255
1256
1257 static int
AxisCorrect(SDL_Joystick * joystick,int which,int value)1258 AxisCorrect(SDL_Joystick *joystick, int which, int value)
1259 {
1260 struct axis_correct *correct;
1261
1262 correct = &joystick->hwdata->abs_correct[which];
1263 if (correct->minimum != correct->maximum) {
1264 if (correct->use_deadzones) {
1265 value *= 2;
1266 if (value > correct->coef[0]) {
1267 if (value < correct->coef[1]) {
1268 return 0;
1269 }
1270 value -= correct->coef[1];
1271 } else {
1272 value -= correct->coef[0];
1273 }
1274 value *= correct->coef[2];
1275 value >>= 13;
1276 } else {
1277 value = (int)SDL_floorf((value - correct->minimum) * correct->scale + SDL_JOYSTICK_AXIS_MIN + 0.5f);
1278 }
1279 }
1280
1281 /* Clamp and return */
1282 if (value < SDL_JOYSTICK_AXIS_MIN) {
1283 return SDL_JOYSTICK_AXIS_MIN;
1284 }
1285 if (value > SDL_JOYSTICK_AXIS_MAX) {
1286 return SDL_JOYSTICK_AXIS_MAX;
1287 }
1288 return value;
1289 }
1290
1291 static void
PollAllValues(SDL_Joystick * joystick)1292 PollAllValues(SDL_Joystick *joystick)
1293 {
1294 struct input_absinfo absinfo;
1295 unsigned long keyinfo[NBITS(KEY_MAX)];
1296 int i;
1297
1298 /* Poll all axis */
1299 for (i = ABS_X; i < ABS_MAX; i++) {
1300 if (i == ABS_HAT0X) { /* we handle hats in the next loop, skip them for now. */
1301 i = ABS_HAT3Y;
1302 continue;
1303 }
1304 if (joystick->hwdata->has_abs[i]) {
1305 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1306 absinfo.value = AxisCorrect(joystick, i, absinfo.value);
1307
1308 #ifdef DEBUG_INPUT_EVENTS
1309 SDL_Log("Joystick : Re-read Axis %d (%d) val= %d\n",
1310 joystick->hwdata->abs_map[i], i, absinfo.value);
1311 #endif
1312 SDL_PrivateJoystickAxis(joystick,
1313 joystick->hwdata->abs_map[i],
1314 absinfo.value);
1315 }
1316 }
1317 }
1318
1319 /* Poll all hats */
1320 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) {
1321 const int baseaxis = i - ABS_HAT0X;
1322 const int hatidx = baseaxis / 2;
1323 SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat));
1324 if (joystick->hwdata->has_hat[hatidx]) {
1325 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1326 const int hataxis = baseaxis % 2;
1327 HandleHat(joystick, joystick->hwdata->hats_indices[hatidx], hataxis, absinfo.value);
1328 }
1329 }
1330 }
1331
1332 /* Poll all buttons */
1333 SDL_zeroa(keyinfo);
1334 if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof (keyinfo)), keyinfo) >= 0) {
1335 for (i = 0; i < KEY_MAX; i++) {
1336 if (joystick->hwdata->has_key[i]) {
1337 const Uint8 value = test_bit(i, keyinfo) ? SDL_PRESSED : SDL_RELEASED;
1338 #ifdef DEBUG_INPUT_EVENTS
1339 SDL_Log("Joystick : Re-read Button %d (%d) val= %d\n",
1340 joystick->hwdata->key_map[i], i, value);
1341 #endif
1342 SDL_PrivateJoystickButton(joystick,
1343 joystick->hwdata->key_map[i], value);
1344 }
1345 }
1346 }
1347
1348 /* Joyballs are relative input, so there's no poll state. Events only! */
1349 }
1350
1351 static void
HandleInputEvents(SDL_Joystick * joystick)1352 HandleInputEvents(SDL_Joystick *joystick)
1353 {
1354 struct input_event events[32];
1355 int i, len, code;
1356
1357 if (joystick->hwdata->fresh) {
1358 PollAllValues(joystick);
1359 joystick->hwdata->fresh = SDL_FALSE;
1360 }
1361
1362 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1363 len /= sizeof(events[0]);
1364 for (i = 0; i < len; ++i) {
1365 code = events[i].code;
1366
1367 /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
1368 rest of the packet (the end of it signified by a SYN_REPORT) */
1369 if ( joystick->hwdata->recovering_from_dropped &&
1370 ((events[i].type != EV_SYN) || (code != SYN_REPORT)) ) {
1371 continue;
1372 }
1373
1374 switch (events[i].type) {
1375 case EV_KEY:
1376 SDL_PrivateJoystickButton(joystick,
1377 joystick->hwdata->key_map[code],
1378 events[i].value);
1379 break;
1380 case EV_ABS:
1381 switch (code) {
1382 case ABS_HAT0X:
1383 case ABS_HAT0Y:
1384 case ABS_HAT1X:
1385 case ABS_HAT1Y:
1386 case ABS_HAT2X:
1387 case ABS_HAT2Y:
1388 case ABS_HAT3X:
1389 case ABS_HAT3Y:
1390 code -= ABS_HAT0X;
1391 HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1392 break;
1393 default:
1394 events[i].value = AxisCorrect(joystick, code, events[i].value);
1395 SDL_PrivateJoystickAxis(joystick,
1396 joystick->hwdata->abs_map[code],
1397 events[i].value);
1398 break;
1399 }
1400 break;
1401 case EV_REL:
1402 switch (code) {
1403 case REL_X:
1404 case REL_Y:
1405 code -= REL_X;
1406 HandleBall(joystick, code / 2, code % 2, events[i].value);
1407 break;
1408 default:
1409 break;
1410 }
1411 break;
1412 case EV_SYN:
1413 switch (code) {
1414 case SYN_DROPPED :
1415 #ifdef DEBUG_INPUT_EVENTS
1416 SDL_Log("Event SYN_DROPPED detected\n");
1417 #endif
1418 joystick->hwdata->recovering_from_dropped = SDL_TRUE;
1419 break;
1420 case SYN_REPORT :
1421 if (joystick->hwdata->recovering_from_dropped) {
1422 joystick->hwdata->recovering_from_dropped = SDL_FALSE;
1423 PollAllValues(joystick); /* try to sync up to current state now */
1424 }
1425 break;
1426 default:
1427 break;
1428 }
1429 default:
1430 break;
1431 }
1432 }
1433 }
1434
1435 if (errno == ENODEV) {
1436 /* We have to wait until the JoystickDetect callback to remove this */
1437 joystick->hwdata->gone = SDL_TRUE;
1438 }
1439 }
1440
1441 static void
HandleClassicEvents(SDL_Joystick * joystick)1442 HandleClassicEvents(SDL_Joystick *joystick)
1443 {
1444 struct js_event events[32];
1445 int i, len, code;
1446
1447 joystick->hwdata->fresh = SDL_FALSE;
1448 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1449 len /= sizeof(events[0]);
1450 for (i = 0; i < len; ++i) {
1451 switch (events[i].type) {
1452 case JS_EVENT_BUTTON:
1453 code = joystick->hwdata->key_pam[events[i].number];
1454 SDL_PrivateJoystickButton(joystick,
1455 joystick->hwdata->key_map[code],
1456 events[i].value);
1457 break;
1458 case JS_EVENT_AXIS:
1459 code = joystick->hwdata->abs_pam[events[i].number];
1460 switch (code) {
1461 case ABS_HAT0X:
1462 case ABS_HAT0Y:
1463 case ABS_HAT1X:
1464 case ABS_HAT1Y:
1465 case ABS_HAT2X:
1466 case ABS_HAT2Y:
1467 case ABS_HAT3X:
1468 case ABS_HAT3Y:
1469 code -= ABS_HAT0X;
1470 HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1471 break;
1472 default:
1473 SDL_PrivateJoystickAxis(joystick,
1474 joystick->hwdata->abs_map[code],
1475 events[i].value);
1476 break;
1477 }
1478 }
1479 }
1480 }
1481 }
1482
1483 static void
LINUX_JoystickUpdate(SDL_Joystick * joystick)1484 LINUX_JoystickUpdate(SDL_Joystick *joystick)
1485 {
1486 int i;
1487
1488 if (joystick->hwdata->m_bSteamController) {
1489 SDL_UpdateSteamController(joystick);
1490 return;
1491 }
1492
1493 if (joystick->hwdata->classic) {
1494 HandleClassicEvents(joystick);
1495 } else {
1496 HandleInputEvents(joystick);
1497 }
1498
1499 /* Deliver ball motion updates */
1500 for (i = 0; i < joystick->nballs; ++i) {
1501 int xrel, yrel;
1502
1503 xrel = joystick->hwdata->balls[i].axis[0];
1504 yrel = joystick->hwdata->balls[i].axis[1];
1505 if (xrel || yrel) {
1506 joystick->hwdata->balls[i].axis[0] = 0;
1507 joystick->hwdata->balls[i].axis[1] = 0;
1508 SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1509 }
1510 }
1511 }
1512
1513 /* Function to close a joystick after use */
1514 static void
LINUX_JoystickClose(SDL_Joystick * joystick)1515 LINUX_JoystickClose(SDL_Joystick *joystick)
1516 {
1517 if (joystick->hwdata) {
1518 if (joystick->hwdata->effect.id >= 0) {
1519 ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1520 joystick->hwdata->effect.id = -1;
1521 }
1522 if (joystick->hwdata->fd >= 0) {
1523 close(joystick->hwdata->fd);
1524 }
1525 if (joystick->hwdata->item) {
1526 joystick->hwdata->item->hwdata = NULL;
1527 }
1528 SDL_free(joystick->hwdata->key_pam);
1529 SDL_free(joystick->hwdata->abs_pam);
1530 SDL_free(joystick->hwdata->hats);
1531 SDL_free(joystick->hwdata->balls);
1532 SDL_free(joystick->hwdata->fname);
1533 SDL_free(joystick->hwdata);
1534 }
1535 }
1536
1537 /* Function to perform any system-specific joystick related cleanup */
1538 static void
LINUX_JoystickQuit(void)1539 LINUX_JoystickQuit(void)
1540 {
1541 SDL_joylist_item *item = NULL;
1542 SDL_joylist_item *next = NULL;
1543
1544 if (inotify_fd >= 0) {
1545 close(inotify_fd);
1546 inotify_fd = -1;
1547 }
1548
1549 for (item = SDL_joylist; item; item = next) {
1550 next = item->next;
1551 FreeJoylistItem(item);
1552 }
1553
1554 SDL_joylist = SDL_joylist_tail = NULL;
1555
1556 numjoysticks = 0;
1557
1558 #if SDL_USE_LIBUDEV
1559 if (enumeration_method == ENUMERATION_LIBUDEV) {
1560 SDL_UDEV_DelCallback(joystick_udev_callback);
1561 SDL_UDEV_Quit();
1562 }
1563 #endif
1564
1565 SDL_QuitSteamControllers();
1566 }
1567
1568 /*
1569 This is based on the Linux Gamepad Specification
1570 available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
1571 */
1572 static SDL_bool
LINUX_JoystickGetGamepadMapping(int device_index,SDL_GamepadMapping * out)1573 LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1574 {
1575 SDL_Joystick *joystick;
1576 SDL_joylist_item *item = JoystickByDevIndex(device_index);
1577
1578 if (item->mapping) {
1579 SDL_memcpy(out, item->mapping, sizeof(*out));
1580 return SDL_TRUE;
1581 }
1582
1583 /* We temporarily open the device to check how it's configured. Make
1584 a fake SDL_Joystick object to do so. */
1585 joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
1586 if (joystick == NULL) {
1587 SDL_OutOfMemory();
1588 return SDL_FALSE;
1589 }
1590 SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
1591
1592 joystick->hwdata = (struct joystick_hwdata *)
1593 SDL_calloc(1, sizeof(*joystick->hwdata));
1594 if (joystick->hwdata == NULL) {
1595 SDL_free(joystick);
1596 SDL_OutOfMemory();
1597 return SDL_FALSE;
1598 }
1599
1600 if (PrepareJoystickHwdata(joystick, item) == -1) {
1601 SDL_free(joystick->hwdata);
1602 SDL_free(joystick);
1603 return SDL_FALSE; /* SDL_SetError will already have been called */
1604 }
1605
1606 /* don't assign `item->hwdata` so it's not in any global state. */
1607
1608 /* it is now safe to call LINUX_JoystickClose on this fake joystick. */
1609
1610 if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
1611 /* Not a gamepad according to the specs. */
1612 LINUX_JoystickClose(joystick);
1613 SDL_free(joystick);
1614 return SDL_FALSE;
1615 }
1616
1617 /* We have a gamepad, start filling out the mappings */
1618
1619 if (joystick->hwdata->has_key[BTN_A]) {
1620 out->a.kind = EMappingKind_Button;
1621 out->a.target = joystick->hwdata->key_map[BTN_A];
1622 }
1623
1624 if (joystick->hwdata->has_key[BTN_B]) {
1625 out->b.kind = EMappingKind_Button;
1626 out->b.target = joystick->hwdata->key_map[BTN_B];
1627 }
1628
1629 /* Xbox controllers use BTN_X and BTN_Y, and PS4 controllers use BTN_WEST and BTN_NORTH */
1630 if (SDL_JoystickGetVendor(joystick) == USB_VENDOR_SONY) {
1631 if (joystick->hwdata->has_key[BTN_WEST]) {
1632 out->x.kind = EMappingKind_Button;
1633 out->x.target = joystick->hwdata->key_map[BTN_WEST];
1634 }
1635
1636 if (joystick->hwdata->has_key[BTN_NORTH]) {
1637 out->y.kind = EMappingKind_Button;
1638 out->y.target = joystick->hwdata->key_map[BTN_NORTH];
1639 }
1640 } else {
1641 if (joystick->hwdata->has_key[BTN_X]) {
1642 out->x.kind = EMappingKind_Button;
1643 out->x.target = joystick->hwdata->key_map[BTN_X];
1644 }
1645
1646 if (joystick->hwdata->has_key[BTN_Y]) {
1647 out->y.kind = EMappingKind_Button;
1648 out->y.target = joystick->hwdata->key_map[BTN_Y];
1649 }
1650 }
1651
1652 if (joystick->hwdata->has_key[BTN_SELECT]) {
1653 out->back.kind = EMappingKind_Button;
1654 out->back.target = joystick->hwdata->key_map[BTN_SELECT];
1655 }
1656
1657 if (joystick->hwdata->has_key[BTN_START]) {
1658 out->start.kind = EMappingKind_Button;
1659 out->start.target = joystick->hwdata->key_map[BTN_START];
1660 }
1661
1662 if (joystick->hwdata->has_key[BTN_THUMBL]) {
1663 out->leftstick.kind = EMappingKind_Button;
1664 out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL];
1665 }
1666
1667 if (joystick->hwdata->has_key[BTN_THUMBR]) {
1668 out->rightstick.kind = EMappingKind_Button;
1669 out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR];
1670 }
1671
1672 if (joystick->hwdata->has_key[BTN_MODE]) {
1673 out->guide.kind = EMappingKind_Button;
1674 out->guide.target = joystick->hwdata->key_map[BTN_MODE];
1675 }
1676
1677 /*
1678 According to the specs the D-Pad, the shoulder buttons and the triggers
1679 can be digital, or analog, or both at the same time.
1680 */
1681
1682 /* Prefer digital shoulder buttons, but settle for analog if missing. */
1683 if (joystick->hwdata->has_key[BTN_TL]) {
1684 out->leftshoulder.kind = EMappingKind_Button;
1685 out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL];
1686 }
1687
1688 if (joystick->hwdata->has_key[BTN_TR]) {
1689 out->rightshoulder.kind = EMappingKind_Button;
1690 out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR];
1691 }
1692
1693 if (joystick->hwdata->has_hat[1] && /* Check if ABS_HAT1{X, Y} is available. */
1694 (!joystick->hwdata->has_key[BTN_TL] || !joystick->hwdata->has_key[BTN_TR])) {
1695 int hat = joystick->hwdata->hats_indices[1] << 4;
1696 out->leftshoulder.kind = EMappingKind_Hat;
1697 out->rightshoulder.kind = EMappingKind_Hat;
1698 out->leftshoulder.target = hat | 0x4;
1699 out->rightshoulder.target = hat | 0x2;
1700 }
1701
1702 /* Prefer analog triggers, but settle for digital if missing. */
1703 if (joystick->hwdata->has_hat[2]) { /* Check if ABS_HAT2{X,Y} is available. */
1704 int hat = joystick->hwdata->hats_indices[2] << 4;
1705 out->lefttrigger.kind = EMappingKind_Hat;
1706 out->righttrigger.kind = EMappingKind_Hat;
1707 out->lefttrigger.target = hat | 0x4;
1708 out->righttrigger.target = hat | 0x2;
1709 } else {
1710 if (joystick->hwdata->has_abs[ABS_Z]) {
1711 out->lefttrigger.kind = EMappingKind_Axis;
1712 out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z];
1713 } else if (joystick->hwdata->has_key[BTN_TL2]) {
1714 out->lefttrigger.kind = EMappingKind_Button;
1715 out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2];
1716 }
1717
1718 if (joystick->hwdata->has_abs[ABS_RZ]) {
1719 out->righttrigger.kind = EMappingKind_Axis;
1720 out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ];
1721 } else if (joystick->hwdata->has_key[BTN_TR2]) {
1722 out->righttrigger.kind = EMappingKind_Button;
1723 out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
1724 }
1725 }
1726
1727 /* Prefer digital D-Pad, but settle for analog if missing. */
1728 if (joystick->hwdata->has_key[BTN_DPAD_UP]) {
1729 out->dpup.kind = EMappingKind_Button;
1730 out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP];
1731 }
1732
1733 if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) {
1734 out->dpdown.kind = EMappingKind_Button;
1735 out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN];
1736 }
1737
1738 if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) {
1739 out->dpleft.kind = EMappingKind_Button;
1740 out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT];
1741 }
1742
1743 if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) {
1744 out->dpright.kind = EMappingKind_Button;
1745 out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT];
1746 }
1747
1748 if (joystick->hwdata->has_hat[0] && /* Check if ABS_HAT0{X,Y} is available. */
1749 (!joystick->hwdata->has_key[BTN_DPAD_LEFT] || !joystick->hwdata->has_key[BTN_DPAD_RIGHT] ||
1750 !joystick->hwdata->has_key[BTN_DPAD_UP] || !joystick->hwdata->has_key[BTN_DPAD_DOWN])) {
1751 int hat = joystick->hwdata->hats_indices[0] << 4;
1752 out->dpleft.kind = EMappingKind_Hat;
1753 out->dpright.kind = EMappingKind_Hat;
1754 out->dpup.kind = EMappingKind_Hat;
1755 out->dpdown.kind = EMappingKind_Hat;
1756 out->dpleft.target = hat | 0x8;
1757 out->dpright.target = hat | 0x2;
1758 out->dpup.target = hat | 0x1;
1759 out->dpdown.target = hat | 0x4;
1760 }
1761
1762 if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) {
1763 out->leftx.kind = EMappingKind_Axis;
1764 out->lefty.kind = EMappingKind_Axis;
1765 out->leftx.target = joystick->hwdata->abs_map[ABS_X];
1766 out->lefty.target = joystick->hwdata->abs_map[ABS_Y];
1767 }
1768
1769 if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
1770 out->rightx.kind = EMappingKind_Axis;
1771 out->righty.kind = EMappingKind_Axis;
1772 out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
1773 out->righty.target = joystick->hwdata->abs_map[ABS_RY];
1774 }
1775
1776 LINUX_JoystickClose(joystick);
1777 SDL_free(joystick);
1778
1779 /* Cache the mapping for later */
1780 item->mapping = (SDL_GamepadMapping *)SDL_malloc(sizeof(*item->mapping));
1781 if (item->mapping) {
1782 SDL_memcpy(item->mapping, out, sizeof(*out));
1783 }
1784
1785 return SDL_TRUE;
1786 }
1787
1788 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
1789 {
1790 LINUX_JoystickInit,
1791 LINUX_JoystickGetCount,
1792 LINUX_JoystickDetect,
1793 LINUX_JoystickGetDeviceName,
1794 LINUX_JoystickGetDevicePlayerIndex,
1795 LINUX_JoystickSetDevicePlayerIndex,
1796 LINUX_JoystickGetDeviceGUID,
1797 LINUX_JoystickGetDeviceInstanceID,
1798 LINUX_JoystickOpen,
1799 LINUX_JoystickRumble,
1800 LINUX_JoystickRumbleTriggers,
1801 LINUX_JoystickGetCapabilities,
1802 LINUX_JoystickSetLED,
1803 LINUX_JoystickSendEffect,
1804 LINUX_JoystickSetSensorsEnabled,
1805 LINUX_JoystickUpdate,
1806 LINUX_JoystickClose,
1807 LINUX_JoystickQuit,
1808 LINUX_JoystickGetGamepadMapping
1809 };
1810
1811 #endif /* SDL_JOYSTICK_LINUX */
1812
1813 /* vi: set ts=4 sw=4 expandtab: */
1814