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