sdl

FORK: Simple Directmedia Layer
git clone https://git.neptards.moe/neptards/sdl.git
Log | Files | Refs

SDL_sysjoystick.c (48177B)


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