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