src/joystick/linux/SDL_sysjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Wed, 05 Dec 2018 19:03:15 -0500
changeset 12461 14205d7f7715
parent 12459 34266b6e578d
child 12503 806492103856
permissions -rw-r--r--
joystick: Removed unused variable.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2018 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 
   613                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   614                     continue;
   615                 }
   616 #ifdef DEBUG_INPUT_EVENTS
   617                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   618                 printf("Values = { %d, %d, %d, %d, %d }\n",
   619                        absinfo.value, absinfo.minimum, absinfo.maximum,
   620                        absinfo.fuzz, absinfo.flat);
   621 #endif /* DEBUG_INPUT_EVENTS */
   622                 ++joystick->nhats;
   623             }
   624         }
   625         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   626             ++joystick->nballs;
   627         }
   628 
   629         /* Allocate data to keep track of these thingamajigs */
   630         if (joystick->nhats > 0) {
   631             if (allocate_hatdata(joystick) < 0) {
   632                 joystick->nhats = 0;
   633             }
   634         }
   635         if (joystick->nballs > 0) {
   636             if (allocate_balldata(joystick) < 0) {
   637                 joystick->nballs = 0;
   638             }
   639         }
   640     }
   641 
   642     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
   643         if (test_bit(FF_RUMBLE, ffbit)) {
   644             joystick->hwdata->ff_rumble = SDL_TRUE;
   645         }
   646         if (test_bit(FF_SINE, ffbit)) {
   647             joystick->hwdata->ff_sine = SDL_TRUE;
   648         }
   649     }
   650 }
   651 
   652 
   653 /* Function to open a joystick for use.
   654    The joystick to open is specified by the device index.
   655    This should fill the nbuttons and naxes fields of the joystick structure.
   656    It returns 0, or -1 if there is an error.
   657  */
   658 static int
   659 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
   660 {
   661     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   662 
   663     if (item == NULL) {
   664         return SDL_SetError("No such device");
   665     }
   666 
   667     joystick->instance_id = item->device_instance;
   668     joystick->hwdata = (struct joystick_hwdata *)
   669         SDL_calloc(1, sizeof(*joystick->hwdata));
   670     if (joystick->hwdata == NULL) {
   671         return SDL_OutOfMemory();
   672     }
   673     joystick->hwdata->item = item;
   674     joystick->hwdata->guid = item->guid;
   675     joystick->hwdata->effect.id = -1;
   676     joystick->hwdata->m_bSteamController = item->m_bSteamController;
   677     SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
   678 
   679     if (item->m_bSteamController) {
   680         joystick->hwdata->fd = -1;
   681         SDL_GetSteamControllerInputs(&joystick->nbuttons,
   682                                      &joystick->naxes,
   683                                      &joystick->nhats);
   684     } else {
   685         int fd = open(item->path, O_RDWR, 0);
   686         if (fd < 0) {
   687             SDL_free(joystick->hwdata);
   688             joystick->hwdata = NULL;
   689             return SDL_SetError("Unable to open %s", item->path);
   690         }
   691 
   692         joystick->hwdata->fd = fd;
   693         joystick->hwdata->fname = SDL_strdup(item->path);
   694         if (joystick->hwdata->fname == NULL) {
   695             SDL_free(joystick->hwdata);
   696             joystick->hwdata = NULL;
   697             close(fd);
   698             return SDL_OutOfMemory();
   699         }
   700 
   701         /* Set the joystick to non-blocking read mode */
   702         fcntl(fd, F_SETFL, O_NONBLOCK);
   703 
   704         /* Get the number of buttons and axes on the joystick */
   705         ConfigJoystick(joystick, fd);
   706     }
   707 
   708     SDL_assert(item->hwdata == NULL);
   709     item->hwdata = joystick->hwdata;
   710 
   711     /* mark joystick as fresh and ready */
   712     joystick->hwdata->fresh = 1;
   713 
   714     return (0);
   715 }
   716 
   717 static int
   718 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   719 {
   720     struct input_event event;
   721 
   722     if (joystick->hwdata->ff_rumble) {
   723         struct ff_effect *effect = &joystick->hwdata->effect;
   724 
   725         effect->type = FF_RUMBLE;
   726         effect->replay.length = SDL_min(duration_ms, 32767);
   727         effect->u.rumble.strong_magnitude = low_frequency_rumble;
   728         effect->u.rumble.weak_magnitude = high_frequency_rumble;
   729     } else if (joystick->hwdata->ff_sine) {
   730         /* Scale and average the two rumble strengths */
   731         Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
   732         struct ff_effect *effect = &joystick->hwdata->effect;
   733 
   734         effect->type = FF_PERIODIC;
   735         effect->replay.length = SDL_min(duration_ms, 32767);
   736         effect->u.periodic.waveform = FF_SINE;
   737         effect->u.periodic.magnitude = magnitude;
   738     } else {
   739         return SDL_Unsupported();
   740     }
   741 
   742     if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   743         return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
   744     }
   745 
   746     event.type = EV_FF;
   747     event.code = joystick->hwdata->effect.id;
   748     event.value = 1;
   749     if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
   750         return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
   751     }
   752     return 0;
   753 }
   754 
   755 static SDL_INLINE void
   756 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   757 {
   758     struct hwdata_hat *the_hat;
   759     const Uint8 position_map[3][3] = {
   760         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   761         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   762         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   763     };
   764 
   765     the_hat = &stick->hwdata->hats[hat];
   766     if (value < 0) {
   767         value = 0;
   768     } else if (value == 0) {
   769         value = 1;
   770     } else if (value > 0) {
   771         value = 2;
   772     }
   773     if (value != the_hat->axis[axis]) {
   774         the_hat->axis[axis] = value;
   775         SDL_PrivateJoystickHat(stick, hat,
   776                                position_map[the_hat->
   777                                             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 a, b = 0;
   822 
   823     /* Poll all axis */
   824     for (a = ABS_X; b < ABS_MAX; a++) {
   825         switch (a) {
   826         case ABS_HAT0X:
   827         case ABS_HAT0Y:
   828         case ABS_HAT1X:
   829         case ABS_HAT1Y:
   830         case ABS_HAT2X:
   831         case ABS_HAT2Y:
   832         case ABS_HAT3X:
   833         case ABS_HAT3Y:
   834             /* ingore hats */
   835             break;
   836         default:
   837             if (joystick->hwdata->abs_correct[b].used) {
   838                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   839                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   840 
   841 #ifdef DEBUG_INPUT_EVENTS
   842                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   843                         joystick->hwdata->abs_map[b], a, absinfo.value);
   844 #endif
   845                     SDL_PrivateJoystickAxis(joystick,
   846                             joystick->hwdata->abs_map[b],
   847                             absinfo.value);
   848                 }
   849             }
   850             b++;
   851         }
   852     }
   853 }
   854 
   855 static SDL_INLINE void
   856 HandleInputEvents(SDL_Joystick * joystick)
   857 {
   858     struct input_event events[32];
   859     int i, len;
   860     int code;
   861 
   862     if (joystick->hwdata->fresh) {
   863         PollAllValues(joystick);
   864         joystick->hwdata->fresh = 0;
   865     }
   866 
   867     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   868         len /= sizeof(events[0]);
   869         for (i = 0; i < len; ++i) {
   870             code = events[i].code;
   871             switch (events[i].type) {
   872             case EV_KEY:
   873                 SDL_PrivateJoystickButton(joystick,
   874                                           joystick->hwdata->key_map[code],
   875                                           events[i].value);
   876                 break;
   877             case EV_ABS:
   878                 switch (code) {
   879                 case ABS_HAT0X:
   880                 case ABS_HAT0Y:
   881                 case ABS_HAT1X:
   882                 case ABS_HAT1Y:
   883                 case ABS_HAT2X:
   884                 case ABS_HAT2Y:
   885                 case ABS_HAT3X:
   886                 case ABS_HAT3Y:
   887                     code -= ABS_HAT0X;
   888                     HandleHat(joystick, code / 2, code % 2, events[i].value);
   889                     break;
   890                 default:
   891                     if (joystick->hwdata->abs_map[code] != 0xFF) {
   892                         events[i].value =
   893                             AxisCorrect(joystick, code, events[i].value);
   894                         SDL_PrivateJoystickAxis(joystick,
   895                                                 joystick->hwdata->abs_map[code],
   896                                                 events[i].value);
   897                     }
   898                     break;
   899                 }
   900                 break;
   901             case EV_REL:
   902                 switch (code) {
   903                 case REL_X:
   904                 case REL_Y:
   905                     code -= REL_X;
   906                     HandleBall(joystick, code / 2, code % 2, events[i].value);
   907                     break;
   908                 default:
   909                     break;
   910                 }
   911                 break;
   912             case EV_SYN:
   913                 switch (code) {
   914                 case SYN_DROPPED :
   915 #ifdef DEBUG_INPUT_EVENTS
   916                     printf("Event SYN_DROPPED detected\n");
   917 #endif
   918                     PollAllValues(joystick);
   919                     break;
   920                 default:
   921                     break;
   922                 }
   923             default:
   924                 break;
   925             }
   926         }
   927     }
   928 }
   929 
   930 static void
   931 LINUX_JoystickUpdate(SDL_Joystick * joystick)
   932 {
   933     int i;
   934 
   935     if (joystick->hwdata->m_bSteamController) {
   936         SDL_UpdateSteamController(joystick);
   937         return;
   938     }
   939 
   940     HandleInputEvents(joystick);
   941 
   942     /* Deliver ball motion updates */
   943     for (i = 0; i < joystick->nballs; ++i) {
   944         int xrel, yrel;
   945 
   946         xrel = joystick->hwdata->balls[i].axis[0];
   947         yrel = joystick->hwdata->balls[i].axis[1];
   948         if (xrel || yrel) {
   949             joystick->hwdata->balls[i].axis[0] = 0;
   950             joystick->hwdata->balls[i].axis[1] = 0;
   951             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
   952         }
   953     }
   954 }
   955 
   956 /* Function to close a joystick after use */
   957 static void
   958 LINUX_JoystickClose(SDL_Joystick * joystick)
   959 {
   960     if (joystick->hwdata) {
   961         if (joystick->hwdata->effect.id >= 0) {
   962             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
   963             joystick->hwdata->effect.id = -1;
   964         }
   965         if (joystick->hwdata->fd >= 0) {
   966             close(joystick->hwdata->fd);
   967         }
   968         if (joystick->hwdata->item) {
   969             joystick->hwdata->item->hwdata = NULL;
   970         }
   971         SDL_free(joystick->hwdata->hats);
   972         SDL_free(joystick->hwdata->balls);
   973         SDL_free(joystick->hwdata->fname);
   974         SDL_free(joystick->hwdata);
   975     }
   976 }
   977 
   978 /* Function to perform any system-specific joystick related cleanup */
   979 static void
   980 LINUX_JoystickQuit(void)
   981 {
   982     SDL_joylist_item *item = NULL;
   983     SDL_joylist_item *next = NULL;
   984 
   985     for (item = SDL_joylist; item; item = next) {
   986         next = item->next;
   987         SDL_free(item->path);
   988         SDL_free(item->name);
   989         SDL_free(item);
   990     }
   991 
   992     SDL_joylist = SDL_joylist_tail = NULL;
   993 
   994     numjoysticks = 0;
   995 
   996 #if SDL_USE_LIBUDEV
   997     SDL_UDEV_DelCallback(joystick_udev_callback);
   998     SDL_UDEV_Quit();
   999 #endif
  1000 
  1001     SDL_QuitSteamControllers();
  1002 }
  1003 
  1004 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
  1005 {
  1006     LINUX_JoystickInit,
  1007     LINUX_JoystickGetCount,
  1008     LINUX_JoystickDetect,
  1009     LINUX_JoystickGetDeviceName,
  1010     LINUX_JoystickGetDevicePlayerIndex,
  1011     LINUX_JoystickGetDeviceGUID,
  1012     LINUX_JoystickGetDeviceInstanceID,
  1013     LINUX_JoystickOpen,
  1014     LINUX_JoystickRumble,
  1015     LINUX_JoystickUpdate,
  1016     LINUX_JoystickClose,
  1017     LINUX_JoystickQuit,
  1018 };
  1019 
  1020 #endif /* SDL_JOYSTICK_LINUX */
  1021 
  1022 /* vi: set ts=4 sw=4 expandtab: */