src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 23 Mar 2020 14:10:25 -0700
changeset 13670 63387e8920f5
parent 13611 bcbfec15e25f
permissions -rw-r--r--
Don't check the HIDAPI driver for the virtual device created by xow
     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 
    56 #include "../../core/linux/SDL_udev.h"
    57 
    58 static int MaybeAddDevice(const char *path);
    59 #if SDL_USE_LIBUDEV
    60 static int MaybeRemoveDevice(const char *path);
    61 #endif /* SDL_USE_LIBUDEV */
    62 
    63 /* A linked list of available joysticks */
    64 typedef struct SDL_joylist_item
    65 {
    66     int device_instance;
    67     char *path;   /* "/dev/input/event2" or whatever */
    68     char *name;   /* "SideWinder 3D Pro" or whatever */
    69     SDL_JoystickGUID guid;
    70     dev_t devnum;
    71     struct joystick_hwdata *hwdata;
    72     struct SDL_joylist_item *next;
    73 
    74     /* Steam Controller support */
    75     SDL_bool m_bSteamController;
    76 } SDL_joylist_item;
    77 
    78 static SDL_joylist_item *SDL_joylist = NULL;
    79 static SDL_joylist_item *SDL_joylist_tail = NULL;
    80 static int numjoysticks = 0;
    81 
    82 #if !SDL_USE_LIBUDEV
    83 static Uint32 last_joy_detect_time;
    84 static time_t last_input_dir_mtime;
    85 #endif
    86 
    87 #define test_bit(nr, addr) \
    88     (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
    89 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
    90 
    91 static void
    92 FixupDeviceInfoForMapping(int fd, struct input_id *inpid)
    93 {
    94     if (inpid->vendor == 0x045e && inpid->product == 0x0b05 && inpid->version == 0x0903) {
    95         /* This is a Microsoft Xbox One Elite Series 2 controller */
    96         unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
    97 
    98         /* The first version of the firmware duplicated all the inputs */
    99         if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   100             test_bit(0x2c0, keybit)) {
   101             /* Change the version to 0x0902, so we can map it differently */
   102             inpid->version = 0x0902;
   103         }
   104     }
   105 }
   106 
   107 #ifdef SDL_JOYSTICK_HIDAPI
   108 static SDL_bool
   109 IsVirtualJoystick(Uint16 vendor, Uint16 product, Uint16 version, const char *name)
   110 {
   111     if (vendor == USB_VENDOR_MICROSOFT && product == USB_PRODUCT_XBOX_ONE_S && version == 0 &&
   112         SDL_strcmp(name, "Xbox One S Controller") == 0) {
   113         /* This is the virtual device created by the xow driver */
   114         return SDL_TRUE;
   115     }
   116     return SDL_FALSE;
   117 }
   118 #endif /* SDL_JOYSTICK_HIDAPI */
   119 
   120 static int
   121 IsJoystick(int fd, char **name_return, SDL_JoystickGUID *guid)
   122 {
   123     struct input_id inpid;
   124     Uint16 *guid16 = (Uint16 *)guid->data;
   125     char *name;
   126     char product_string[128];
   127 
   128 #if !SDL_USE_LIBUDEV
   129     /* When udev is enabled we only get joystick devices here, so there's no need to test them */
   130     unsigned long evbit[NBITS(EV_MAX)] = { 0 };
   131     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   132     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   133 
   134     if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
   135         (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
   136         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
   137         return (0);
   138     }
   139 
   140     if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
   141           test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
   142         return 0;
   143     }
   144 #endif
   145 
   146     if (ioctl(fd, EVIOCGID, &inpid) < 0) {
   147         return 0;
   148     }
   149 
   150     if (ioctl(fd, EVIOCGNAME(sizeof(product_string)), product_string) < 0) {
   151         return 0;
   152     }
   153 
   154     name = SDL_CreateJoystickName(inpid.vendor, inpid.product, NULL, product_string);
   155     if (!name) {
   156         return 0;
   157     }
   158 
   159 #ifdef SDL_JOYSTICK_HIDAPI
   160     if (!IsVirtualJoystick(inpid.vendor, inpid.product, inpid.version, name) &&
   161         HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version, name)) {
   162         /* The HIDAPI driver is taking care of this device */
   163         SDL_free(name);
   164         return 0;
   165     }
   166 #endif
   167 
   168     FixupDeviceInfoForMapping(fd, &inpid);
   169 
   170 #ifdef DEBUG_JOYSTICK
   171     printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", name, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
   172 #endif
   173 
   174     SDL_memset(guid->data, 0, sizeof(guid->data));
   175 
   176     /* We only need 16 bits for each of these; space them out to fill 128. */
   177     /* Byteswap so devices get same GUID on little/big endian platforms. */
   178     *guid16++ = SDL_SwapLE16(inpid.bustype);
   179     *guid16++ = 0;
   180 
   181     if (inpid.vendor && inpid.product) {
   182         *guid16++ = SDL_SwapLE16(inpid.vendor);
   183         *guid16++ = 0;
   184         *guid16++ = SDL_SwapLE16(inpid.product);
   185         *guid16++ = 0;
   186         *guid16++ = SDL_SwapLE16(inpid.version);
   187         *guid16++ = 0;
   188     } else {
   189         SDL_strlcpy((char*)guid16, name, sizeof(guid->data) - 4);
   190     }
   191 
   192     if (SDL_ShouldIgnoreJoystick(name, *guid)) {
   193         SDL_free(name);
   194         return 0;
   195     }
   196     *name_return = name;
   197     return 1;
   198 }
   199 
   200 #if SDL_USE_LIBUDEV
   201 static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
   202 {
   203     if (devpath == NULL) {
   204         return;
   205     }
   206 
   207     switch (udev_type) {
   208         case SDL_UDEV_DEVICEADDED:
   209             if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
   210                 return;
   211             }
   212             MaybeAddDevice(devpath);
   213             break;
   214             
   215         case SDL_UDEV_DEVICEREMOVED:
   216             MaybeRemoveDevice(devpath);
   217             break;
   218             
   219         default:
   220             break;
   221     }
   222     
   223 }
   224 #endif /* SDL_USE_LIBUDEV */
   225 
   226 static int
   227 MaybeAddDevice(const char *path)
   228 {
   229     struct stat sb;
   230     int fd = -1;
   231     int isstick = 0;
   232     char *name = NULL;
   233     SDL_JoystickGUID guid;
   234     SDL_joylist_item *item;
   235 
   236     if (path == NULL) {
   237         return -1;
   238     }
   239 
   240     if (stat(path, &sb) == -1) {
   241         return -1;
   242     }
   243 
   244     /* Check to make sure it's not already in list. */
   245     for (item = SDL_joylist; item != NULL; item = item->next) {
   246         if (sb.st_rdev == item->devnum) {
   247             return -1;  /* already have this one */
   248         }
   249     }
   250 
   251     fd = open(path, O_RDONLY, 0);
   252     if (fd < 0) {
   253         return -1;
   254     }
   255 
   256 #ifdef DEBUG_INPUT_EVENTS
   257     printf("Checking %s\n", path);
   258 #endif
   259 
   260     isstick = IsJoystick(fd, &name, &guid);
   261     close(fd);
   262     if (!isstick) {
   263         return -1;
   264     }
   265 
   266     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   267     if (item == NULL) {
   268         return -1;
   269     }
   270 
   271     SDL_zerop(item);
   272     item->devnum = sb.st_rdev;
   273     item->path = SDL_strdup(path);
   274     item->name = name;
   275     item->guid = guid;
   276 
   277     if ((item->path == NULL) || (item->name == NULL)) {
   278          SDL_free(item->path);
   279          SDL_free(item->name);
   280          SDL_free(item);
   281          return -1;
   282     }
   283 
   284     item->device_instance = SDL_GetNextJoystickInstanceID();
   285     if (SDL_joylist_tail == NULL) {
   286         SDL_joylist = SDL_joylist_tail = item;
   287     } else {
   288         SDL_joylist_tail->next = item;
   289         SDL_joylist_tail = item;
   290     }
   291 
   292     /* Need to increment the joystick count before we post the event */
   293     ++numjoysticks;
   294 
   295     SDL_PrivateJoystickAdded(item->device_instance);
   296 
   297     return numjoysticks;
   298 }
   299 
   300 #if SDL_USE_LIBUDEV
   301 static int
   302 MaybeRemoveDevice(const char *path)
   303 {
   304     SDL_joylist_item *item;
   305     SDL_joylist_item *prev = NULL;
   306 
   307     if (path == NULL) {
   308         return -1;
   309     }
   310 
   311     for (item = SDL_joylist; item != NULL; item = item->next) {
   312         /* found it, remove it. */
   313         if (SDL_strcmp(path, item->path) == 0) {
   314             const int retval = item->device_instance;
   315             if (item->hwdata) {
   316                 item->hwdata->item = NULL;
   317             }
   318             if (prev != NULL) {
   319                 prev->next = item->next;
   320             } else {
   321                 SDL_assert(SDL_joylist == item);
   322                 SDL_joylist = item->next;
   323             }
   324             if (item == SDL_joylist_tail) {
   325                 SDL_joylist_tail = prev;
   326             }
   327 
   328             /* Need to decrement the joystick count before we post the event */
   329             --numjoysticks;
   330 
   331             SDL_PrivateJoystickRemoved(item->device_instance);
   332 
   333             SDL_free(item->path);
   334             SDL_free(item->name);
   335             SDL_free(item);
   336             return retval;
   337         }
   338         prev = item;
   339     }
   340 
   341     return -1;
   342 }
   343 #endif
   344 
   345 static void
   346 HandlePendingRemovals(void)
   347 {
   348     SDL_joylist_item *prev = NULL;
   349     SDL_joylist_item *item = SDL_joylist;
   350 
   351     while (item != NULL) {
   352         if (item->hwdata && item->hwdata->gone) {
   353             item->hwdata->item = NULL;
   354 
   355             if (prev != NULL) {
   356                 prev->next = item->next;
   357             } else {
   358                 SDL_assert(SDL_joylist == item);
   359                 SDL_joylist = item->next;
   360             }
   361             if (item == SDL_joylist_tail) {
   362                 SDL_joylist_tail = prev;
   363             }
   364 
   365             /* Need to decrement the joystick count before we post the event */
   366             --numjoysticks;
   367 
   368             SDL_PrivateJoystickRemoved(item->device_instance);
   369 
   370             SDL_free(item->path);
   371             SDL_free(item->name);
   372             SDL_free(item);
   373 
   374             if (prev != NULL) {
   375                 item = prev->next;
   376             } else {
   377                 item = SDL_joylist;
   378             }
   379         } else {
   380             prev = item;
   381             item = item->next;
   382         }
   383     }
   384 }
   385 
   386 static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
   387 {
   388     SDL_joylist_item *item;
   389 
   390     item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
   391     if (item == NULL) {
   392         return SDL_FALSE;
   393     }
   394 
   395     item->path = SDL_strdup("");
   396     item->name = SDL_strdup(name);
   397     item->guid = guid;
   398     item->m_bSteamController = SDL_TRUE;
   399 
   400     if ((item->path == NULL) || (item->name == NULL)) {
   401          SDL_free(item->path);
   402          SDL_free(item->name);
   403          SDL_free(item);
   404          return SDL_FALSE;
   405     }
   406 
   407     *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
   408     if (SDL_joylist_tail == NULL) {
   409         SDL_joylist = SDL_joylist_tail = item;
   410     } else {
   411         SDL_joylist_tail->next = item;
   412         SDL_joylist_tail = item;
   413     }
   414 
   415     /* Need to increment the joystick count before we post the event */
   416     ++numjoysticks;
   417 
   418     SDL_PrivateJoystickAdded(item->device_instance);
   419 
   420     return SDL_TRUE;
   421 }
   422 
   423 static void SteamControllerDisconnectedCallback(int device_instance)
   424 {
   425     SDL_joylist_item *item;
   426     SDL_joylist_item *prev = NULL;
   427 
   428     for (item = SDL_joylist; item != NULL; item = item->next) {
   429         /* found it, remove it. */
   430         if (item->device_instance == device_instance) {
   431             if (item->hwdata) {
   432                 item->hwdata->item = NULL;
   433             }
   434             if (prev != NULL) {
   435                 prev->next = item->next;
   436             } else {
   437                 SDL_assert(SDL_joylist == item);
   438                 SDL_joylist = item->next;
   439             }
   440             if (item == SDL_joylist_tail) {
   441                 SDL_joylist_tail = prev;
   442             }
   443 
   444             /* Need to decrement the joystick count before we post the event */
   445             --numjoysticks;
   446 
   447             SDL_PrivateJoystickRemoved(item->device_instance);
   448 
   449             SDL_free(item->name);
   450             SDL_free(item);
   451             return;
   452         }
   453         prev = item;
   454     }
   455 }
   456 
   457 static void
   458 LINUX_JoystickDetect(void)
   459 {
   460 #if SDL_USE_LIBUDEV
   461     SDL_UDEV_Poll();
   462 #else
   463     const Uint32 SDL_JOY_DETECT_INTERVAL_MS = 3000;  /* Update every 3 seconds */
   464     Uint32 now = SDL_GetTicks();
   465 
   466     if (!last_joy_detect_time || SDL_TICKS_PASSED(now, last_joy_detect_time + SDL_JOY_DETECT_INTERVAL_MS)) {
   467         struct stat sb;
   468 
   469         /* Opening input devices can generate synchronous device I/O, so avoid it if we can */
   470         if (stat("/dev/input", &sb) == 0 && sb.st_mtime != last_input_dir_mtime) {
   471             DIR *folder;
   472             struct dirent *dent;
   473 
   474             folder = opendir("/dev/input");
   475             if (folder) {
   476                 while ((dent = readdir(folder))) {
   477                     int len = SDL_strlen(dent->d_name);
   478                     if (len > 5 && SDL_strncmp(dent->d_name, "event", 5) == 0) {
   479                         char path[PATH_MAX];
   480                         SDL_snprintf(path, SDL_arraysize(path), "/dev/input/%s", dent->d_name);
   481                         MaybeAddDevice(path);
   482                     }
   483                 }
   484 
   485                 closedir(folder);
   486             }
   487 
   488             last_input_dir_mtime = sb.st_mtime;
   489         }
   490 
   491         last_joy_detect_time = now;
   492     }
   493 #endif
   494 
   495     HandlePendingRemovals();
   496 
   497     SDL_UpdateSteamControllers();
   498 }
   499 
   500 static int
   501 LINUX_JoystickInit(void)
   502 {
   503     /* First see if the user specified one or more joysticks to use */
   504     if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
   505         char *envcopy, *envpath, *delim;
   506         envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
   507         envpath = envcopy;
   508         while (envpath != NULL) {
   509             delim = SDL_strchr(envpath, ':');
   510             if (delim != NULL) {
   511                 *delim++ = '\0';
   512             }
   513             MaybeAddDevice(envpath);
   514             envpath = delim;
   515         }
   516         SDL_free(envcopy);
   517     }
   518 
   519     SDL_InitSteamControllers(SteamControllerConnectedCallback,
   520                              SteamControllerDisconnectedCallback);
   521 
   522 #if SDL_USE_LIBUDEV
   523     if (SDL_UDEV_Init() < 0) {
   524         return SDL_SetError("Could not initialize UDEV");
   525     }
   526 
   527     /* Set up the udev callback */
   528     if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
   529         SDL_UDEV_Quit();
   530         return SDL_SetError("Could not set up joystick <-> udev callback");
   531     }
   532 
   533     /* Force a scan to build the initial device list */
   534     SDL_UDEV_Scan();
   535 #else
   536     /* Force immediate joystick detection */
   537     last_joy_detect_time = 0;
   538     last_input_dir_mtime = 0;
   539 
   540     /* Report all devices currently present */
   541     LINUX_JoystickDetect();
   542 #endif
   543 
   544     return 0;
   545 }
   546 
   547 static int
   548 LINUX_JoystickGetCount(void)
   549 {
   550     return numjoysticks;
   551 }
   552 
   553 static SDL_joylist_item *
   554 JoystickByDevIndex(int device_index)
   555 {
   556     SDL_joylist_item *item = SDL_joylist;
   557 
   558     if ((device_index < 0) || (device_index >= numjoysticks)) {
   559         return NULL;
   560     }
   561 
   562     while (device_index > 0) {
   563         SDL_assert(item != NULL);
   564         device_index--;
   565         item = item->next;
   566     }
   567 
   568     return item;
   569 }
   570 
   571 /* Function to get the device-dependent name of a joystick */
   572 static const char *
   573 LINUX_JoystickGetDeviceName(int device_index)
   574 {
   575     return JoystickByDevIndex(device_index)->name;
   576 }
   577 
   578 static int
   579 LINUX_JoystickGetDevicePlayerIndex(int device_index)
   580 {
   581     return -1;
   582 }
   583 
   584 static void
   585 LINUX_JoystickSetDevicePlayerIndex(int device_index, int player_index)
   586 {
   587 }
   588 
   589 static SDL_JoystickGUID
   590 LINUX_JoystickGetDeviceGUID( int device_index )
   591 {
   592     return JoystickByDevIndex(device_index)->guid;
   593 }
   594 
   595 /* Function to perform the mapping from device index to the instance id for this index */
   596 static SDL_JoystickID
   597 LINUX_JoystickGetDeviceInstanceID(int device_index)
   598 {
   599     return JoystickByDevIndex(device_index)->device_instance;
   600 }
   601 
   602 static int
   603 allocate_hatdata(SDL_Joystick * joystick)
   604 {
   605     int i;
   606 
   607     joystick->hwdata->hats =
   608         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   609                                          sizeof(struct hwdata_hat));
   610     if (joystick->hwdata->hats == NULL) {
   611         return (-1);
   612     }
   613     for (i = 0; i < joystick->nhats; ++i) {
   614         joystick->hwdata->hats[i].axis[0] = 1;
   615         joystick->hwdata->hats[i].axis[1] = 1;
   616     }
   617     return (0);
   618 }
   619 
   620 static int
   621 allocate_balldata(SDL_Joystick * joystick)
   622 {
   623     int i;
   624 
   625     joystick->hwdata->balls =
   626         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   627                                           sizeof(struct hwdata_ball));
   628     if (joystick->hwdata->balls == NULL) {
   629         return (-1);
   630     }
   631     for (i = 0; i < joystick->nballs; ++i) {
   632         joystick->hwdata->balls[i].axis[0] = 0;
   633         joystick->hwdata->balls[i].axis[1] = 0;
   634     }
   635     return (0);
   636 }
   637 
   638 static void
   639 ConfigJoystick(SDL_Joystick * joystick, int fd)
   640 {
   641     int i, t;
   642     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   643     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   644     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   645     unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
   646 
   647     /* See if this device uses the new unified event API */
   648     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   649         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   650         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   651 
   652         /* Get the number of buttons, axes, and other thingamajigs */
   653         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
   654             if (test_bit(i, keybit)) {
   655 #ifdef DEBUG_INPUT_EVENTS
   656                 printf("Joystick has button: 0x%x\n", i);
   657 #endif
   658                 joystick->hwdata->key_map[i] = joystick->nbuttons;
   659                 ++joystick->nbuttons;
   660             }
   661         }
   662         for (i = 0; i < BTN_JOYSTICK; ++i) {
   663             if (test_bit(i, keybit)) {
   664 #ifdef DEBUG_INPUT_EVENTS
   665                 printf("Joystick has button: 0x%x\n", i);
   666 #endif
   667                 joystick->hwdata->key_map[i] = joystick->nbuttons;
   668                 ++joystick->nbuttons;
   669             }
   670         }
   671         for (i = 0; i < ABS_MAX; ++i) {
   672             /* Skip hats */
   673             if (i == ABS_HAT0X) {
   674                 i = ABS_HAT3Y;
   675                 continue;
   676             }
   677             if (test_bit(i, absbit)) {
   678                 struct input_absinfo absinfo;
   679 
   680                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   681                     continue;
   682                 }
   683 #ifdef DEBUG_INPUT_EVENTS
   684                 printf("Joystick has absolute axis: 0x%.2x\n", i);
   685                 printf("Values = { %d, %d, %d, %d, %d }\n",
   686                        absinfo.value, absinfo.minimum, absinfo.maximum,
   687                        absinfo.fuzz, absinfo.flat);
   688 #endif /* DEBUG_INPUT_EVENTS */
   689                 joystick->hwdata->abs_map[i] = joystick->naxes;
   690                 if (absinfo.minimum == absinfo.maximum) {
   691                     joystick->hwdata->abs_correct[i].used = 0;
   692                 } else {
   693                     joystick->hwdata->abs_correct[i].used = 1;
   694                     joystick->hwdata->abs_correct[i].coef[0] =
   695                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   696                     joystick->hwdata->abs_correct[i].coef[1] =
   697                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   698                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   699                     if (t != 0) {
   700                         joystick->hwdata->abs_correct[i].coef[2] =
   701                             (1 << 28) / t;
   702                     } else {
   703                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   704                     }
   705                 }
   706                 ++joystick->naxes;
   707             }
   708         }
   709         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   710             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   711                 struct input_absinfo absinfo;
   712                 int hat_index = (i - ABS_HAT0X) / 2;
   713 
   714                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   715                     continue;
   716                 }
   717 #ifdef DEBUG_INPUT_EVENTS
   718                 printf("Joystick has hat %d\n", hat_index);
   719                 printf("Values = { %d, %d, %d, %d, %d }\n",
   720                        absinfo.value, absinfo.minimum, absinfo.maximum,
   721                        absinfo.fuzz, absinfo.flat);
   722 #endif /* DEBUG_INPUT_EVENTS */
   723                 joystick->hwdata->hats_indices[hat_index] = joystick->nhats++;
   724             }
   725         }
   726         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   727             ++joystick->nballs;
   728         }
   729 
   730         /* Allocate data to keep track of these thingamajigs */
   731         if (joystick->nhats > 0) {
   732             if (allocate_hatdata(joystick) < 0) {
   733                 joystick->nhats = 0;
   734             }
   735         }
   736         if (joystick->nballs > 0) {
   737             if (allocate_balldata(joystick) < 0) {
   738                 joystick->nballs = 0;
   739             }
   740         }
   741     }
   742 
   743     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
   744         if (test_bit(FF_RUMBLE, ffbit)) {
   745             joystick->hwdata->ff_rumble = SDL_TRUE;
   746         }
   747         if (test_bit(FF_SINE, ffbit)) {
   748             joystick->hwdata->ff_sine = SDL_TRUE;
   749         }
   750     }
   751 }
   752 
   753 
   754 /* Function to open a joystick for use.
   755    The joystick to open is specified by the device index.
   756    This should fill the nbuttons and naxes fields of the joystick structure.
   757    It returns 0, or -1 if there is an error.
   758  */
   759 static int
   760 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
   761 {
   762     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   763 
   764     if (item == NULL) {
   765         return SDL_SetError("No such device");
   766     }
   767 
   768     joystick->instance_id = item->device_instance;
   769     joystick->hwdata = (struct joystick_hwdata *)
   770         SDL_calloc(1, sizeof(*joystick->hwdata));
   771     if (joystick->hwdata == NULL) {
   772         return SDL_OutOfMemory();
   773     }
   774     joystick->hwdata->item = item;
   775     joystick->hwdata->guid = item->guid;
   776     joystick->hwdata->effect.id = -1;
   777     joystick->hwdata->m_bSteamController = item->m_bSteamController;
   778     SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
   779 
   780     if (item->m_bSteamController) {
   781         joystick->hwdata->fd = -1;
   782         SDL_GetSteamControllerInputs(&joystick->nbuttons,
   783                                      &joystick->naxes,
   784                                      &joystick->nhats);
   785     } else {
   786         int fd = open(item->path, O_RDWR, 0);
   787         if (fd < 0) {
   788             SDL_free(joystick->hwdata);
   789             joystick->hwdata = NULL;
   790             return SDL_SetError("Unable to open %s", item->path);
   791         }
   792 
   793         joystick->hwdata->fd = fd;
   794         joystick->hwdata->fname = SDL_strdup(item->path);
   795         if (joystick->hwdata->fname == NULL) {
   796             SDL_free(joystick->hwdata);
   797             joystick->hwdata = NULL;
   798             close(fd);
   799             return SDL_OutOfMemory();
   800         }
   801 
   802         /* Set the joystick to non-blocking read mode */
   803         fcntl(fd, F_SETFL, O_NONBLOCK);
   804 
   805         /* Get the number of buttons and axes on the joystick */
   806         ConfigJoystick(joystick, fd);
   807     }
   808 
   809     SDL_assert(item->hwdata == NULL);
   810     item->hwdata = joystick->hwdata;
   811 
   812     /* mark joystick as fresh and ready */
   813     joystick->hwdata->fresh = 1;
   814 
   815     return (0);
   816 }
   817 
   818 static int
   819 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   820 {
   821     struct input_event event;
   822 
   823     if (joystick->hwdata->ff_rumble) {
   824         struct ff_effect *effect = &joystick->hwdata->effect;
   825 
   826         effect->type = FF_RUMBLE;
   827         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
   828         effect->u.rumble.strong_magnitude = low_frequency_rumble;
   829         effect->u.rumble.weak_magnitude = high_frequency_rumble;
   830     } else if (joystick->hwdata->ff_sine) {
   831         /* Scale and average the two rumble strengths */
   832         Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
   833         struct ff_effect *effect = &joystick->hwdata->effect;
   834 
   835         effect->type = FF_PERIODIC;
   836         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
   837         effect->u.periodic.waveform = FF_SINE;
   838         effect->u.periodic.magnitude = magnitude;
   839     } else {
   840         return SDL_Unsupported();
   841     }
   842 
   843     if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   844         /* The kernel may have lost this effect, try to allocate a new one */
   845         joystick->hwdata->effect.id = -1;
   846         if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   847             return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
   848         }
   849     }
   850 
   851     event.type = EV_FF;
   852     event.code = joystick->hwdata->effect.id;
   853     event.value = 1;
   854     if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
   855         return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
   856     }
   857     return 0;
   858 }
   859 
   860 static SDL_INLINE void
   861 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   862 {
   863     struct hwdata_hat *the_hat;
   864     const Uint8 position_map[3][3] = {
   865         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   866         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   867         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   868     };
   869 
   870     the_hat = &stick->hwdata->hats[hat];
   871     if (value < 0) {
   872         value = 0;
   873     } else if (value == 0) {
   874         value = 1;
   875     } else if (value > 0) {
   876         value = 2;
   877     }
   878     if (value != the_hat->axis[axis]) {
   879         the_hat->axis[axis] = value;
   880         SDL_PrivateJoystickHat(stick, hat,
   881                                position_map[the_hat->axis[1]][the_hat->axis[0]]);
   882     }
   883 }
   884 
   885 static SDL_INLINE void
   886 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   887 {
   888     stick->hwdata->balls[ball].axis[axis] += value;
   889 }
   890 
   891 
   892 static SDL_INLINE int
   893 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   894 {
   895     struct axis_correct *correct;
   896 
   897     correct = &joystick->hwdata->abs_correct[which];
   898     if (correct->used) {
   899         value *= 2;
   900         if (value > correct->coef[0]) {
   901             if (value < correct->coef[1]) {
   902                 return 0;
   903             }
   904             value -= correct->coef[1];
   905         } else {
   906             value -= correct->coef[0];
   907         }
   908         value *= correct->coef[2];
   909         value >>= 13;
   910     }
   911 
   912     /* Clamp and return */
   913     if (value < -32768)
   914         return -32768;
   915     if (value > 32767)
   916         return 32767;
   917 
   918     return value;
   919 }
   920 
   921 static SDL_INLINE void
   922 PollAllValues(SDL_Joystick * joystick)
   923 {
   924     struct input_absinfo absinfo;
   925     int i;
   926 
   927     /* Poll all axis */
   928     for (i = ABS_X; i < ABS_MAX; i++) {
   929         if (i == ABS_HAT0X) {
   930             i = ABS_HAT3Y;
   931             continue;
   932         }
   933         if (joystick->hwdata->abs_correct[i].used) {
   934             if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
   935                 absinfo.value = AxisCorrect(joystick, i, absinfo.value);
   936 
   937 #ifdef DEBUG_INPUT_EVENTS
   938                 printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   939                     joystick->hwdata->abs_map[i], i, absinfo.value);
   940 #endif
   941                 SDL_PrivateJoystickAxis(joystick,
   942                         joystick->hwdata->abs_map[i],
   943                         absinfo.value);
   944             }
   945         }
   946     }
   947 }
   948 
   949 static SDL_INLINE void
   950 HandleInputEvents(SDL_Joystick * joystick)
   951 {
   952     struct input_event events[32];
   953     int i, len;
   954     int code;
   955 
   956     if (joystick->hwdata->fresh) {
   957         PollAllValues(joystick);
   958         joystick->hwdata->fresh = 0;
   959     }
   960 
   961     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   962         len /= sizeof(events[0]);
   963         for (i = 0; i < len; ++i) {
   964             code = events[i].code;
   965             switch (events[i].type) {
   966             case EV_KEY:
   967                 SDL_PrivateJoystickButton(joystick,
   968                                           joystick->hwdata->key_map[code],
   969                                           events[i].value);
   970                 break;
   971             case EV_ABS:
   972                 switch (code) {
   973                 case ABS_HAT0X:
   974                 case ABS_HAT0Y:
   975                 case ABS_HAT1X:
   976                 case ABS_HAT1Y:
   977                 case ABS_HAT2X:
   978                 case ABS_HAT2Y:
   979                 case ABS_HAT3X:
   980                 case ABS_HAT3Y:
   981                     code -= ABS_HAT0X;
   982                     HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
   983                     break;
   984                 default:
   985                     if (joystick->hwdata->abs_map[code] != 0xFF) {
   986                         events[i].value =
   987                             AxisCorrect(joystick, code, events[i].value);
   988                         SDL_PrivateJoystickAxis(joystick,
   989                                                 joystick->hwdata->abs_map[code],
   990                                                 events[i].value);
   991                     }
   992                     break;
   993                 }
   994                 break;
   995             case EV_REL:
   996                 switch (code) {
   997                 case REL_X:
   998                 case REL_Y:
   999                     code -= REL_X;
  1000                     HandleBall(joystick, code / 2, code % 2, events[i].value);
  1001                     break;
  1002                 default:
  1003                     break;
  1004                 }
  1005                 break;
  1006             case EV_SYN:
  1007                 switch (code) {
  1008                 case SYN_DROPPED :
  1009 #ifdef DEBUG_INPUT_EVENTS
  1010                     printf("Event SYN_DROPPED detected\n");
  1011 #endif
  1012                     PollAllValues(joystick);
  1013                     break;
  1014                 default:
  1015                     break;
  1016                 }
  1017             default:
  1018                 break;
  1019             }
  1020         }
  1021     }
  1022 
  1023     if (errno == ENODEV) {
  1024         /* We have to wait until the JoystickDetect callback to remove this */
  1025         joystick->hwdata->gone = SDL_TRUE;
  1026     }
  1027 }
  1028 
  1029 static void
  1030 LINUX_JoystickUpdate(SDL_Joystick * joystick)
  1031 {
  1032     int i;
  1033 
  1034     if (joystick->hwdata->m_bSteamController) {
  1035         SDL_UpdateSteamController(joystick);
  1036         return;
  1037     }
  1038 
  1039     HandleInputEvents(joystick);
  1040 
  1041     /* Deliver ball motion updates */
  1042     for (i = 0; i < joystick->nballs; ++i) {
  1043         int xrel, yrel;
  1044 
  1045         xrel = joystick->hwdata->balls[i].axis[0];
  1046         yrel = joystick->hwdata->balls[i].axis[1];
  1047         if (xrel || yrel) {
  1048             joystick->hwdata->balls[i].axis[0] = 0;
  1049             joystick->hwdata->balls[i].axis[1] = 0;
  1050             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
  1051         }
  1052     }
  1053 }
  1054 
  1055 /* Function to close a joystick after use */
  1056 static void
  1057 LINUX_JoystickClose(SDL_Joystick * joystick)
  1058 {
  1059     if (joystick->hwdata) {
  1060         if (joystick->hwdata->effect.id >= 0) {
  1061             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
  1062             joystick->hwdata->effect.id = -1;
  1063         }
  1064         if (joystick->hwdata->fd >= 0) {
  1065             close(joystick->hwdata->fd);
  1066         }
  1067         if (joystick->hwdata->item) {
  1068             joystick->hwdata->item->hwdata = NULL;
  1069         }
  1070         SDL_free(joystick->hwdata->hats);
  1071         SDL_free(joystick->hwdata->balls);
  1072         SDL_free(joystick->hwdata->fname);
  1073         SDL_free(joystick->hwdata);
  1074     }
  1075 }
  1076 
  1077 /* Function to perform any system-specific joystick related cleanup */
  1078 static void
  1079 LINUX_JoystickQuit(void)
  1080 {
  1081     SDL_joylist_item *item = NULL;
  1082     SDL_joylist_item *next = NULL;
  1083 
  1084     for (item = SDL_joylist; item; item = next) {
  1085         next = item->next;
  1086         SDL_free(item->path);
  1087         SDL_free(item->name);
  1088         SDL_free(item);
  1089     }
  1090 
  1091     SDL_joylist = SDL_joylist_tail = NULL;
  1092 
  1093     numjoysticks = 0;
  1094 
  1095 #if SDL_USE_LIBUDEV
  1096     SDL_UDEV_DelCallback(joystick_udev_callback);
  1097     SDL_UDEV_Quit();
  1098 #endif
  1099 
  1100     SDL_QuitSteamControllers();
  1101 }
  1102 
  1103 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
  1104 {
  1105     LINUX_JoystickInit,
  1106     LINUX_JoystickGetCount,
  1107     LINUX_JoystickDetect,
  1108     LINUX_JoystickGetDeviceName,
  1109     LINUX_JoystickGetDevicePlayerIndex,
  1110     LINUX_JoystickSetDevicePlayerIndex,
  1111     LINUX_JoystickGetDeviceGUID,
  1112     LINUX_JoystickGetDeviceInstanceID,
  1113     LINUX_JoystickOpen,
  1114     LINUX_JoystickRumble,
  1115     LINUX_JoystickUpdate,
  1116     LINUX_JoystickClose,
  1117     LINUX_JoystickQuit,
  1118 };
  1119 
  1120 #endif /* SDL_JOYSTICK_LINUX */
  1121 
  1122 /* vi: set ts=4 sw=4 expandtab: */