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