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