1 /*
2   Simple DirectMedia Layer
3   Copyright (C) 1997-2020 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 #include <sys/ioctl.h>
36 #include <unistd.h>
37 #include <dirent.h>
38 #include <linux/joystick.h>
39 
40 #include "SDL_assert.h"
41 #include "SDL_joystick.h"
42 #include "SDL_endian.h"
43 #include "SDL_timer.h"
44 #include "../../events/SDL_events_c.h"
45 #include "../SDL_sysjoystick.h"
46 #include "../SDL_joystick_c.h"
47 #include "../steam/SDL_steamcontroller.h"
48 #include "SDL_sysjoystick_c.h"
49 #include "../hidapi/SDL_hidapijoystick_c.h"
50 
51 /* This isn't defined in older Linux kernel headers */
52 #ifndef SYN_DROPPED
53 #define SYN_DROPPED 3
54 #endif
55 #ifndef BTN_SOUTH
56 #define BTN_SOUTH       0x130
57 #endif
58 #ifndef BTN_EAST
59 #define BTN_EAST        0x131
60 #endif
61 #ifndef BTN_NORTH
62 #define BTN_NORTH       0x133
63 #endif
64 #ifndef BTN_WEST
65 #define BTN_WEST        0x134
66 #endif
67 #ifndef BTN_DPAD_UP
68 #define BTN_DPAD_UP     0x220
69 #endif
70 #ifndef BTN_DPAD_DOWN
71 #define BTN_DPAD_DOWN   0x221
72 #endif
73 #ifndef BTN_DPAD_LEFT
74 #define BTN_DPAD_LEFT   0x222
75 #endif
76 #ifndef BTN_DPAD_RIGHT
77 #define BTN_DPAD_RIGHT  0x223
78 #endif
79 
80 #include "../../core/linux/SDL_udev.h"
81 
82 #if 0
83 #define DEBUG_INPUT_EVENTS 1
84 #endif
85 
86 static int MaybeAddDevice(const char *path);
87 #if SDL_USE_LIBUDEV
88 static int MaybeRemoveDevice(const char *path);
89 #endif /* SDL_USE_LIBUDEV */
90 
91 /* A linked list of available joysticks */
92 typedef struct SDL_joylist_item
93 {
94     int device_instance;
95     char *path;   /* "/dev/input/event2" or whatever */
96     char *name;   /* "SideWinder 3D Pro" or whatever */
97     SDL_JoystickGUID guid;
98     dev_t devnum;
99     struct joystick_hwdata *hwdata;
100     struct SDL_joylist_item *next;
101 
102     /* Steam Controller support */
103     SDL_bool m_bSteamController;
104 } SDL_joylist_item;
105 
106 static SDL_joylist_item *SDL_joylist = NULL;
107 static SDL_joylist_item *SDL_joylist_tail = NULL;
108 static int numjoysticks = 0;
109 
110 #if !SDL_USE_LIBUDEV
111 static Uint32 last_joy_detect_time;
112 static time_t last_input_dir_mtime;
113 #endif
114 
115 #define test_bit(nr, addr) \
116     (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
117 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
118 
119 static void
FixupDeviceInfoForMapping(int fd,struct input_id * inpid)120 FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
121 {
122     if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
123         /* This is a Microsoft Xbox One Elite Series 2 controller */
124         unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
125 
126         /* The first version of the firmware duplicated all the inputs */
127         if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
128             test_bit(0x2c0, keybit)) {
129             /* Change the version to 0x0902, so we can map it differently */
130             inpid->version = 0x0902;
131         }
132     }
133 }
134 
135 #ifdef SDL_JOYSTICK_HIDAPI
136 static SDL_bool
IsVirtualJoystick(Uint16 vendor,Uint16 product,Uint16 version,const char * name)137 IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
138 {
139     if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 &&
140         SDL_strcmp(name, "Xbox One S Controller") == 0) {
141         /* This is the virtual device created by the xow driver */
142         return SDL_TRUE;
143     }
144     return SDL_FALSE;
145 }
146 #endif /* SDL_JOYSTICK_HIDAPI */
147 
148 static int
IsJoystick(int fd,char ** name_return,SDL_JoystickGUID * guid)149 IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
150 {
151     struct input_id inpid;
152     Uint16 *guid16 = (Uint16 *)guid->data;
153     char *name;
154     char product_string[128];
155 
156 #if !SDL_USE_LIBUDEV
157     /* When udev is enabled we only get joystick devices here, so there's no need to test them */
158     unsigned long evbit[NBITS(EV_MAX)] = { 0 };
159     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
160     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
161 
162     if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
163         (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
164         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
165         return (0);
166     }
167 
168     if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
169           test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
170         return 0;
171     }
172 #endif
173 
174     if (ioctl(fd, EVIOCGID, &inpid) < 0) {
175         return 0;
176     }
177 
178     if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
179         return 0;
180     }
181 
182     name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
183     if (!name) {
184         return 0;
185     }
186 
187 #ifdef SDL_JOYSTICK_HIDAPI
188     if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
189         HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, name)) {
190         /* The HIDAPI driver is taking care of this device */
191         SDL_free(name);
192         return 0;
193     }
194 #endif
195 
196     FixupDeviceInfoForMapping(fd, &inpid);
197 
198 #ifdef DEBUG_JOYSTICK
199     printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
200 #endif
201 
202     SDL_memset(guid->data, 0, sizeof(guid->data));
203 
204     /* We only need 16 bits for each of these; space them out to fill 128. */
205     /* Byteswap so devices get same GUID on little/big endian platforms. */
206     *guid16++ = SDL_SwapLE16(inpid.bustype);
207     *guid16++ = 0;
208 
209     if (inpid.vendor && inpid.product) {
210         *guid16++ = SDL_SwapLE16(inpid.vendor);
211         *guid16++ = 0;
212         *guid16++ = SDL_SwapLE16(inpid.product);
213         *guid16++ = 0;
214         *guid16++ = SDL_SwapLE16(inpid.version);
215         *guid16++ = 0;
216     } else {
217         SDL_strlcpy((char*)guid16, name, sizeof(guid->data) - 4);
218     }
219 
220     if (SDL_ShouldIgnoreJoystick(name, *guid)) {
221         SDL_free(name);
222         return 0;
223     }
224     *name_return = name;
225     return 1;
226 }
227 
228 #if SDL_USE_LIBUDEV
joystick_udev_callback(SDL_UDEV_deviceevent udev_type,int udev_class,const char * devpath)229 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
230 {
231     if (devpath == NULL) {
232         return;
233     }
234 
235     switch (udev_type) {
236         case SDL_UDEV_DEVICEADDED:
237             if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
238                 return;
239             }
240             MaybeAddDevice(devpath);
241             break;
242 
243         case SDL_UDEV_DEVICEREMOVED:
244             MaybeRemoveDevice(devpath);
245             break;
246 
247         default:
248             break;
249     }
250 
251 }
252 #endif /* SDL_USE_LIBUDEV */
253 
254 static int
MaybeAddDevice(const char * path)255 MaybeAddDevice(const char *path)
256 {
257     struct stat sb;
258     int fd = -1;
259     int isstick = 0;
260     char *name = NULL;
261     SDL_JoystickGUID guid;
262     SDL_joylist_item *item;
263 
264     if (path == NULL) {
265         return -1;
266     }
267 
268     if (stat(path, &sb) == -1) {
269         return -1;
270     }
271 
272     /* Check to make sure it's not already in list. */
273     for (item = SDL_joylist; item != NULL; item = item->next) {
274         if (sb.st_rdev == item->devnum) {
275             return -1;  /* already have this one */
276         }
277     }
278 
279     fd = open(path, O_RDONLY, 0);
280     if (fd < 0) {
281         return -1;
282     }
283 
284 #ifdef DEBUG_INPUT_EVENTS
285     printf("Checking %s\n", path);
286 #endif
287 
288     isstick = IsJoystick(fd, &name, &guid);
289     close(fd);
290     if (!isstick) {
291         return -1;
292     }
293 
294     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
295     if (item == NULL) {
296         return -1;
297     }
298 
299     SDL_zerop(item);
300     item->devnum = sb.st_rdev;
301     item->path = SDL_strdup(path);
302     item->name = name;
303     item->guid = guid;
304 
305     if ((item->path == NULL) || (item->name == NULL)) {
306          SDL_free(item->path);
307          SDL_free(item->name);
308          SDL_free(item);
309          return -1;
310     }
311 
312     item->device_instance = SDL_GetNextJoystickInstanceID();
313     if (SDL_joylist_tail == NULL) {
314         SDL_joylist = SDL_joylist_tail = item;
315     } else {
316         SDL_joylist_tail->next = item;
317         SDL_joylist_tail = item;
318     }
319 
320     /* Need to increment the joystick count before we post the event */
321     ++numjoysticks;
322 
323     SDL_PrivateJoystickAdded(item->device_instance);
324 
325     return numjoysticks;
326 }
327 
328 #if SDL_USE_LIBUDEV
329 static int
MaybeRemoveDevice(const char * path)330 MaybeRemoveDevice(const char *path)
331 {
332     SDL_joylist_item *item;
333     SDL_joylist_item *prev = NULL;
334 
335     if (path == NULL) {
336         return -1;
337     }
338 
339     for (item = SDL_joylist; item != NULL; item = item->next) {
340         /* found it, remove it. */
341         if (SDL_strcmp(path, item->path) == 0) {
342             const int retval = item->device_instance;
343             if (item->hwdata) {
344                 item->hwdata->item = NULL;
345             }
346             if (prev != NULL) {
347                 prev->next = item->next;
348             } else {
349                 SDL_assert(SDL_joylist == item);
350                 SDL_joylist = item->next;
351             }
352             if (item == SDL_joylist_tail) {
353                 SDL_joylist_tail = prev;
354             }
355 
356             /* Need to decrement the joystick count before we post the event */
357             --numjoysticks;
358 
359             SDL_PrivateJoystickRemoved(item->device_instance);
360 
361             SDL_free(item->path);
362             SDL_free(item->name);
363             SDL_free(item);
364             return retval;
365         }
366         prev = item;
367     }
368 
369     return -1;
370 }
371 #endif
372 
373 static void
HandlePendingRemovals(void)374 HandlePendingRemovals(void)
375 {
376     SDL_joylist_item *prev = NULL;
377     SDL_joylist_item *item = SDL_joylist;
378 
379     while (item != NULL) {
380         if (item->hwdata && item->hwdata->gone) {
381             item->hwdata->item = NULL;
382 
383             if (prev != NULL) {
384                 prev->next = item->next;
385             } else {
386                 SDL_assert(SDL_joylist == item);
387                 SDL_joylist = item->next;
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 
398             SDL_free(item->path);
399             SDL_free(item->name);
400             SDL_free(item);
401 
402             if (prev != NULL) {
403                 item = prev->next;
404             } else {
405                 item = SDL_joylist;
406             }
407         } else {
408             prev = item;
409             item = item->next;
410         }
411     }
412 }
413 
SteamControllerConnectedCallback(const char * name,SDL_JoystickGUID guid,int * device_instance)414 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
415 {
416     SDL_joylist_item *item;
417 
418     item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
419     if (item == NULL) {
420         return SDL_FALSE;
421     }
422 
423     item->path = SDL_strdup("");
424     item->name = SDL_strdup(name);
425     item->guid = guid;
426     item->m_bSteamController = SDL_TRUE;
427 
428     if ((item->path == NULL) || (item->name == NULL)) {
429          SDL_free(item->path);
430          SDL_free(item->name);
431          SDL_free(item);
432          return SDL_FALSE;
433     }
434 
435     *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
436     if (SDL_joylist_tail == NULL) {
437         SDL_joylist = SDL_joylist_tail = item;
438     } else {
439         SDL_joylist_tail->next = item;
440         SDL_joylist_tail = item;
441     }
442 
443     /* Need to increment the joystick count before we post the event */
444     ++numjoysticks;
445 
446     SDL_PrivateJoystickAdded(item->device_instance);
447 
448     return SDL_TRUE;
449 }
450 
SteamControllerDisconnectedCallback(int device_instance)451 static void SteamControllerDisconnectedCallback(int device_instance)
452 {
453     SDL_joylist_item *item;
454     SDL_joylist_item *prev = NULL;
455 
456     for (item = SDL_joylist; item != NULL; item = item->next) {
457         /* found it, remove it. */
458         if (item->device_instance == device_instance) {
459             if (item->hwdata) {
460                 item->hwdata->item = NULL;
461             }
462             if (prev != NULL) {
463                 prev->next = item->next;
464             } else {
465                 SDL_assert(SDL_joylist == item);
466                 SDL_joylist = item->next;
467             }
468             if (item == SDL_joylist_tail) {
469                 SDL_joylist_tail = prev;
470             }
471 
472             /* Need to decrement the joystick count before we post the event */
473             --numjoysticks;
474 
475             SDL_PrivateJoystickRemoved(item->device_instance);
476 
477             SDL_free(item->name);
478             SDL_free(item);
479             return;
480         }
481         prev = item;
482     }
483 }
484 
485 static void
LINUX_JoystickDetect(void)486 LINUX_JoystickDetect(void)
487 {
488 #if SDL_USE_LIBUDEV
489     SDL_UDEV_Poll();
490 #else
491     const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000;  /* Update every 3 seconds */
492     Uint32 now = SDL_GetTicks();
493 
494     if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
495         struct stat sb;
496 
497         /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
498         if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
499             DIR *folder;
500             struct dirent *dent;
501 
502             folder = opendir("/dev/input");
503             if (folder) {
504                 while ((dent = readdir(folder))) {
505                     int len = SDL_strlen(dent->d_name);
506                     if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
507                         char path[PATH_MAX];
508                         SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
509                         MaybeAddDevice(path);
510                     }
511                 }
512 
513                 closedir(folder);
514             }
515 
516             last_input_dir_mtime = sb.st_mtime;
517         }
518 
519         last_joy_detect_time = now;
520     }
521 #endif
522 
523     HandlePendingRemovals();
524 
525     SDL_UpdateSteamControllers();
526 }
527 
528 static int
LINUX_JoystickInit(void)529 LINUX_JoystickInit(void)
530 {
531     /* First see if the user specified one or more joysticks to use */
532     if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
533         char *envcopy, *envpath, *delim;
534         envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
535         envpath = envcopy;
536         while (envpath != NULL) {
537             delim = SDL_strchr(envpath, ':');
538             if (delim != NULL) {
539                 *delim++ = '\0';
540             }
541             MaybeAddDevice(envpath);
542             envpath = delim;
543         }
544         SDL_free(envcopy);
545     }
546 
547     SDL_InitSteamControllers(SteamControllerConnectedCallback,
548                              SteamControllerDisconnectedCallback);
549 
550 #if SDL_USE_LIBUDEV
551     if (SDL_UDEV_Init() < 0) {
552         return SDL_SetError("Could not initialize UDEV");
553     }
554 
555     /* Set up the udev callback */
556     if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
557         SDL_UDEV_Quit();
558         return SDL_SetError("Could not set up joystick <-> udev callback");
559     }
560 
561     /* Force a scan to build the initial device list */
562     SDL_UDEV_Scan();
563 #else
564     /* Force immediate joystick detection */
565     last_joy_detect_time = 0;
566     last_input_dir_mtime = 0;
567 
568     /* Report all devices currently present */
569     LINUX_JoystickDetect();
570 #endif
571 
572     return 0;
573 }
574 
575 static int
LINUX_JoystickGetCount(void)576 LINUX_JoystickGetCount(void)
577 {
578     return numjoysticks;
579 }
580 
581 static SDL_joylist_item *
JoystickByDevIndex(int device_index)582 JoystickByDevIndex(int device_index)
583 {
584     SDL_joylist_item *item = SDL_joylist;
585 
586     if ((device_index < 0) || (device_index >= numjoysticks)) {
587         return NULL;
588     }
589 
590     while (device_index > 0) {
591         SDL_assert(item != NULL);
592         device_index--;
593         item = item->next;
594     }
595 
596     return item;
597 }
598 
599 /* Function to get the device-dependent name of a joystick */
600 static const char *
LINUX_JoystickGetDeviceName(int device_index)601 LINUX_JoystickGetDeviceName(int device_index)
602 {
603     return JoystickByDevIndex(device_index)->name;
604 }
605 
606 static int
LINUX_JoystickGetDevicePlayerIndex(int device_index)607 LINUX_JoystickGetDevicePlayerIndex(int device_index)
608 {
609     return -1;
610 }
611 
612 static void
LINUX_JoystickSetDevicePlayerIndex(int device_index,int player_index)613 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
614 {
615 }
616 
617 static SDL_JoystickGUID
LINUX_JoystickGetDeviceGUID(int device_index)618 LINUX_JoystickGetDeviceGUID( int device_index )
619 {
620     return JoystickByDevIndex(device_index)->guid;
621 }
622 
623 /* Function to perform the mapping from device index to the instance id for this index */
624 static SDL_JoystickID
LINUX_JoystickGetDeviceInstanceID(int device_index)625 LINUX_JoystickGetDeviceInstanceID(int device_index)
626 {
627     return JoystickByDevIndex(device_index)->device_instance;
628 }
629 
630 static int
allocate_hatdata(SDL_Joystick * joystick)631 allocate_hatdata(SDL_Joystick * joystick)
632 {
633     int i;
634 
635     joystick->hwdata->hats =
636         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
637                                          sizeof(struct hwdata_hat));
638     if (joystick->hwdata->hats == NULL) {
639         return (-1);
640     }
641     for (i = 0; i < joystick->nhats; ++i) {
642         joystick->hwdata->hats[i].axis[0] = 1;
643         joystick->hwdata->hats[i].axis[1] = 1;
644     }
645     return (0);
646 }
647 
648 static int
allocate_balldata(SDL_Joystick * joystick)649 allocate_balldata(SDL_Joystick * joystick)
650 {
651     int i;
652 
653     joystick->hwdata->balls =
654         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
655                                           sizeof(struct hwdata_ball));
656     if (joystick->hwdata->balls == NULL) {
657         return (-1);
658     }
659     for (i = 0; i < joystick->nballs; ++i) {
660         joystick->hwdata->balls[i].axis[0] = 0;
661         joystick->hwdata->balls[i].axis[1] = 0;
662     }
663     return (0);
664 }
665 
666 static void
ConfigJoystick(SDL_Joystick * joystick,int fd)667 ConfigJoystick(SDL_Joystick * joystick, int fd)
668 {
669     int i, t;
670     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
671     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
672     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
673     unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
674 
675     /* See if this device uses the new unified event API */
676     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
677         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
678         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
679 
680         /* Get the number of buttons, axes, and other thingamajigs */
681         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
682             if (test_bit(i, keybit)) {
683 #ifdef DEBUG_INPUT_EVENTS
684                 printf("Joystick has button: 0x%x\n", i);
685 #endif
686                 joystick->hwdata->key_map[i] = joystick->nbuttons;
687                 joystick->hwdata->has_key[i] = SDL_TRUE;
688                 ++joystick->nbuttons;
689             }
690         }
691         for (i = 0; i < BTN_JOYSTICK; ++i) {
692             if (test_bit(i, keybit)) {
693 #ifdef DEBUG_INPUT_EVENTS
694                 printf("Joystick has button: 0x%x\n", i);
695 #endif
696                 joystick->hwdata->key_map[i] = joystick->nbuttons;
697                 joystick->hwdata->has_key[i] = SDL_TRUE;
698                 ++joystick->nbuttons;
699             }
700         }
701         for (i = 0; i < ABS_MAX; ++i) {
702             /* Skip hats */
703             if (i == ABS_HAT0X) {
704                 i = ABS_HAT3Y;
705                 continue;
706             }
707             if (test_bit(i, absbit)) {
708                 struct input_absinfo absinfo;
709 
710                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
711                     continue;
712                 }
713 #ifdef DEBUG_INPUT_EVENTS
714                 printf("Joystick has absolute axis: 0x%.2x\n", i);
715                 printf("Values = { %d, %d, %d, %d, %d }\n",
716                        absinfo.value, absinfo.minimum, absinfo.maximum,
717                        absinfo.fuzz, absinfo.flat);
718 #endif /* DEBUG_INPUT_EVENTS */
719                 joystick->hwdata->abs_map[i] = joystick->naxes;
720                 joystick->hwdata->has_abs[i] = SDL_TRUE;
721                 if (absinfo.minimum == absinfo.maximum) {
722                     joystick->hwdata->abs_correct[i].used = 0;
723                 } else {
724                     joystick->hwdata->abs_correct[i].used = 1;
725                     joystick->hwdata->abs_correct[i].coef[0] =
726                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
727                     joystick->hwdata->abs_correct[i].coef[1] =
728                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
729                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
730                     if (t != 0) {
731                         joystick->hwdata->abs_correct[i].coef[2] =
732                             (1 << 28) / t;
733                     } else {
734                         joystick->hwdata->abs_correct[i].coef[2] = 0;
735                     }
736                 }
737                 ++joystick->naxes;
738             }
739         }
740         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
741             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
742                 struct input_absinfo absinfo;
743                 int hat_index = (i - ABS_HAT0X) / 2;
744 
745                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
746                     continue;
747                 }
748 #ifdef DEBUG_INPUT_EVENTS
749                 printf("Joystick has hat %d\n", hat_index);
750                 printf("Values = { %d, %d, %d, %d, %d }\n",
751                        absinfo.value, absinfo.minimum, absinfo.maximum,
752                        absinfo.fuzz, absinfo.flat);
753 #endif /* DEBUG_INPUT_EVENTS */
754                 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
755                 joystick->hwdata->has_hat[hat_index] = SDL_TRUE;
756             }
757         }
758         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
759             ++joystick->nballs;
760         }
761 
762         /* Allocate data to keep track of these thingamajigs */
763         if (joystick->nhats > 0) {
764             if (allocate_hatdata(joystick) < 0) {
765                 joystick->nhats = 0;
766             }
767         }
768         if (joystick->nballs > 0) {
769             if (allocate_balldata(joystick) < 0) {
770                 joystick->nballs = 0;
771             }
772         }
773     }
774 
775     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
776         if (test_bit(FF_RUMBLE, ffbit)) {
777             joystick->hwdata->ff_rumble = SDL_TRUE;
778         }
779         if (test_bit(FF_SINE, ffbit)) {
780             joystick->hwdata->ff_sine = SDL_TRUE;
781         }
782     }
783 }
784 
785 
786 /* Function to open a joystick for use.
787    The joystick to open is specified by the device index.
788    This should fill the nbuttons and naxes fields of the joystick structure.
789    It returns 0, or -1 if there is an error.
790  */
791 static int
LINUX_JoystickOpen(SDL_Joystick * joystick,int device_index)792 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
793 {
794     SDL_joylist_item *item = JoystickByDevIndex(device_index);
795 
796     if (item == NULL) {
797         return SDL_SetError("No such device");
798     }
799 
800     joystick->instance_id = item->device_instance;
801     joystick->hwdata = (struct joystick_hwdata *)
802         SDL_calloc(1, sizeof(*joystick->hwdata));
803     if (joystick->hwdata == NULL) {
804         return SDL_OutOfMemory();
805     }
806     joystick->hwdata->item = item;
807     joystick->hwdata->guid = item->guid;
808     joystick->hwdata->effect.id = -1;
809     joystick->hwdata->m_bSteamController = item->m_bSteamController;
810     SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
811 
812     if (item->m_bSteamController) {
813         joystick->hwdata->fd = -1;
814         SDL_GetSteamControllerInputs(&joystick->nbuttons,
815                                      &joystick->naxes,
816                                      &joystick->nhats);
817     } else {
818         int fd = open(item->path, O_RDWR, 0);
819         if (fd < 0) {
820             SDL_free(joystick->hwdata);
821             joystick->hwdata = NULL;
822             return SDL_SetError("Unable to open %s", item->path);
823         }
824 
825         joystick->hwdata->fd = fd;
826         joystick->hwdata->fname = SDL_strdup(item->path);
827         if (joystick->hwdata->fname == NULL) {
828             SDL_free(joystick->hwdata);
829             joystick->hwdata = NULL;
830             close(fd);
831             return SDL_OutOfMemory();
832         }
833 
834         /* Set the joystick to non-blocking read mode */
835         fcntl(fd, F_SETFL, O_NONBLOCK);
836 
837         /* Get the number of buttons and axes on the joystick */
838         ConfigJoystick(joystick, fd);
839     }
840 
841     SDL_assert(item->hwdata == NULL);
842     item->hwdata = joystick->hwdata;
843 
844     /* mark joystick as fresh and ready */
845     joystick->hwdata->fresh = SDL_TRUE;
846 
847     return (0);
848 }
849 
850 static int
LINUX_JoystickRumble(SDL_Joystick * joystick,Uint16 low_frequency_rumble,Uint16 high_frequency_rumble)851 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
852 {
853     struct input_event event;
854 
855     if (joystick->hwdata->ff_rumble) {
856         struct ff_effect *effect = &joystick->hwdata->effect;
857 
858         effect->type = FF_RUMBLE;
859         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
860         effect->u.rumble.strong_magnitude = low_frequency_rumble;
861         effect->u.rumble.weak_magnitude = high_frequency_rumble;
862     } else if (joystick->hwdata->ff_sine) {
863         /* Scale and average the two rumble strengths */
864         Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
865         struct ff_effect *effect = &joystick->hwdata->effect;
866 
867         effect->type = FF_PERIODIC;
868         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
869         effect->u.periodic.waveform = FF_SINE;
870         effect->u.periodic.magnitude = magnitude;
871     } else {
872         return SDL_Unsupported();
873     }
874 
875     if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
876         /* The kernel may have lost this effect, try to allocate a new one */
877         joystick->hwdata->effect.id = -1;
878         if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
879             return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
880         }
881     }
882 
883     event.type = EV_FF;
884     event.code = joystick->hwdata->effect.id;
885     event.value = 1;
886     if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
887         return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
888     }
889     return 0;
890 }
891 
892 static SDL_INLINE void
HandleHat(SDL_Joystick * stick,Uint8 hat,int axis,int value)893 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
894 {
895     struct hwdata_hat *the_hat;
896     const Uint8 position_map[3][3] = {
897         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
898         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
899         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
900     };
901 
902     the_hat = &stick->hwdata->hats[hat];
903     if (value < 0) {
904         value = 0;
905     } else if (value == 0) {
906         value = 1;
907     } else if (value > 0) {
908         value = 2;
909     }
910     if (value != the_hat->axis[axis]) {
911         the_hat->axis[axis] = value;
912         SDL_PrivateJoystickHat(stick, hat,
913                                position_map[the_hat->axis[1]][the_hat->axis[0]]);
914     }
915 }
916 
917 static SDL_INLINE void
HandleBall(SDL_Joystick * stick,Uint8 ball,int axis,int value)918 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
919 {
920     stick->hwdata->balls[ball].axis[axis] += value;
921 }
922 
923 
924 static SDL_INLINE int
AxisCorrect(SDL_Joystick * joystick,int which,int value)925 AxisCorrect(SDL_Joystick * joystick, int which, int value)
926 {
927     struct axis_correct *correct;
928 
929     correct = &joystick->hwdata->abs_correct[which];
930     if (correct->used) {
931         value *= 2;
932         if (value > correct->coef[0]) {
933             if (value < correct->coef[1]) {
934                 return 0;
935             }
936             value -= correct->coef[1];
937         } else {
938             value -= correct->coef[0];
939         }
940         value *= correct->coef[2];
941         value >>= 13;
942     }
943 
944     /* Clamp and return */
945     if (value < -32768)
946         return -32768;
947     if (value > 32767)
948         return 32767;
949 
950     return value;
951 }
952 
953 static SDL_INLINE void
PollAllValues(SDL_Joystick * joystick)954 PollAllValues(SDL_Joystick * joystick)
955 {
956     struct input_absinfo absinfo;
957     unsigned long keyinfo[NBITS(KEY_MAX)];
958     int i;
959 
960     /* Poll all axis */
961     for (i = ABS_X; i < ABS_MAX; i++) {
962         if (i == ABS_HAT0X) {  /* we handle hats in the next loop, skip them for now. */
963             i = ABS_HAT3Y;
964             continue;
965         }
966         if (joystick->hwdata->abs_correct[i].used) {
967             if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
968                 absinfo.value = AxisCorrect(joystick, i, absinfo.value);
969 
970 #ifdef DEBUG_INPUT_EVENTS
971                 printf("Joystick : Re-read Axis %d (%d) val= %d\n",
972                     joystick->hwdata->abs_map[i], i, absinfo.value);
973 #endif
974                 SDL_PrivateJoystickAxis(joystick,
975                         joystick->hwdata->abs_map[i],
976                         absinfo.value);
977             }
978         }
979     }
980 
981     /* Poll all hats */
982     for (i = ABS_HAT0X; i <= ABS_HAT3Y; i++) {
983         const int baseaxis = i - ABS_HAT0X;
984         const int hatidx = baseaxis / 2;
985         SDL_assert(hatidx < SDL_arraysize(joystick->hwdata->has_hat));
986         if (joystick->hwdata->has_hat[hatidx]) {
987             if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
988                 const int hataxis = baseaxis % 2;
989                 HandleHat(joystick, joystick->hwdata->hats_indices[hatidx], hataxis, absinfo.value);
990             }
991         }
992     }
993 
994     /* Poll all buttons */
995     SDL_zeroa(keyinfo);
996     if (ioctl(joystick->hwdata->fd, EVIOCGKEY(sizeof (keyinfo)), keyinfo) >= 0) {
997         for (i = 0; i < KEY_MAX; i++) {
998             if (joystick->hwdata->has_key[i]) {
999                 const Uint8 value = test_bit(i, keyinfo) ? SDL_PRESSED : SDL_RELEASED;
1000 #ifdef DEBUG_INPUT_EVENTS
1001                 printf("Joystick : Re-read Button %d (%d) val= %d\n",
1002                     joystick->hwdata->key_map[i], i, value);
1003 #endif
1004                 SDL_PrivateJoystickButton(joystick,
1005                         joystick->hwdata->key_map[i], value);
1006             }
1007         }
1008     }
1009 
1010     /* Joyballs are relative input, so there's no poll state. Events only! */
1011 }
1012 
1013 static SDL_INLINE void
HandleInputEvents(SDL_Joystick * joystick)1014 HandleInputEvents(SDL_Joystick * joystick)
1015 {
1016     struct input_event events[32];
1017     int i, len;
1018     int code;
1019 
1020     if (joystick->hwdata->fresh) {
1021         PollAllValues(joystick);
1022         joystick->hwdata->fresh = SDL_FALSE;
1023     }
1024 
1025     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
1026         len /= sizeof(events[0]);
1027         for (i = 0; i < len; ++i) {
1028             code = events[i].code;
1029 
1030             /* If the kernel sent a SYN_DROPPED, we are supposed to ignore the
1031                rest of the packet (the end of it signified by a SYN_REPORT) */
1032             if ( joystick->hwdata->recovering_from_dropped &&
1033                  ((events[i].type != EV_SYN) || (code != SYN_REPORT)) ) {
1034                 continue;
1035             }
1036 
1037             switch (events[i].type) {
1038             case EV_KEY:
1039                 SDL_PrivateJoystickButton(joystick,
1040                                           joystick->hwdata->key_map[code],
1041                                           events[i].value);
1042                 break;
1043             case EV_ABS:
1044                 switch (code) {
1045                 case ABS_HAT0X:
1046                 case ABS_HAT0Y:
1047                 case ABS_HAT1X:
1048                 case ABS_HAT1Y:
1049                 case ABS_HAT2X:
1050                 case ABS_HAT2Y:
1051                 case ABS_HAT3X:
1052                 case ABS_HAT3Y:
1053                     code -= ABS_HAT0X;
1054                     HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
1055                     break;
1056                 default:
1057                     if (joystick->hwdata->abs_map[code] != 0xFF) {
1058                         events[i].value =
1059                             AxisCorrect(joystick, code, events[i].value);
1060                         SDL_PrivateJoystickAxis(joystick,
1061                                                 joystick->hwdata->abs_map[code],
1062                                                 events[i].value);
1063                     }
1064                     break;
1065                 }
1066                 break;
1067             case EV_REL:
1068                 switch (code) {
1069                 case REL_X:
1070                 case REL_Y:
1071                     code -= REL_X;
1072                     HandleBall(joystick, code / 2, code % 2, events[i].value);
1073                     break;
1074                 default:
1075                     break;
1076                 }
1077                 break;
1078             case EV_SYN:
1079                 switch (code) {
1080                 case SYN_DROPPED :
1081 #ifdef DEBUG_INPUT_EVENTS
1082                     printf("Event SYN_DROPPED detected\n");
1083 #endif
1084                     joystick->hwdata->recovering_from_dropped = SDL_TRUE;
1085                     break;
1086                 case SYN_REPORT :
1087                     if (joystick->hwdata->recovering_from_dropped) {
1088                         joystick->hwdata->recovering_from_dropped = SDL_FALSE;
1089                         PollAllValues(joystick);  /* try to sync up to current state now */
1090                     }
1091                     break;
1092                 default:
1093                     break;
1094                 }
1095             default:
1096                 break;
1097             }
1098         }
1099     }
1100 
1101     if (errno == ENODEV) {
1102         /* We have to wait until the JoystickDetect callback to remove this */
1103         joystick->hwdata->gone = SDL_TRUE;
1104     }
1105 }
1106 
1107 static void
LINUX_JoystickUpdate(SDL_Joystick * joystick)1108 LINUX_JoystickUpdate(SDL_Joystick * joystick)
1109 {
1110     int i;
1111 
1112     if (joystick->hwdata->m_bSteamController) {
1113         SDL_UpdateSteamController(joystick);
1114         return;
1115     }
1116 
1117     HandleInputEvents(joystick);
1118 
1119     /* Deliver ball motion updates */
1120     for (i = 0; i < joystick->nballs; ++i) {
1121         int xrel, yrel;
1122 
1123         xrel = joystick->hwdata->balls[i].axis[0];
1124         yrel = joystick->hwdata->balls[i].axis[1];
1125         if (xrel || yrel) {
1126             joystick->hwdata->balls[i].axis[0] = 0;
1127             joystick->hwdata->balls[i].axis[1] = 0;
1128             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
1129         }
1130     }
1131 }
1132 
1133 /* Function to close a joystick after use */
1134 static void
LINUX_JoystickClose(SDL_Joystick * joystick)1135 LINUX_JoystickClose(SDL_Joystick * joystick)
1136 {
1137     if (joystick->hwdata) {
1138         if (joystick->hwdata->effect.id >= 0) {
1139             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
1140             joystick->hwdata->effect.id = -1;
1141         }
1142         if (joystick->hwdata->fd >= 0) {
1143             close(joystick->hwdata->fd);
1144         }
1145         if (joystick->hwdata->item) {
1146             joystick->hwdata->item->hwdata = NULL;
1147         }
1148         SDL_free(joystick->hwdata->hats);
1149         SDL_free(joystick->hwdata->balls);
1150         SDL_free(joystick->hwdata->fname);
1151         SDL_free(joystick->hwdata);
1152     }
1153 }
1154 
1155 /* Function to perform any system-specific joystick related cleanup */
1156 static void
LINUX_JoystickQuit(void)1157 LINUX_JoystickQuit(void)
1158 {
1159     SDL_joylist_item *item = NULL;
1160     SDL_joylist_item *next = NULL;
1161 
1162     for (item = SDL_joylist; item; item = next) {
1163         next = item->next;
1164         SDL_free(item->path);
1165         SDL_free(item->name);
1166         SDL_free(item);
1167     }
1168 
1169     SDL_joylist = SDL_joylist_tail = NULL;
1170 
1171     numjoysticks = 0;
1172 
1173 #if SDL_USE_LIBUDEV
1174     SDL_UDEV_DelCallback(joystick_udev_callback);
1175     SDL_UDEV_Quit();
1176 #endif
1177 
1178     SDL_QuitSteamControllers();
1179 }
1180 
1181 /*
1182    This is based on the Linux Gamepad Specification
1183    available at: https://www.kernel.org/doc/html/v4.15/input/gamepad.html
1184  */
1185 static SDL_bool
LINUX_JoystickGetGamepadMapping(int device_index,SDL_GamepadMapping * out)1186 LINUX_JoystickGetGamepadMapping(int device_index, SDL_GamepadMapping *out)
1187 {
1188     SDL_Joystick * joystick;
1189 
1190     joystick = (SDL_Joystick *) SDL_calloc(sizeof(*joystick), 1);
1191     if (joystick == NULL) {
1192         SDL_OutOfMemory();
1193         return SDL_FALSE;
1194     }
1195 
1196     /* We temporarily open the device to check how it's configured. */
1197     if (LINUX_JoystickOpen(joystick, device_index) < 0) {
1198         SDL_free(joystick);
1199         return SDL_FALSE;
1200     }
1201 
1202     if (!joystick->hwdata->has_key[BTN_GAMEPAD]) {
1203         /* Not a gamepad according to the specs. */
1204         LINUX_JoystickClose(joystick);
1205         SDL_free(joystick);
1206         return SDL_FALSE;
1207     }
1208 
1209     /* We have a gamepad, start filling out the mappings */
1210 
1211     if (joystick->hwdata->has_key[BTN_SOUTH]) {
1212         out->a.kind = EMappingKind_Button;
1213         out->a.target = joystick->hwdata->key_map[BTN_SOUTH];
1214     }
1215 
1216     if (joystick->hwdata->has_key[BTN_EAST]) {
1217         out->b.kind = EMappingKind_Button;
1218         out->b.target = joystick->hwdata->key_map[BTN_EAST];
1219     }
1220 
1221     if (joystick->hwdata->has_key[BTN_NORTH]) {
1222         out->y.kind = EMappingKind_Button;
1223         out->y.target = joystick->hwdata->key_map[BTN_NORTH];
1224     }
1225 
1226     if (joystick->hwdata->has_key[BTN_WEST]) {
1227         out->x.kind = EMappingKind_Button;
1228         out->x.target = joystick->hwdata->key_map[BTN_WEST];
1229     }
1230 
1231     if (joystick->hwdata->has_key[BTN_SELECT]) {
1232         out->back.kind = EMappingKind_Button;
1233         out->back.target = joystick->hwdata->key_map[BTN_SELECT];
1234     }
1235 
1236     if (joystick->hwdata->has_key[BTN_START]) {
1237         out->start.kind = EMappingKind_Button;
1238         out->start.target = joystick->hwdata->key_map[BTN_START];
1239     }
1240 
1241     if (joystick->hwdata->has_key[BTN_THUMBL]) {
1242         out->leftstick.kind = EMappingKind_Button;
1243         out->leftstick.target = joystick->hwdata->key_map[BTN_THUMBL];
1244     }
1245 
1246     if (joystick->hwdata->has_key[BTN_THUMBR]) {
1247         out->rightstick.kind = EMappingKind_Button;
1248         out->rightstick.target = joystick->hwdata->key_map[BTN_THUMBR];
1249     }
1250 
1251     if (joystick->hwdata->has_key[BTN_MODE]) {
1252         out->guide.kind = EMappingKind_Button;
1253         out->guide.target = joystick->hwdata->key_map[BTN_MODE];
1254     }
1255 
1256     /*
1257        According to the specs the D-Pad, the shoulder buttons and the triggers
1258        can be digital, or analog, or both at the same time.
1259      */
1260 
1261     /* Prefer digital shoulder buttons, but settle for analog if missing. */
1262     if (joystick->hwdata->has_key[BTN_TL]) {
1263         out->leftshoulder.kind = EMappingKind_Button;
1264         out->leftshoulder.target = joystick->hwdata->key_map[BTN_TL];
1265     }
1266 
1267     if (joystick->hwdata->has_key[BTN_TR]) {
1268         out->rightshoulder.kind = EMappingKind_Button;
1269         out->rightshoulder.target = joystick->hwdata->key_map[BTN_TR];
1270     }
1271 
1272     if (joystick->hwdata->has_hat[1] && /* Check if ABS_HAT1{X, Y} is available. */
1273        (!joystick->hwdata->has_key[BTN_TL] || !joystick->hwdata->has_key[BTN_TR])) {
1274         int hat = joystick->hwdata->hats_indices[1] << 4;
1275         out->leftshoulder.kind = EMappingKind_Hat;
1276         out->rightshoulder.kind = EMappingKind_Hat;
1277         out->leftshoulder.target = hat | 0x4;
1278         out->rightshoulder.target = hat | 0x2;
1279     }
1280 
1281     /* Prefer analog triggers, but settle for digital if missing. */
1282     if (joystick->hwdata->has_hat[2]) { /* Check if ABS_HAT2{X,Y} is available. */
1283         int hat = joystick->hwdata->hats_indices[2] << 4;
1284         out->lefttrigger.kind = EMappingKind_Hat;
1285         out->righttrigger.kind = EMappingKind_Hat;
1286         out->lefttrigger.target = hat | 0x4;
1287         out->righttrigger.target = hat | 0x2;
1288     } else {
1289         if (joystick->hwdata->has_key[BTN_TL2]) {
1290             out->lefttrigger.kind = EMappingKind_Button;
1291             out->lefttrigger.target = joystick->hwdata->key_map[BTN_TL2];
1292         }
1293 
1294         if (joystick->hwdata->has_key[BTN_TR2]) {
1295             out->righttrigger.kind = EMappingKind_Button;
1296             out->righttrigger.target = joystick->hwdata->key_map[BTN_TR2];
1297         }
1298     }
1299 
1300     /* Prefer digital D-Pad, but settle for analog if missing. */
1301     if (joystick->hwdata->has_key[BTN_DPAD_UP]) {
1302         out->dpup.kind = EMappingKind_Button;
1303         out->dpup.target = joystick->hwdata->key_map[BTN_DPAD_UP];
1304     }
1305 
1306     if (joystick->hwdata->has_key[BTN_DPAD_DOWN]) {
1307         out->dpdown.kind = EMappingKind_Button;
1308         out->dpdown.target = joystick->hwdata->key_map[BTN_DPAD_DOWN];
1309     }
1310 
1311     if (joystick->hwdata->has_key[BTN_DPAD_LEFT]) {
1312         out->dpleft.kind = EMappingKind_Button;
1313         out->dpleft.target = joystick->hwdata->key_map[BTN_DPAD_LEFT];
1314     }
1315 
1316     if (joystick->hwdata->has_key[BTN_DPAD_RIGHT]) {
1317         out->dpright.kind = EMappingKind_Button;
1318         out->dpright.target = joystick->hwdata->key_map[BTN_DPAD_RIGHT];
1319     }
1320 
1321     if (joystick->hwdata->has_hat[0] && /* Check if ABS_HAT0{X,Y} is available. */
1322        (!joystick->hwdata->has_key[BTN_DPAD_LEFT] || !joystick->hwdata->has_key[BTN_DPAD_RIGHT] ||
1323         !joystick->hwdata->has_key[BTN_DPAD_UP] || !joystick->hwdata->has_key[BTN_DPAD_DOWN])) {
1324        int hat = joystick->hwdata->hats_indices[0] << 4;
1325        out->dpleft.kind = EMappingKind_Hat;
1326        out->dpright.kind = EMappingKind_Hat;
1327        out->dpup.kind = EMappingKind_Hat;
1328        out->dpdown.kind = EMappingKind_Hat;
1329        out->dpleft.target = hat | 0x8;
1330        out->dpright.target = hat | 0x2;
1331        out->dpup.target = hat | 0x1;
1332        out->dpdown.target = hat | 0x4;
1333     }
1334 
1335     if (joystick->hwdata->has_abs[ABS_X] && joystick->hwdata->has_abs[ABS_Y]) {
1336         out->leftx.kind = EMappingKind_Axis;
1337         out->lefty.kind = EMappingKind_Axis;
1338         out->leftx.target = joystick->hwdata->abs_map[ABS_X];
1339         out->lefty.target = joystick->hwdata->abs_map[ABS_Y];
1340     }
1341 
1342     if (joystick->hwdata->has_abs[ABS_RX] && joystick->hwdata->has_abs[ABS_RY]) {
1343         out->rightx.kind = EMappingKind_Axis;
1344         out->righty.kind = EMappingKind_Axis;
1345         out->rightx.target = joystick->hwdata->abs_map[ABS_RX];
1346         out->righty.target = joystick->hwdata->abs_map[ABS_RY];
1347     }
1348 
1349     LINUX_JoystickClose(joystick);
1350     SDL_free(joystick);
1351 
1352     return SDL_TRUE;
1353 }
1354 
1355 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
1356 {
1357     LINUX_JoystickInit,
1358     LINUX_JoystickGetCount,
1359     LINUX_JoystickDetect,
1360     LINUX_JoystickGetDeviceName,
1361     LINUX_JoystickGetDevicePlayerIndex,
1362     LINUX_JoystickSetDevicePlayerIndex,
1363     LINUX_JoystickGetDeviceGUID,
1364     LINUX_JoystickGetDeviceInstanceID,
1365     LINUX_JoystickOpen,
1366     LINUX_JoystickRumble,
1367     LINUX_JoystickUpdate,
1368     LINUX_JoystickClose,
1369     LINUX_JoystickQuit,
1370     LINUX_JoystickGetGamepadMapping
1371 };
1372 
1373 #endif /* SDL_JOYSTICK_LINUX */
1374 
1375 /* vi: set ts=4 sw=4 expandtab: */
1376