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
510 static int
StrHasPrefix(const char * string,const char * prefix)511 StrHasPrefix(const char *string, const char *prefix)
512 {
513 return (SDL_strncmp(string, prefix, SDL_strlen(prefix)) == 0);
514 }
515
516 static int
StrIsInteger(const char * string)517 StrIsInteger(const char *string)
518 {
519 const char *p;
520
521 if (*string == '\0') {
522 return 0;
523 }
524
525 for (p = string; *p != '\0'; p++) {
526 if (*p < '0' || *p > '9') {
527 return 0;
528 }
529 }
530
531 return 1;
532 }
533
534 static SDL_bool
IsJoystickJSNode(const char * node)535 IsJoystickJSNode(const char *node)
536 {
537 const char *last_slash = SDL_strrchr(node, '/');
538 if (last_slash) {
539 node = last_slash + 1;
540 }
541 return (StrHasPrefix(node, "js") && StrIsInteger(node + 2));
542 }
543
544 static SDL_bool
IsJoystickEventNode(const char * node)545 IsJoystickEventNode(const char *node)
546 {
547 const char *last_slash = SDL_strrchr(node, '/');
548 if (last_slash) {
549 node = last_slash + 1;
550 }
551 return (StrHasPrefix(node, "event") && StrIsInteger(node + 5));
552 }
553
554 static SDL_bool
IsJoystickDeviceNode(const char * node)555 IsJoystickDeviceNode(const char *node)
556 {
557 if (SDL_classic_joysticks) {
558 return IsJoystickJSNode(node);
559 } else {
560 return IsJoystickEventNode(node);
561 }
562 }
563
564 static void
LINUX_InotifyJoystickDetect(void)565 LINUX_InotifyJoystickDetect(void)
566 {
567 union
568 {
569 struct inotify_event event;
570 char storage[4096];
571 char enough_for_inotify[sizeof (struct inotify_event) + NAME_MAX + 1];
572 } buf;
573 ssize_t bytes;
574 size_t remain = 0;
575 size_t len;
576 char path[PATH_MAX];
577
578 bytes = read(inotify_fd, &buf, sizeof (buf));
579
580 if (bytes > 0) {
581 remain = (size_t) bytes;
582 }
583
584 while (remain > 0) {
585 if (buf.event.len > 0) {
586 if (IsJoystickDeviceNode(buf.event.name)) {
587 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", buf.event.name);
588
589 if (buf.event.mask & (IN_CREATE | IN_MOVED_TO | IN_ATTRIB)) {
590 MaybeAddDevice(path);
591 }
592 else if (buf.event.mask & (IN_DELETE | IN_MOVED_FROM)) {
593 MaybeRemoveDevice(path);
594 }
595 }
596 }
597
598 len = sizeof (struct inotify_event) + buf.event.len;
599 remain -= len;
600
601 if (remain != 0) {
602 SDL_memmove (&buf.storage[0], &buf.storage[len], remain);
603 }
604 }
605 }
606 #endif /* HAVE_INOTIFY */
607
608 /* Detect devices by reading /dev/input. In the inotify code path we
609 * have to do this the first time, to detect devices that already existed
610 * before we started; in the non-inotify code path we do this repeatedly
611 * (polling). */
612 static int
filter_entries(const struct dirent * entry)613 filter_entries(const struct dirent *entry)
614 {
615 return IsJoystickDeviceNode(entry->d_name);
616 }
617 static int
sort_entries(const struct dirent ** a,const struct dirent ** b)618 sort_entries(const struct dirent **a, const struct dirent **b)
619 {
620 int numA = SDL_atoi((*a)->d_name+5);
621 int numB = SDL_atoi((*b)->d_name+5);
622 return (numA - numB);
623 }
624 static void
LINUX_FallbackJoystickDetect(void)625 LINUX_FallbackJoystickDetect(void)
626 {
627 const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000; /* Update every 3 seconds */
628 Uint32 now = SDL_GetTicks();
629
630 if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
631 struct stat sb;
632
633 /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
634 if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
635 int i, count;
636 struct dirent **entries;
637 char path[PATH_MAX];
638
639 count = scandir("/dev/input", &entries, filter_entries, sort_entries);
640 for (i = 0; i < count; ++i) {
641 SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", entries[i]->d_name);
642 MaybeAddDevice(path);
643
644 free(entries[i]); /* This should NOT be SDL_free() */
645 }
646 free(entries); /* This should NOT be SDL_free() */
647
648 last_input_dir_mtime = sb.st_mtime;
649 }
650
651 last_joy_detect_time = now;
652 }
653 }
654
655 static void
LINUX_JoystickDetect(void)656 LINUX_JoystickDetect(void)
657 {
658 #if SDL_USE_LIBUDEV
659 if (enumeration_method == ENUMERATION_LIBUDEV) {
660 SDL_UDEV_Poll();
661 }
662 else
663 #endif
664 #ifdef HAVE_INOTIFY
665 if (inotify_fd >= 0 && last_joy_detect_time != 0) {
666 LINUX_InotifyJoystickDetect();
667 }
668 else
669 #endif
670 {
671 LINUX_FallbackJoystickDetect();
672 }
673
674 HandlePendingRemovals();
675
676 SDL_UpdateSteamControllers();
677 }
678
679 static int
LINUX_JoystickInit(void)680 LINUX_JoystickInit(void)
681 {
682 const char *devices = SDL_GetHint(SDL_HINT_JOYSTICK_DEVICE);
683
684 SDL_classic_joysticks = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_CLASSIC, SDL_FALSE);
685
686 #if SDL_USE_LIBUDEV
687 if (enumeration_method == ENUMERATION_UNSET) {
688 if (SDL_GetHintBoolean("SDL_JOYSTICK_DISABLE_UDEV", SDL_FALSE)) {
689 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
690 "udev disabled by SDL_JOYSTICK_DISABLE_UDEV");
691 enumeration_method = ENUMERATION_FALLBACK;
692
693 } else if (access("/.flatpak-info", F_OK) == 0
694 || access("/run/host/container-manager", F_OK) == 0) {
695 /* Explicitly check `/.flatpak-info` because, for old versions of
696 * Flatpak, this was the only available way to tell if we were in
697 * a Flatpak container. */
698 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
699 "Container detected, disabling udev integration");
700 enumeration_method = ENUMERATION_FALLBACK;
701
702 } else {
703 SDL_LogDebug(SDL_LOG_CATEGORY_INPUT,
704 "Using udev for joystick device discovery");
705 enumeration_method = ENUMERATION_LIBUDEV;
706 }
707 }
708 #endif
709
710 /* First see if the user specified one or more joysticks to use */
711 if (devices != NULL) {
712 char *envcopy, *envpath, *delim;
713 envcopy = SDL_strdup(devices);
714 envpath = envcopy;
715 while (envpath != NULL) {
716 delim = SDL_strchr(envpath, ':');
717 if (delim != NULL) {
718 *delim++ = '\0';
719 }
720 MaybeAddDevice(envpath);
721 envpath = delim;
722 }
723 SDL_free(envcopy);
724 }
725
726 SDL_InitSteamControllers(SteamControllerConnectedCallback,
727 SteamControllerDisconnectedCallback);
728
729 /* Force immediate joystick detection if using fallback */
730 last_joy_detect_time = 0;
731 last_input_dir_mtime = 0;
732
733 /* Manually scan first, since we sort by device number and udev doesn't */
734 LINUX_JoystickDetect();
735
736 #if SDL_USE_LIBUDEV
737 if (enumeration_method == ENUMERATION_LIBUDEV) {
738 if (SDL_UDEV_Init() < 0) {
739 return SDL_SetError("Could not initialize UDEV");
740 }
741
742 /* Set up the udev callback */
743 if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
744 SDL_UDEV_Quit();
745 return SDL_SetError("Could not set up joystick <-> udev callback");
746 }
747
748 /* Force a scan to build the initial device list */
749 SDL_UDEV_Scan();
750 }
751 else
752 #endif
753 {
754 #if defined(HAVE_INOTIFY)
755 inotify_fd = SDL_inotify_init1();
756
757 if (inotify_fd < 0) {
758 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
759 "Unable to initialize inotify, falling back to polling: %s",
760 strerror (errno));
761 } else {
762 /* We need to watch for attribute changes in addition to
763 * creation, because when a device is first created, it has
764 * permissions that we can't read. When udev chmods it to
765 * something that we maybe *can* read, we'll get an
766 * IN_ATTRIB event to tell us. */
767 if (inotify_add_watch(inotify_fd, "/dev/input",
768 IN_CREATE | IN_DELETE | IN_MOVE | IN_ATTRIB) < 0) {
769 close(inotify_fd);
770 inotify_fd = -1;
771 SDL_LogWarn(SDL_LOG_CATEGORY_INPUT,
772 "Unable to add inotify watch, falling back to polling: %s",
773 strerror (errno));
774 }
775 }
776 #endif /* HAVE_INOTIFY */
777 }
778
779 return 0;
780 }
781
782 static int
LINUX_JoystickGetCount(void)783 LINUX_JoystickGetCount(void)
784 {
785 return numjoysticks;
786 }
787
788 static SDL_joylist_item *
JoystickByDevIndex(int device_index)789 JoystickByDevIndex(int device_index)
790 {
791 SDL_joylist_item *item = SDL_joylist;
792
793 if ((device_index < 0) || (device_index >= numjoysticks)) {
794 return NULL;
795 }
796
797 while (device_index > 0) {
798 SDL_assert(item != NULL);
799 device_index--;
800 item = item->next;
801 }
802
803 return item;
804 }
805
806 /* Function to get the device-dependent name of a joystick */
807 static const char *
LINUX_JoystickGetDeviceName(int device_index)808 LINUX_JoystickGetDeviceName(int device_index)
809 {
810 return JoystickByDevIndex(device_index)->name;
811 }
812
813 static int
LINUX_JoystickGetDevicePlayerIndex(int device_index)814 LINUX_JoystickGetDevicePlayerIndex(int device_index)
815 {
816 return -1;
817 }
818
819 static void
LINUX_JoystickSetDevicePlayerIndex(int device_index,int player_index)820 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
821 {
822 }
823
824 static SDL_JoystickGUID
LINUX_JoystickGetDeviceGUID(int device_index)825 LINUX_JoystickGetDeviceGUID( int device_index )
826 {
827 return JoystickByDevIndex(device_index)->guid;
828 }
829
830 /* Function to perform the mapping from device index to the instance id for this index */
831 static SDL_JoystickID
LINUX_JoystickGetDeviceInstanceID(int device_index)832 LINUX_JoystickGetDeviceInstanceID(int device_index)
833 {
834 return JoystickByDevIndex(device_index)->device_instance;
835 }
836
837 static int
allocate_hatdata(SDL_Joystick * joystick)838 allocate_hatdata(SDL_Joystick *joystick)
839 {
840 int i;
841
842 joystick->hwdata->hats =
843 (struct hwdata_hat *) SDL_malloc(joystick->nhats *
844 sizeof(struct hwdata_hat));
845 if (joystick->hwdata->hats == NULL) {
846 return (-1);
847 }
848 for (i = 0; i < joystick->nhats; ++i) {
849 joystick->hwdata->hats[i].axis[0] = 1;
850 joystick->hwdata->hats[i].axis[1] = 1;
851 }
852 return (0);
853 }
854
855 static int
allocate_balldata(SDL_Joystick * joystick)856 allocate_balldata(SDL_Joystick *joystick)
857 {
858 int i;
859
860 joystick->hwdata->balls =
861 (struct hwdata_ball *) SDL_malloc(joystick->nballs *
862 sizeof(struct hwdata_ball));
863 if (joystick->hwdata->balls == NULL) {
864 return (-1);
865 }
866 for (i = 0; i < joystick->nballs; ++i) {
867 joystick->hwdata->balls[i].axis[0] = 0;
868 joystick->hwdata->balls[i].axis[1] = 0;
869 }
870 return (0);
871 }
872
873 static void
ConfigJoystick(SDL_Joystick * joystick,int fd)874 ConfigJoystick(SDL_Joystick *joystick, int fd)
875 {
876 int i, t;
877 unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
878 unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
879 unsigned long relbit[NBITS(REL_MAX)] = { 0 };
880 unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
881 Uint8 key_pam_size, abs_pam_size;
882 SDL_bool use_deadzones = SDL_GetHintBoolean(SDL_HINT_LINUX_JOYSTICK_DEADZONES, SDL_FALSE);
883
884 /* See if this device uses the new unified event API */
885 if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
886 (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
887 (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
888
889 /* Get the number of buttons, axes, and other thingamajigs */
890 for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
891 if (test_bit(i, keybit)) {
892 #ifdef DEBUG_INPUT_EVENTS
893 SDL_Log("Joystick has button: 0x%x\n", i);
894 #endif
895 joystick->hwdata->key_map[i] = joystick->nbuttons;
896 joystick->hwdata->has_key[i] = SDL_TRUE;
897 ++joystick->nbuttons;
898 }
899 }
900 for (i = 0; i < BTN_JOYSTICK; ++i) {
901 if (test_bit(i, keybit)) {
902 #ifdef DEBUG_INPUT_EVENTS
903 SDL_Log("Joystick has button: 0x%x\n", i);
904 #endif
905 joystick->hwdata->key_map[i] = joystick->nbuttons;
906 joystick->hwdata->has_key[i] = SDL_TRUE;
907 ++joystick->nbuttons;
908 }
909 }
910 for (i = 0; i < ABS_MAX; ++i) {
911 /* Skip hats */
912 if (i == ABS_HAT0X) {
913 i = ABS_HAT3Y;
914 continue;
915 }
916 if (test_bit(i, absbit)) {
917 struct input_absinfo absinfo;
918 struct axis_correct *correct = &joystick->hwdata->abs_correct[i];
919
920 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
921 continue;
922 }
923 #ifdef DEBUG_INPUT_EVENTS
924 SDL_Log("Joystick has absolute axis: 0x%.2x\n", i);
925 SDL_Log("Values = { %d, %d, %d, %d, %d }\n",
926 absinfo.value, absinfo.minimum, absinfo.maximum,
927 absinfo.fuzz, absinfo.flat);
928 #endif /* DEBUG_INPUT_EVENTS */
929 joystick->hwdata->abs_map[i] = joystick->naxes;
930 joystick->hwdata->has_abs[i] = SDL_TRUE;
931
932 correct->minimum = absinfo.minimum;
933 correct->maximum = absinfo.maximum;
934 if (correct->minimum != correct->maximum) {
935 if (use_deadzones) {
936 correct->use_deadzones = SDL_TRUE;
937 correct->coef[0] = (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
938 correct->coef[1] = (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
939 t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
940 if (t != 0) {
941 correct->coef[2] = (1 << 28) / t;
942 } else {
943 correct->coef[2] = 0;
944 }
945 } else {
946 float value_range = (correct->maximum - correct->minimum);
947 float output_range = (SDL_JOYSTICK_AXIS_MAX - SDL_JOYSTICK_AXIS_MIN);
948
949 correct->scale = (output_range / value_range);
950 }
951 }
952 ++joystick->naxes;
953 }
954 }
955 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
956 if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
957 struct input_absinfo absinfo;
958 int hat_index = (i - ABS_HAT0X) / 2;
959
960 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
961 continue;
962 }
963 #ifdef DEBUG_INPUT_EVENTS
964 SDL_Log("Joystick has hat %d\n", hat_index);
965 SDL_Log("Values = { %d, %d, %d, %d, %d }\n",
966 absinfo.value, absinfo.minimum, absinfo.maximum,
967 absinfo.fuzz, absinfo.flat);
968 #endif /* DEBUG_INPUT_EVENTS */
969 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
970 joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
971 }
972 }
973 if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
974 ++joystick->nballs;
975 }
976
977 } else if ((ioctl(fd, JSIOCGBUTTONS, &key_pam_size, sizeof(key_pam_size)) >= 0) &&
978 (ioctl(fd, JSIOCGAXES, &abs_pam_size, sizeof(abs_pam_size)) >= 0)) {
979 size_t len;
980
981 joystick->hwdata->classic = SDL_TRUE;
982
983 len = (KEY_MAX - BTN_MISC + 1) * sizeof(*joystick->hwdata->key_pam);
984 joystick->hwdata->key_pam = (Uint16 *)SDL_calloc(1, len);
985 if (joystick->hwdata->key_pam) {
986 if (ioctl(fd, JSIOCGBTNMAP, joystick->hwdata->key_pam, len) < 0) {
987 SDL_free(joystick->hwdata->key_pam);
988 joystick->hwdata->key_pam = NULL;
989 key_pam_size = 0;
990 }
991 } else {
992 key_pam_size = 0;
993 }
994 for (i = 0; i < key_pam_size; ++i) {
995 Uint16 code = joystick->hwdata->key_pam[i];
996 #ifdef DEBUG_INPUT_EVENTS
997 SDL_Log("Joystick has button: 0x%x\n", code);
998 #endif
999 joystick->hwdata->key_map[code] = joystick->nbuttons;
1000 joystick->hwdata->has_key[code] = SDL_TRUE;
1001 ++joystick->nbuttons;
1002 }
1003
1004 len = ABS_CNT * sizeof(*joystick->hwdata->abs_pam);
1005 joystick->hwdata->abs_pam = (Uint8 *)SDL_calloc(1, len);
1006 if (joystick->hwdata->abs_pam) {
1007 if (ioctl(fd, JSIOCGAXMAP, joystick->hwdata->abs_pam, len) < 0) {
1008 SDL_free(joystick->hwdata->abs_pam);
1009 joystick->hwdata->abs_pam = NULL;
1010 abs_pam_size = 0;
1011 }
1012 } else {
1013 abs_pam_size = 0;
1014 }
1015 for (i = 0; i < abs_pam_size; ++i) {
1016 Uint8 code = joystick->hwdata->abs_pam[i];
1017
1018 if (code >= ABS_HAT0X && code <= ABS_HAT3Y) {
1019 int hat_index = (code - ABS_HAT0X) / 2;
1020 if (!joystick->hwdata->has_hat[hat_index]) {
1021 #ifdef DEBUG_INPUT_EVENTS
1022 SDL_Log("Joystick has hat %d\n", hat_index);
1023 #endif
1024 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
1025 joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
1026 }
1027 } else {
1028 #ifdef DEBUG_INPUT_EVENTS
1029 SDL_Log("Joystick has absolute axis: 0x%.2x\n", code);
1030 #endif
1031 joystick->hwdata->abs_map[code] = joystick->naxes;
1032 joystick->hwdata->has_abs[code] = SDL_TRUE;
1033 ++joystick->naxes;
1034 }
1035 }
1036 }
1037
1038 /* Allocate data to keep track of these thingamajigs */
1039 if (joystick->nhats > 0) {
1040 if (allocate_hatdata(joystick) < 0) {
1041 joystick->nhats = 0;
1042 }
1043 }
1044 if (joystick->nballs > 0) {
1045 if (allocate_balldata(joystick) < 0) {
1046 joystick->nballs = 0;
1047 }
1048 }
1049
1050 if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
1051 if (test_bit(FF_RUMBLE, ffbit)) {
1052 joystick->hwdata->ff_rumble = SDL_TRUE;
1053 }
1054 if (test_bit(FF_SINE, ffbit)) {
1055 joystick->hwdata->ff_sine = SDL_TRUE;
1056 }
1057 }
1058 }
1059
1060
1061 /* This is used to do the heavy lifting for LINUX_JoystickOpen and
1062 also LINUX_JoystickGetGamepadMapping, so we can query the hardware
1063 without adding an opened SDL_Joystick object to the system.
1064 This expects `joystick->hwdata` to be allocated and will not free it
1065 on error. Returns -1 on error, 0 on success. */
1066 static int
PrepareJoystickHwdata(SDL_Joystick * joystick,SDL_joylist_item * item)1067 PrepareJoystickHwdata(SDL_Joystick *joystick, SDL_joylist_item *item)
1068 {
1069 joystick->hwdata->item = item;
1070 joystick->hwdata->guid = item->guid;
1071 joystick->hwdata->effect.id = -1;
1072 joystick->hwdata->m_bSteamController = item->m_bSteamController;
1073 SDL_memset(joystick->hwdata->key_map, 0xFF, sizeof(joystick->hwdata->key_map));
1074 SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
1075
1076 if (item->m_bSteamController) {
1077 joystick->hwdata->fd = -1;
1078 SDL_GetSteamControllerInputs(&joystick->nbuttons,
1079 &joystick->naxes,
1080 &joystick->nhats);
1081 } else {
1082 /* Try read-write first, so we can do rumble */
1083 int fd = open(item->path, O_RDWR | O_CLOEXEC, 0);
1084 if (fd < 0) {
1085 /* Try read-only again, at least we'll get events in this case */
1086 fd = open(item->path, O_RDONLY | O_CLOEXEC, 0);
1087 }
1088 if (fd < 0) {
1089 return SDL_SetError("Unable to open %s", item->path);
1090 }
1091
1092 joystick->hwdata->fd = fd;
1093 joystick->hwdata->fname = SDL_strdup(item->path);
1094 if (joystick->hwdata->fname == NULL) {
1095 close(fd);
1096 return SDL_OutOfMemory();
1097 }
1098
1099 /* Set the joystick to non-blocking read mode */
1100 fcntl(fd, F_SETFL, O_NONBLOCK);
1101
1102 /* Get the number of buttons and axes on the joystick */
1103 ConfigJoystick(joystick, fd);
1104 }
1105 return 0;
1106 }
1107
1108
1109 /* Function to open a joystick for use.
1110 The joystick to open is specified by the device index.
1111 This should fill the nbuttons and naxes fields of the joystick structure.
1112 It returns 0, or -1 if there is an error.
1113 */
1114 static int
LINUX_JoystickOpen(SDL_Joystick * joystick,int device_index)1115 LINUX_JoystickOpen(SDL_Joystick *joystick, int device_index)
1116 {
1117 SDL_joylist_item *item = JoystickByDevIndex(device_index);
1118
1119 if (item == NULL) {
1120 return SDL_SetError("No such device");
1121 }
1122
1123 joystick->instance_id = item->device_instance;
1124 joystick->hwdata = (struct joystick_hwdata *)
1125 SDL_calloc(1, sizeof(*joystick->hwdata));
1126 if (joystick->hwdata == NULL) {
1127 return SDL_OutOfMemory();
1128 }
1129
1130 if (PrepareJoystickHwdata(joystick, item) == -1) {
1131 SDL_free(joystick->hwdata);
1132 joystick->hwdata = NULL;
1133 return -1; /* SDL_SetError will already have been called */
1134 }
1135
1136 SDL_assert(item->hwdata == NULL);
1137 item->hwdata = joystick->hwdata;
1138
1139 /* mark joystick as fresh and ready */
1140 joystick->hwdata->fresh = SDL_TRUE;
1141
1142 return 0;
1143 }
1144
1145 static int
LINUX_JoystickRumble(SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)1146 LINUX_JoystickRumble(SDL_Joystick *joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
1147 {
1148 struct input_event event;
1149
1150 if (joystick->hwdata->ff_rumble) {
1151 struct ff_effect *effect = &joystick->hwdata->effect;
1152
1153 effect->type = FF_RUMBLE;
1154 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1155 effect->u.rumble.strong_magnitude = low_frequency_rumble;
1156 effect->u.rumble.weak_magnitude = high_frequency_rumble;
1157 } else if (joystick->hwdata->ff_sine) {
1158 /* Scale and average the two rumble strengths */
1159 Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
1160 struct ff_effect *effect = &joystick->hwdata->effect;
1161
1162 effect->type = FF_PERIODIC;
1163 effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
1164 effect->u.periodic.waveform = FF_SINE;
1165 effect->u.periodic.magnitude = magnitude;
1166 } else {
1167 return SDL_Unsupported();
1168 }
1169
1170 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1171 /* The kernel may have lost this effect, try to allocate a new one */
1172 joystick->hwdata->effect.id = -1;
1173 if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
1174 return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
1175 }
1176 }
1177
1178 event.type = EV_FF;
1179 event.code = joystick->hwdata->effect.id;
1180 event.value = 1;
1181 if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
1182 return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
1183 }
1184 return 0;
1185 }
1186
1187 static int
LINUX_JoystickRumbleTriggers(SDL_Joystick * joystick,Uint16 left_rumble,Uint16 right_rumble)1188 LINUX_JoystickRumbleTriggers(SDL_Joystick *joystick, Uint16 left_rumble, Uint16 right_rumble)
1189 {
1190 return SDL_Unsupported();
1191 }
1192
1193 static Uint32
LINUX_JoystickGetCapabilities(SDL_Joystick * joystick)1194 LINUX_JoystickGetCapabilities(SDL_Joystick *joystick)
1195 {
1196 Uint32 result = 0;
1197
1198 if (joystick->hwdata->ff_rumble || joystick->hwdata->ff_sine) {
1199 result |= SDL_JOYCAP_RUMBLE;
1200 }
1201
1202 return result;
1203 }
1204
1205 static int
LINUX_JoystickSetLED(SDL_Joystick * joystick,Uint8 red,Uint8 green,Uint8 blue)1206 LINUX_JoystickSetLED(SDL_Joystick *joystick, Uint8 red, Uint8 green, Uint8 blue)
1207 {
1208 return SDL_Unsupported();
1209 }
1210
1211 static int
LINUX_JoystickSendEffect(SDL_Joystick * joystick,const void * data,int size)1212 LINUX_JoystickSendEffect(SDL_Joystick *joystick, const void *data, int size)
1213 {
1214 return SDL_Unsupported();
1215 }
1216
1217 static int
LINUX_JoystickSetSensorsEnabled(SDL_Joystick * joystick,SDL_bool enabled)1218 LINUX_JoystickSetSensorsEnabled(SDL_Joystick *joystick, SDL_bool enabled)
1219 {
1220 return SDL_Unsupported();
1221 }
1222
1223 static void
HandleHat(SDL_Joystick * stick,Uint8 hat,int axis,int value)1224 HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
1225 {
1226 struct hwdata_hat *the_hat;
1227 const Uint8 position_map[3][3] = {
1228 {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
1229 {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
1230 {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
1231 };
1232
1233 the_hat = &stick->hwdata->hats[hat];
1234 if (value < 0) {
1235 value = 0;
1236 } else if (value == 0) {
1237 value = 1;
1238 } else if (value > 0) {
1239 value = 2;
1240 }
1241 if (value != the_hat->axis[axis]) {
1242 the_hat->axis[axis] = value;
1243 SDL_PrivateJoystickHat(stick, hat,
1244 position_map[the_hat->axis[1]][the_hat->axis[0]]);
1245 }
1246 }
1247
1248 static void
HandleBall(SDL_Joystick * stick,Uint8 ball,int axis,int value)1249 HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
1250 {
1251 stick->hwdata->balls[ball].axis[axis] += value;
1252 }
1253
1254
1255 static int
AxisCorrect(SDL_Joystick * joystick,int which,int value)1256 AxisCorrect(SDL_Joystick *joystick, int which, int value)
1257 {
1258 struct axis_correct *correct;
1259
1260 correct = &joystick->hwdata->abs_correct[which];
1261 if (correct->minimum != correct->maximum) {
1262 if (correct->use_deadzones) {
1263 value *= 2;
1264 if (value > correct->coef[0]) {
1265 if (value < correct->coef[1]) {
1266 return 0;
1267 }
1268 value -= correct->coef[1];
1269 } else {
1270 value -= correct->coef[0];
1271 }
1272 value *= correct->coef[2];
1273 value >>= 13;
1274 } else {
1275 value = (int)SDL_floorf((value - correct->minimum) * correct->scale + SDL_JOYSTICK_AXIS_MIN + 0.5f);
1276 }
1277 }
1278
1279 /* Clamp and return */
1280 if (value < SDL_JOYSTICK_AXIS_MIN) {
1281 return SDL_JOYSTICK_AXIS_MIN;
1282 }
1283 if (value > SDL_JOYSTICK_AXIS_MAX) {
1284 return SDL_JOYSTICK_AXIS_MAX;
1285 }
1286 return value;
1287 }
1288
1289 static void
PollAllValues(SDL_Joystick * joystick)1290 PollAllValues(SDL_Joystick *joystick)
1291 {
1292 struct input_absinfo absinfo;
1293 unsigned long keyinfo[NBITS(KEY_MAX)];
1294 int i;
1295
1296 /* Poll all axis */
1297 for (i = ABS_X; i < ABS_MAX; i++) {
1298 if (i == ABS_HAT0X) { /* we handle hats in the next loop, skip them for now. */
1299 i = ABS_HAT3Y;
1300 continue;
1301 }
1302 if (joystick->hwdata->has_abs[i]) {
1303 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1304 absinfo.value = AxisCorrect(joystick, i, absinfo.value);
1305
1306 #ifdef DEBUG_INPUT_EVENTS
1307 SDL_Log("Joystick : Re-read Axis %d (%d) val= %d\n",
1308 joystick->hwdata->abs_map[i], i, absinfo.value);
1309 #endif
1310 SDL_PrivateJoystickAxis(joystick,
1311 joystick->hwdata->abs_map[i],
1312 absinfo.value);
1313 }
1314 }
1315 }
1316
1317 /* Poll all hats */
1318 for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) {
1319 const int baseaxis = i - ABS_HAT0X;
1320 const int hatidx = baseaxis / 2;
1321 SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat));
1322 if (joystick->hwdata->has_hat[hatidx]) {
1323 if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
1324 const int hataxis = baseaxis % 2;
1325 HandleHat(joystick, joystick->hwdata->hats_indices[hatidx], hataxis, absinfo.value);
1326 }
1327 }
1328 }
1329
1330 /* Poll all buttons */
1331 SDL_zeroa(keyinfo);
1332 if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof (keyinfo)), keyinfo) >= 0) {
1333 for (i = 0; i < KEY_MAX; i++) {
1334 if (joystick->hwdata->has_key[i]) {
1335 const Uint8 value = test_bit(i, keyinfo) ? SDL_PRESSED : SDL_RELEASED;
1336 #ifdef DEBUG_INPUT_EVENTS
1337 SDL_Log("Joystick : Re-read Button %d (%d) val= %d\n",
1338 joystick->hwdata->key_map[i], i, value);
1339 #endif
1340 SDL_PrivateJoystickButton(joystick,
1341 joystick->hwdata->key_map[i], value);
1342 }
1343 }
1344 }
1345
1346 /* Joyballs are relative input, so there's no poll state. Events only! */
1347 }
1348
1349 static void
HandleInputEvents(SDL_Joystick * joystick)1350 HandleInputEvents(SDL_Joystick *joystick)
1351 {
1352 struct input_event events[32];
1353 int i, len, code;
1354
1355 if (joystick->hwdata->fresh) {
1356 PollAllValues(joystick);
1357 joystick->hwdata->fresh = SDL_FALSE;
1358 }
1359
1360 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1361 len /= sizeof(events[0]);
1362 for (i = 0; i < len; ++i) {
1363 code = events[i].code;
1364
1365 /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
1366 rest of the packet (the end of it signified by a SYN_REPORT) */
1367 if ( joystick->hwdata->recovering_from_dropped &&
1368 ((events[i].type != EV_SYN) || (code != SYN_REPORT)) ) {
1369 continue;
1370 }
1371
1372 switch (events[i].type) {
1373 case EV_KEY:
1374 SDL_PrivateJoystickButton(joystick,
1375 joystick->hwdata->key_map[code],
1376 events[i].value);
1377 break;
1378 case EV_ABS:
1379 switch (code) {
1380 case ABS_HAT0X:
1381 case ABS_HAT0Y:
1382 case ABS_HAT1X:
1383 case ABS_HAT1Y:
1384 case ABS_HAT2X:
1385 case ABS_HAT2Y:
1386 case ABS_HAT3X:
1387 case ABS_HAT3Y:
1388 code -= ABS_HAT0X;
1389 HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1390 break;
1391 default:
1392 events[i].value = AxisCorrect(joystick, code, events[i].value);
1393 SDL_PrivateJoystickAxis(joystick,
1394 joystick->hwdata->abs_map[code],
1395 events[i].value);
1396 break;
1397 }
1398 break;
1399 case EV_REL:
1400 switch (code) {
1401 case REL_X:
1402 case REL_Y:
1403 code -= REL_X;
1404 HandleBall(joystick, code / 2, code % 2, events[i].value);
1405 break;
1406 default:
1407 break;
1408 }
1409 break;
1410 case EV_SYN:
1411 switch (code) {
1412 case SYN_DROPPED :
1413 #ifdef DEBUG_INPUT_EVENTS
1414 SDL_Log("Event SYN_DROPPED detected\n");
1415 #endif
1416 joystick->hwdata->recovering_from_dropped = SDL_TRUE;
1417 break;
1418 case SYN_REPORT :
1419 if (joystick->hwdata->recovering_from_dropped) {
1420 joystick->hwdata->recovering_from_dropped = SDL_FALSE;
1421 PollAllValues(joystick); /* try to sync up to current state now */
1422 }
1423 break;
1424 default:
1425 break;
1426 }
1427 default:
1428 break;
1429 }
1430 }
1431 }
1432
1433 if (errno == ENODEV) {
1434 /* We have to wait until the JoystickDetect callback to remove this */
1435 joystick->hwdata->gone = SDL_TRUE;
1436 }
1437 }
1438
1439 static void
HandleClassicEvents(SDL_Joystick * joystick)1440 HandleClassicEvents(SDL_Joystick *joystick)
1441 {
1442 struct js_event events[32];
1443 int i, len, code;
1444
1445 joystick->hwdata->fresh = SDL_FALSE;
1446 while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1447 len /= sizeof(events[0]);
1448 for (i = 0; i < len; ++i) {
1449 switch (events[i].type) {
1450 case JS_EVENT_BUTTON:
1451 code = joystick->hwdata->key_pam[events[i].number];
1452 SDL_PrivateJoystickButton(joystick,
1453 joystick->hwdata->key_map[code],
1454 events[i].value);
1455 break;
1456 case JS_EVENT_AXIS:
1457 code = joystick->hwdata->abs_pam[events[i].number];
1458 switch (code) {
1459 case ABS_HAT0X:
1460 case ABS_HAT0Y:
1461 case ABS_HAT1X:
1462 case ABS_HAT1Y:
1463 case ABS_HAT2X:
1464 case ABS_HAT2Y:
1465 case ABS_HAT3X:
1466 case ABS_HAT3Y:
1467 code -= ABS_HAT0X;
1468 HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1469 break;
1470 default:
1471 SDL_PrivateJoystickAxis(joystick,
1472 joystick->hwdata->abs_map[code],
1473 events[i].value);
1474 break;
1475 }
1476 }
1477 }
1478 }
1479 }
1480
1481 static void
LINUX_JoystickUpdate(SDL_Joystick * joystick)1482 LINUX_JoystickUpdate(SDL_Joystick *joystick)
1483 {
1484 int i;
1485
1486 if (joystick->hwdata->m_bSteamController) {
1487 SDL_UpdateSteamController(joystick);
1488 return;
1489 }
1490
1491 if (joystick->hwdata->classic) {
1492 HandleClassicEvents(joystick);
1493 } else {
1494 HandleInputEvents(joystick);
1495 }
1496
1497 /* Deliver ball motion updates */
1498 for (i = 0; i < joystick->nballs; ++i) {
1499 int xrel, yrel;
1500
1501 xrel = joystick->hwdata->balls[i].axis[0];
1502 yrel = joystick->hwdata->balls[i].axis[1];
1503 if (xrel || yrel) {
1504 joystick->hwdata->balls[i].axis[0] = 0;
1505 joystick->hwdata->balls[i].axis[1] = 0;
1506 SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1507 }
1508 }
1509 }
1510
1511 /* Function to close a joystick after use */
1512 static void
LINUX_JoystickClose(SDL_Joystick * joystick)1513 LINUX_JoystickClose(SDL_Joystick *joystick)
1514 {
1515 if (joystick->hwdata) {
1516 if (joystick->hwdata->effect.id >= 0) {
1517 ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1518 joystick->hwdata->effect.id = -1;
1519 }
1520 if (joystick->hwdata->fd >= 0) {
1521 close(joystick->hwdata->fd);
1522 }
1523 if (joystick->hwdata->item) {
1524 joystick->hwdata->item->hwdata = NULL;
1525 }
1526 SDL_free(joystick->hwdata->key_pam);
1527 SDL_free(joystick->hwdata->abs_pam);
1528 SDL_free(joystick->hwdata->hats);
1529 SDL_free(joystick->hwdata->balls);
1530 SDL_free(joystick->hwdata->fname);
1531 SDL_free(joystick->hwdata);
1532 }
1533 }
1534
1535 /* Function to perform any system-specific joystick related cleanup */
1536 static void
LINUX_JoystickQuit(void)1537 LINUX_JoystickQuit(void)
1538 {
1539 SDL_joylist_item *item = NULL;
1540 SDL_joylist_item *next = NULL;
1541
1542 if (inotify_fd >= 0) {
1543 close(inotify_fd);
1544 inotify_fd = -1;
1545 }
1546
1547 for (item = SDL_joylist; item; item = next) {
1548 next = item->next;
1549 FreeJoylistItem(item);
1550 }
1551
1552 SDL_joylist = SDL_joylist_tail = NULL;
1553
1554 numjoysticks = 0;
1555
1556 #if SDL_USE_LIBUDEV
1557 if (enumeration_method == ENUMERATION_LIBUDEV) {
1558 SDL_UDEV_DelCallback(joystick_udev_callback);
1559 SDL_UDEV_Quit();
1560 }
1561 #endif
1562
1563 SDL_QuitSteamControllers();
1564 }
1565
1566 /*
1567 This is based on the Linux Gamepad Specification
1568 available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
1569 */
1570 static SDL_bool
LINUX_JoystickGetGamepadMapping(int device_index,SDL_GamepadMapping * out)1571 LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1572 {
1573 SDL_Joystick *joystick;
1574 SDL_joylist_item *item = JoystickByDevIndex(device_index);
1575
1576 if (item->mapping) {
1577 SDL_memcpy(out, item->mapping, sizeof(*out));
1578 return SDL_TRUE;
1579 }
1580
1581 /* We temporarily open the device to check how it's configured. Make
1582 a fake SDL_Joystick object to do so. */
1583 joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
1584 if (joystick == NULL) {
1585 SDL_OutOfMemory();
1586 return SDL_FALSE;
1587 }
1588 SDL_memcpy(&joystick->guid, &item->guid, sizeof(item->guid));
1589
1590 joystick->hwdata = (struct joystick_hwdata *)
1591 SDL_calloc(1, sizeof(*joystick->hwdata));
1592 if (joystick->hwdata == NULL) {
1593 SDL_free(joystick);
1594 SDL_OutOfMemory();
1595 return SDL_FALSE;
1596 }
1597
1598 if (PrepareJoystickHwdata(joystick, item) == -1) {
1599 SDL_free(joystick->hwdata);
1600 SDL_free(joystick);
1601 return SDL_FALSE; /* SDL_SetError will already have been called */
1602 }
1603
1604 /* don't assign `item->hwdata` so it's not in any global state. */
1605
1606 /* it is now safe to call LINUX_JoystickClose on this fake joystick. */
1607
1608 if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
1609 /* Not a gamepad according to the specs. */
1610 LINUX_JoystickClose(joystick);
1611 SDL_free(joystick);
1612 return SDL_FALSE;
1613 }
1614
1615 /* We have a gamepad, start filling out the mappings */
1616
1617 if (joystick->hwdata->has_key[BTN_A]) {
1618 out->a.kind = EMappingKind_Button;
1619 out->a.target = joystick->hwdata->key_map[BTN_A];
1620 }
1621
1622 if (joystick->hwdata->has_key[BTN_B]) {
1623 out->b.kind = EMappingKind_Button;
1624 out->b.target = joystick->hwdata->key_map[BTN_B];
1625 }
1626
1627 /* Xbox controllers use BTN_X and BTN_Y, and PS4 controllers use BTN_WEST and BTN_NORTH */
1628 if (SDL_JoystickGetVendor(joystick) == USB_VENDOR_SONY) {
1629 if (joystick->hwdata->has_key[BTN_WEST]) {
1630 out->x.kind = EMappingKind_Button;
1631 out->x.target = joystick->hwdata->key_map[BTN_WEST];
1632 }
1633
1634 if (joystick->hwdata->has_key[BTN_NORTH]) {
1635 out->y.kind = EMappingKind_Button;
1636 out->y.target = joystick->hwdata->key_map[BTN_NORTH];
1637 }
1638 } else {
1639 if (joystick->hwdata->has_key[BTN_X]) {
1640 out->x.kind = EMappingKind_Button;
1641 out->x.target = joystick->hwdata->key_map[BTN_X];
1642 }
1643
1644 if (joystick->hwdata->has_key[BTN_Y]) {
1645 out->y.kind = EMappingKind_Button;
1646 out->y.target = joystick->hwdata->key_map[BTN_Y];
1647 }
1648 }
1649
1650 if (joystick->hwdata->has_key[BTN_SELECT]) {
1651 out->back.kind = EMappingKind_Button;
1652 out->back.target = joystick->hwdata->key_map[BTN_SELECT];
1653 }
1654
1655 if (joystick->hwdata->has_key[BTN_START]) {
1656 out->start.kind = EMappingKind_Button;
1657 out->start.target = joystick->hwdata->key_map[BTN_START];
1658 }
1659
1660 if (joystick->hwdata->has_key[BTN_THUMBL]) {
1661 out->leftstick.kind = EMappingKind_Button;
1662 out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL];
1663 }
1664
1665 if (joystick->hwdata->has_key[BTN_THUMBR]) {
1666 out->rightstick.kind = EMappingKind_Button;
1667 out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR];
1668 }
1669
1670 if (joystick->hwdata->has_key[BTN_MODE]) {
1671 out->guide.kind = EMappingKind_Button;
1672 out->guide.target = joystick->hwdata->key_map[BTN_MODE];
1673 }
1674
1675 /*
1676 According to the specs the D-Pad, the shoulder buttons and the triggers
1677 can be digital, or analog, or both at the same time.
1678 */
1679
1680 /* Prefer digital shoulder buttons, but settle for analog if missing. */
1681 if (joystick->hwdata->has_key[BTN_TL]) {
1682 out->leftshoulder.kind = EMappingKind_Button;
1683 out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL];
1684 }
1685
1686 if (joystick->hwdata->has_key[BTN_TR]) {
1687 out->rightshoulder.kind = EMappingKind_Button;
1688 out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR];
1689 }
1690
1691 if (joystick->hwdata->has_hat[1] && /* Check if ABS_HAT1{X, Y} is available. */
1692 (!joystick->hwdata->has_key[BTN_TL] || !joystick->hwdata->has_key[BTN_TR])) {
1693 int hat = joystick->hwdata->hats_indices[1] << 4;
1694 out->leftshoulder.kind = EMappingKind_Hat;
1695 out->rightshoulder.kind = EMappingKind_Hat;
1696 out->leftshoulder.target = hat | 0x4;
1697 out->rightshoulder.target = hat | 0x2;
1698 }
1699
1700 /* Prefer analog triggers, but settle for digital if missing. */
1701 if (joystick->hwdata->has_hat[2]) { /* Check if ABS_HAT2{X,Y} is available. */
1702 int hat = joystick->hwdata->hats_indices[2] << 4;
1703 out->lefttrigger.kind = EMappingKind_Hat;
1704 out->righttrigger.kind = EMappingKind_Hat;
1705 out->lefttrigger.target = hat | 0x4;
1706 out->righttrigger.target = hat | 0x2;
1707 } else {
1708 if (joystick->hwdata->has_abs[ABS_Z]) {
1709 out->lefttrigger.kind = EMappingKind_Axis;
1710 out->lefttrigger.target = joystick->hwdata->abs_map[ABS_Z];
1711 } else if (joystick->hwdata->has_key[BTN_TL2]) {
1712 out->lefttrigger.kind = EMappingKind_Button;
1713 out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2];
1714 }
1715
1716 if (joystick->hwdata->has_abs[ABS_RZ]) {
1717 out->righttrigger.kind = EMappingKind_Axis;
1718 out->righttrigger.target = joystick->hwdata->abs_map[ABS_RZ];
1719 } else if (joystick->hwdata->has_key[BTN_TR2]) {
1720 out->righttrigger.kind = EMappingKind_Button;
1721 out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
1722 }
1723 }
1724
1725 /* Prefer digital D-Pad, but settle for analog if missing. */
1726 if (joystick->hwdata->has_key[BTN_DPAD_UP]) {
1727 out->dpup.kind = EMappingKind_Button;
1728 out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP];
1729 }
1730
1731 if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) {
1732 out->dpdown.kind = EMappingKind_Button;
1733 out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN];
1734 }
1735
1736 if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) {
1737 out->dpleft.kind = EMappingKind_Button;
1738 out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT];
1739 }
1740
1741 if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) {
1742 out->dpright.kind = EMappingKind_Button;
1743 out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT];
1744 }
1745
1746 if (joystick->hwdata->has_hat[0] && /* Check if ABS_HAT0{X,Y} is available. */
1747 (!joystick->hwdata->has_key[BTN_DPAD_LEFT] || !joystick->hwdata->has_key[BTN_DPAD_RIGHT] ||
1748 !joystick->hwdata->has_key[BTN_DPAD_UP] || !joystick->hwdata->has_key[BTN_DPAD_DOWN])) {
1749 int hat = joystick->hwdata->hats_indices[0] << 4;
1750 out->dpleft.kind = EMappingKind_Hat;
1751 out->dpright.kind = EMappingKind_Hat;
1752 out->dpup.kind = EMappingKind_Hat;
1753 out->dpdown.kind = EMappingKind_Hat;
1754 out->dpleft.target = hat | 0x8;
1755 out->dpright.target = hat | 0x2;
1756 out->dpup.target = hat | 0x1;
1757 out->dpdown.target = hat | 0x4;
1758 }
1759
1760 if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) {
1761 out->leftx.kind = EMappingKind_Axis;
1762 out->lefty.kind = EMappingKind_Axis;
1763 out->leftx.target = joystick->hwdata->abs_map[ABS_X];
1764 out->lefty.target = joystick->hwdata->abs_map[ABS_Y];
1765 }
1766
1767 if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
1768 out->rightx.kind = EMappingKind_Axis;
1769 out->righty.kind = EMappingKind_Axis;
1770 out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
1771 out->righty.target = joystick->hwdata->abs_map[ABS_RY];
1772 }
1773
1774 LINUX_JoystickClose(joystick);
1775 SDL_free(joystick);
1776
1777 /* Cache the mapping for later */
1778 item->mapping = (SDL_GamepadMapping *)SDL_malloc(sizeof(*item->mapping));
1779 if (item->mapping) {
1780 SDL_memcpy(item->mapping, out, sizeof(*out));
1781 }
1782
1783 return SDL_TRUE;
1784 }
1785
1786 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
1787 {
1788 LINUX_JoystickInit,
1789 LINUX_JoystickGetCount,
1790 LINUX_JoystickDetect,
1791 LINUX_JoystickGetDeviceName,
1792 LINUX_JoystickGetDevicePlayerIndex,
1793 LINUX_JoystickSetDevicePlayerIndex,
1794 LINUX_JoystickGetDeviceGUID,
1795 LINUX_JoystickGetDeviceInstanceID,
1796 LINUX_JoystickOpen,
1797 LINUX_JoystickRumble,
1798 LINUX_JoystickRumbleTriggers,
1799 LINUX_JoystickGetCapabilities,
1800 LINUX_JoystickSetLED,
1801 LINUX_JoystickSendEffect,
1802 LINUX_JoystickSetSensorsEnabled,
1803 LINUX_JoystickUpdate,
1804 LINUX_JoystickClose,
1805 LINUX_JoystickQuit,
1806 LINUX_JoystickGetGamepadMapping
1807 };
1808
1809 #endif /* SDL_JOYSTICK_LINUX */
1810
1811 /* vi: set ts=4 sw=4 expandtab: */
1812