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