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