src/joystick/linux/SDL_sysjoystick.c
author Sylvain Becker <sylvain.becker@gmail.com>
Mon, 24 Feb 2020 21:57:03 +0100
changeset 13551 4efb3eb7a3b3
parent 13480 6a144eb5e1f1
permissions -rw-r--r--
Better fix to set the palette opaque, when there is also a colorkey
(see bug 3827)
     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[hat_index] = joystick->nhats++;
   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 static int
   826 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble)
   827 {
   828     struct input_event event;
   829 
   830     if (joystick->hwdata->ff_rumble) {
   831         struct ff_effect *effect = &joystick->hwdata->effect;
   832 
   833         effect->type = FF_RUMBLE;
   834         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
   835         effect->u.rumble.strong_magnitude = low_frequency_rumble;
   836         effect->u.rumble.weak_magnitude = high_frequency_rumble;
   837     } else if (joystick->hwdata->ff_sine) {
   838         /* Scale and average the two rumble strengths */
   839         Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
   840         struct ff_effect *effect = &joystick->hwdata->effect;
   841 
   842         effect->type = FF_PERIODIC;
   843         effect->replay.length = SDL_MAX_RUMBLE_DURATION_MS;
   844         effect->u.periodic.waveform = FF_SINE;
   845         effect->u.periodic.magnitude = magnitude;
   846     } else {
   847         return SDL_Unsupported();
   848     }
   849 
   850     if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   851         /* The kernel may have lost this effect, try to allocate a new one */
   852         joystick->hwdata->effect.id = -1;
   853         if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   854             return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
   855         }
   856     }
   857 
   858     event.type = EV_FF;
   859     event.code = joystick->hwdata->effect.id;
   860     event.value = 1;
   861     if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
   862         return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
   863     }
   864     return 0;
   865 }
   866 
   867 static SDL_INLINE void
   868 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   869 {
   870     struct hwdata_hat *the_hat;
   871     const Uint8 position_map[3][3] = {
   872         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   873         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   874         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   875     };
   876 
   877     the_hat = &stick->hwdata->hats[hat];
   878     if (value < 0) {
   879         value = 0;
   880     } else if (value == 0) {
   881         value = 1;
   882     } else if (value > 0) {
   883         value = 2;
   884     }
   885     if (value != the_hat->axis[axis]) {
   886         the_hat->axis[axis] = value;
   887         SDL_PrivateJoystickHat(stick, hat,
   888                                position_map[the_hat->axis[1]][the_hat->axis[0]]);
   889     }
   890 }
   891 
   892 static SDL_INLINE void
   893 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   894 {
   895     stick->hwdata->balls[ball].axis[axis] += value;
   896 }
   897 
   898 
   899 static SDL_INLINE int
   900 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   901 {
   902     struct axis_correct *correct;
   903 
   904     correct = &joystick->hwdata->abs_correct[which];
   905     if (correct->used) {
   906         value *= 2;
   907         if (value > correct->coef[0]) {
   908             if (value < correct->coef[1]) {
   909                 return 0;
   910             }
   911             value -= correct->coef[1];
   912         } else {
   913             value -= correct->coef[0];
   914         }
   915         value *= correct->coef[2];
   916         value >>= 13;
   917     }
   918 
   919     /* Clamp and return */
   920     if (value < -32768)
   921         return -32768;
   922     if (value > 32767)
   923         return 32767;
   924 
   925     return value;
   926 }
   927 
   928 static SDL_INLINE void
   929 PollAllValues(SDL_Joystick * joystick)
   930 {
   931     struct input_absinfo absinfo;
   932     int i;
   933 
   934     /* Poll all axis */
   935     for (i = ABS_X; i < ABS_MAX; i++) {
   936         if (i == ABS_HAT0X) {
   937             i = ABS_HAT3Y;
   938             continue;
   939         }
   940         if (joystick->hwdata->abs_correct[i].used) {
   941             if (ioctl(joystick->hwdata->fd, EVIOCGABS(i), &absinfo) >= 0) {
   942                 absinfo.value = AxisCorrect(joystick, i, absinfo.value);
   943 
   944 #ifdef DEBUG_INPUT_EVENTS
   945                 printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   946                     joystick->hwdata->abs_map[i], i, absinfo.value);
   947 #endif
   948                 SDL_PrivateJoystickAxis(joystick,
   949                         joystick->hwdata->abs_map[i],
   950                         absinfo.value);
   951             }
   952         }
   953     }
   954 }
   955 
   956 static SDL_INLINE void
   957 HandleInputEvents(SDL_Joystick * joystick)
   958 {
   959     struct input_event events[32];
   960     int i, len;
   961     int code;
   962 
   963     if (joystick->hwdata->fresh) {
   964         PollAllValues(joystick);
   965         joystick->hwdata->fresh = 0;
   966     }
   967 
   968     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   969         len /= sizeof(events[0]);
   970         for (i = 0; i < len; ++i) {
   971             code = events[i].code;
   972             switch (events[i].type) {
   973             case EV_KEY:
   974                 SDL_PrivateJoystickButton(joystick,
   975                                           joystick->hwdata->key_map[code],
   976                                           events[i].value);
   977                 break;
   978             case EV_ABS:
   979                 switch (code) {
   980                 case ABS_HAT0X:
   981                 case ABS_HAT0Y:
   982                 case ABS_HAT1X:
   983                 case ABS_HAT1Y:
   984                 case ABS_HAT2X:
   985                 case ABS_HAT2Y:
   986                 case ABS_HAT3X:
   987                 case ABS_HAT3Y:
   988                     code -= ABS_HAT0X;
   989                     HandleHat(joystick, joystick->hwdata->hats_indices[code / 2], code % 2, events[i].value);
   990                     break;
   991                 default:
   992                     if (joystick->hwdata->abs_map[code] != 0xFF) {
   993                         events[i].value =
   994                             AxisCorrect(joystick, code, events[i].value);
   995                         SDL_PrivateJoystickAxis(joystick,
   996                                                 joystick->hwdata->abs_map[code],
   997                                                 events[i].value);
   998                     }
   999                     break;
  1000                 }
  1001                 break;
  1002             case EV_REL:
  1003                 switch (code) {
  1004                 case REL_X:
  1005                 case REL_Y:
  1006                     code -= REL_X;
  1007                     HandleBall(joystick, code / 2, code % 2, events[i].value);
  1008                     break;
  1009                 default:
  1010                     break;
  1011                 }
  1012                 break;
  1013             case EV_SYN:
  1014                 switch (code) {
  1015                 case SYN_DROPPED :
  1016 #ifdef DEBUG_INPUT_EVENTS
  1017                     printf("Event SYN_DROPPED detected\n");
  1018 #endif
  1019                     PollAllValues(joystick);
  1020                     break;
  1021                 default:
  1022                     break;
  1023                 }
  1024             default:
  1025                 break;
  1026             }
  1027         }
  1028     }
  1029 
  1030     if (errno == ENODEV) {
  1031         /* We have to wait until the JoystickDetect callback to remove this */
  1032         joystick->hwdata->gone = SDL_TRUE;
  1033     }
  1034 }
  1035 
  1036 static void
  1037 LINUX_JoystickUpdate(SDL_Joystick * joystick)
  1038 {
  1039     int i;
  1040 
  1041     if (joystick->hwdata->m_bSteamController) {
  1042         SDL_UpdateSteamController(joystick);
  1043         return;
  1044     }
  1045 
  1046     HandleInputEvents(joystick);
  1047 
  1048     /* Deliver ball motion updates */
  1049     for (i = 0; i < joystick->nballs; ++i) {
  1050         int xrel, yrel;
  1051 
  1052         xrel = joystick->hwdata->balls[i].axis[0];
  1053         yrel = joystick->hwdata->balls[i].axis[1];
  1054         if (xrel || yrel) {
  1055             joystick->hwdata->balls[i].axis[0] = 0;
  1056             joystick->hwdata->balls[i].axis[1] = 0;
  1057             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
  1058         }
  1059     }
  1060 }
  1061 
  1062 /* Function to close a joystick after use */
  1063 static void
  1064 LINUX_JoystickClose(SDL_Joystick * joystick)
  1065 {
  1066     if (joystick->hwdata) {
  1067         if (joystick->hwdata->effect.id >= 0) {
  1068             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
  1069             joystick->hwdata->effect.id = -1;
  1070         }
  1071         if (joystick->hwdata->fd >= 0) {
  1072             close(joystick->hwdata->fd);
  1073         }
  1074         if (joystick->hwdata->item) {
  1075             joystick->hwdata->item->hwdata = NULL;
  1076         }
  1077         SDL_free(joystick->hwdata->hats);
  1078         SDL_free(joystick->hwdata->balls);
  1079         SDL_free(joystick->hwdata->fname);
  1080         SDL_free(joystick->hwdata);
  1081     }
  1082 }
  1083 
  1084 /* Function to perform any system-specific joystick related cleanup */
  1085 static void
  1086 LINUX_JoystickQuit(void)
  1087 {
  1088     SDL_joylist_item *item = NULL;
  1089     SDL_joylist_item *next = NULL;
  1090 
  1091     for (item = SDL_joylist; item; item = next) {
  1092         next = item->next;
  1093         SDL_free(item->path);
  1094         SDL_free(item->name);
  1095         SDL_free(item);
  1096     }
  1097 
  1098     SDL_joylist = SDL_joylist_tail = NULL;
  1099 
  1100     numjoysticks = 0;
  1101 
  1102 #if SDL_USE_LIBUDEV
  1103     SDL_UDEV_DelCallback(joystick_udev_callback);
  1104     SDL_UDEV_Quit();
  1105 #endif
  1106 
  1107     SDL_QuitSteamControllers();
  1108 }
  1109 
  1110 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
  1111 {
  1112     LINUX_JoystickInit,
  1113     LINUX_JoystickGetCount,
  1114     LINUX_JoystickDetect,
  1115     LINUX_JoystickGetDeviceName,
  1116     LINUX_JoystickGetDevicePlayerIndex,
  1117     LINUX_JoystickSetDevicePlayerIndex,
  1118     LINUX_JoystickGetDeviceGUID,
  1119     LINUX_JoystickGetDeviceInstanceID,
  1120     LINUX_JoystickOpen,
  1121     LINUX_JoystickRumble,
  1122     LINUX_JoystickUpdate,
  1123     LINUX_JoystickClose,
  1124     LINUX_JoystickQuit,
  1125 };
  1126 
  1127 #endif /* SDL_JOYSTICK_LINUX */
  1128 
  1129 /* vi: set ts=4 sw=4 expandtab: */