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