src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Thu, 25 Oct 2018 16:53:14 -0700
changeset 12359 691c32a30fb9
parent 12333 898f03b00670
child 12410 a7ee81795c75
permissions -rw-r--r--
Generalized the XInput user index into a player index
     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 int
   586 LINUX_JoystickGetDevicePlayerIndex(int device_index)
   587 {
   588     return -1;
   589 }
   590 
   591 static SDL_JoystickGUID
   592 LINUX_JoystickGetDeviceGUID( int device_index )
   593 {
   594     return JoystickByDevIndex(device_index)->guid;
   595 }
   596 
   597 /* Function to perform the mapping from device index to the instance id for this index */
   598 static SDL_JoystickID
   599 LINUX_JoystickGetDeviceInstanceID(int device_index)
   600 {
   601     return JoystickByDevIndex(device_index)->device_instance;
   602 }
   603 
   604 static int
   605 allocate_hatdata(SDL_Joystick * joystick)
   606 {
   607     int i;
   608 
   609     joystick->hwdata->hats =
   610         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   611                                          sizeof(struct hwdata_hat));
   612     if (joystick->hwdata->hats == NULL) {
   613         return (-1);
   614     }
   615     for (i = 0; i < joystick->nhats; ++i) {
   616         joystick->hwdata->hats[i].axis[0] = 1;
   617         joystick->hwdata->hats[i].axis[1] = 1;
   618     }
   619     return (0);
   620 }
   621 
   622 static int
   623 allocate_balldata(SDL_Joystick * joystick)
   624 {
   625     int i;
   626 
   627     joystick->hwdata->balls =
   628         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   629                                           sizeof(struct hwdata_ball));
   630     if (joystick->hwdata->balls == NULL) {
   631         return (-1);
   632     }
   633     for (i = 0; i < joystick->nballs; ++i) {
   634         joystick->hwdata->balls[i].axis[0] = 0;
   635         joystick->hwdata->balls[i].axis[1] = 0;
   636     }
   637     return (0);
   638 }
   639 
   640 static void
   641 ConfigJoystick(SDL_Joystick * joystick, int fd)
   642 {
   643     int i, t;
   644     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   645     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   646     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   647     unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
   648 
   649     /* See if this device uses the new unified event API */
   650     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   651         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   652         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   653 
   654         /* Get the number of buttons, axes, and other thingamajigs */
   655         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
   656             if (test_bit(i, keybit)) {
   657 #ifdef DEBUG_INPUT_EVENTS
   658                 printf("Joystick has button: 0x%x\n", i);
   659 #endif
   660                 joystick->hwdata->key_map[i] = joystick->nbuttons;
   661                 ++joystick->nbuttons;
   662             }
   663         }
   664         for (i = 0; i < BTN_JOYSTICK; ++i) {
   665             if (test_bit(i, keybit)) {
   666 #ifdef DEBUG_INPUT_EVENTS
   667                 printf("Joystick has button: 0x%x\n", i);
   668 #endif
   669                 joystick->hwdata->key_map[i] = joystick->nbuttons;
   670                 ++joystick->nbuttons;
   671             }
   672         }
   673         for (i = 0; i < ABS_MAX; ++i) {
   674             /* Skip hats */
   675             if (i == ABS_HAT0X) {
   676                 i = ABS_HAT3Y;
   677                 continue;
   678             }
   679             if (test_bit(i, absbit)) {
   680                 struct input_absinfo absinfo;
   681 
   682                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   683                     continue;
   684                 }
   685 #ifdef DEBUG_INPUT_EVENTS
   686                 printf("Joystick has absolute axis: 0x%.2x\n", i);
   687                 printf("Values = { %d, %d, %d, %d, %d }\n",
   688                        absinfo.value, absinfo.minimum, absinfo.maximum,
   689                        absinfo.fuzz, absinfo.flat);
   690 #endif /* DEBUG_INPUT_EVENTS */
   691                 joystick->hwdata->abs_map[i] = joystick->naxes;
   692                 if (absinfo.minimum == absinfo.maximum) {
   693                     joystick->hwdata->abs_correct[i].used = 0;
   694                 } else {
   695                     joystick->hwdata->abs_correct[i].used = 1;
   696                     joystick->hwdata->abs_correct[i].coef[0] =
   697                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   698                     joystick->hwdata->abs_correct[i].coef[1] =
   699                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   700                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   701                     if (t != 0) {
   702                         joystick->hwdata->abs_correct[i].coef[2] =
   703                             (1 << 28) / t;
   704                     } else {
   705                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   706                     }
   707                 }
   708                 ++joystick->naxes;
   709             }
   710         }
   711         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   712             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   713                 struct input_absinfo absinfo;
   714 
   715                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   716                     continue;
   717                 }
   718 #ifdef DEBUG_INPUT_EVENTS
   719                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   720                 printf("Values = { %d, %d, %d, %d, %d }\n",
   721                        absinfo.value, absinfo.minimum, absinfo.maximum,
   722                        absinfo.fuzz, absinfo.flat);
   723 #endif /* DEBUG_INPUT_EVENTS */
   724                 ++joystick->nhats;
   725             }
   726         }
   727         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   728             ++joystick->nballs;
   729         }
   730 
   731         /* Allocate data to keep track of these thingamajigs */
   732         if (joystick->nhats > 0) {
   733             if (allocate_hatdata(joystick) < 0) {
   734                 joystick->nhats = 0;
   735             }
   736         }
   737         if (joystick->nballs > 0) {
   738             if (allocate_balldata(joystick) < 0) {
   739                 joystick->nballs = 0;
   740             }
   741         }
   742     }
   743 
   744     if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
   745         if (test_bit(FF_RUMBLE, ffbit)) {
   746             joystick->hwdata->ff_rumble = SDL_TRUE;
   747         }
   748         if (test_bit(FF_SINE, ffbit)) {
   749             joystick->hwdata->ff_sine = SDL_TRUE;
   750         }
   751     }
   752 }
   753 
   754 
   755 /* Function to open a joystick for use.
   756    The joystick to open is specified by the device index.
   757    This should fill the nbuttons and naxes fields of the joystick structure.
   758    It returns 0, or -1 if there is an error.
   759  */
   760 static int
   761 LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
   762 {
   763     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   764 
   765     if (item == NULL) {
   766         return SDL_SetError("No such device");
   767     }
   768 
   769     joystick->instance_id = item->device_instance;
   770     joystick->hwdata = (struct joystick_hwdata *)
   771         SDL_calloc(1, sizeof(*joystick->hwdata));
   772     if (joystick->hwdata == NULL) {
   773         return SDL_OutOfMemory();
   774     }
   775     joystick->hwdata->item = item;
   776     joystick->hwdata->guid = item->guid;
   777     joystick->hwdata->effect.id = -1;
   778     joystick->hwdata->m_bSteamController = item->m_bSteamController;
   779 
   780     if (item->m_bSteamController) {
   781         joystick->hwdata->fd = -1;
   782         SDL_GetSteamControllerInputs(&joystick->nbuttons,
   783                                      &joystick->naxes,
   784                                      &joystick->nhats);
   785     } else {
   786         int fd = open(item->path, O_RDWR, 0);
   787         if (fd < 0) {
   788             SDL_free(joystick->hwdata);
   789             joystick->hwdata = NULL;
   790             return SDL_SetError("Unable to open %s", item->path);
   791         }
   792 
   793         joystick->hwdata->fd = fd;
   794         joystick->hwdata->fname = SDL_strdup(item->path);
   795         if (joystick->hwdata->fname == NULL) {
   796             SDL_free(joystick->hwdata);
   797             joystick->hwdata = NULL;
   798             close(fd);
   799             return SDL_OutOfMemory();
   800         }
   801 
   802         /* Set the joystick to non-blocking read mode */
   803         fcntl(fd, F_SETFL, O_NONBLOCK);
   804 
   805         /* Get the number of buttons and axes on the joystick */
   806         ConfigJoystick(joystick, fd);
   807     }
   808 
   809     SDL_assert(item->hwdata == NULL);
   810     item->hwdata = joystick->hwdata;
   811 
   812     /* mark joystick as fresh and ready */
   813     joystick->hwdata->fresh = 1;
   814 
   815     return (0);
   816 }
   817 
   818 static int
   819 LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
   820 {
   821     struct input_event event;
   822 
   823     if (joystick->hwdata->ff_rumble) {
   824         struct ff_effect *effect = &joystick->hwdata->effect;
   825 
   826         effect->type = FF_RUMBLE;
   827         effect->replay.length = SDL_min(duration_ms, 32767);
   828         effect->u.rumble.strong_magnitude = low_frequency_rumble;
   829         effect->u.rumble.weak_magnitude = high_frequency_rumble;
   830     } else if (joystick->hwdata->ff_sine) {
   831         /* Scale and average the two rumble strengths */
   832         Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
   833         struct ff_effect *effect = &joystick->hwdata->effect;
   834 
   835         effect->type = FF_PERIODIC;
   836         effect->replay.length = SDL_min(duration_ms, 32767);
   837         effect->u.periodic.waveform = FF_SINE;
   838         effect->u.periodic.magnitude = magnitude;
   839     } else {
   840         return SDL_Unsupported();
   841     }
   842 
   843     if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
   844         return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
   845     }
   846 
   847     event.type = EV_FF;
   848     event.code = joystick->hwdata->effect.id;
   849     event.value = 1;
   850     if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
   851         return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
   852     }
   853     return 0;
   854 }
   855 
   856 static SDL_INLINE void
   857 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   858 {
   859     struct hwdata_hat *the_hat;
   860     const Uint8 position_map[3][3] = {
   861         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   862         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   863         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   864     };
   865 
   866     the_hat = &stick->hwdata->hats[hat];
   867     if (value < 0) {
   868         value = 0;
   869     } else if (value == 0) {
   870         value = 1;
   871     } else if (value > 0) {
   872         value = 2;
   873     }
   874     if (value != the_hat->axis[axis]) {
   875         the_hat->axis[axis] = value;
   876         SDL_PrivateJoystickHat(stick, hat,
   877                                position_map[the_hat->
   878                                             axis[1]][the_hat->axis[0]]);
   879     }
   880 }
   881 
   882 static SDL_INLINE void
   883 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   884 {
   885     stick->hwdata->balls[ball].axis[axis] += value;
   886 }
   887 
   888 
   889 static SDL_INLINE int
   890 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   891 {
   892     struct axis_correct *correct;
   893 
   894     correct = &joystick->hwdata->abs_correct[which];
   895     if (correct->used) {
   896         value *= 2;
   897         if (value > correct->coef[0]) {
   898             if (value < correct->coef[1]) {
   899                 return 0;
   900             }
   901             value -= correct->coef[1];
   902         } else {
   903             value -= correct->coef[0];
   904         }
   905         value *= correct->coef[2];
   906         value >>= 13;
   907     }
   908 
   909     /* Clamp and return */
   910     if (value < -32768)
   911         return -32768;
   912     if (value > 32767)
   913         return 32767;
   914 
   915     return value;
   916 }
   917 
   918 static SDL_INLINE void
   919 PollAllValues(SDL_Joystick * joystick)
   920 {
   921     struct input_absinfo absinfo;
   922     int a, b = 0;
   923 
   924     /* Poll all axis */
   925     for (a = ABS_X; b < ABS_MAX; a++) {
   926         switch (a) {
   927         case ABS_HAT0X:
   928         case ABS_HAT0Y:
   929         case ABS_HAT1X:
   930         case ABS_HAT1Y:
   931         case ABS_HAT2X:
   932         case ABS_HAT2Y:
   933         case ABS_HAT3X:
   934         case ABS_HAT3Y:
   935             /* ingore hats */
   936             break;
   937         default:
   938             if (joystick->hwdata->abs_correct[b].used) {
   939                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   940                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   941 
   942 #ifdef DEBUG_INPUT_EVENTS
   943                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   944                         joystick->hwdata->abs_map[b], a, absinfo.value);
   945 #endif
   946                     SDL_PrivateJoystickAxis(joystick,
   947                             joystick->hwdata->abs_map[b],
   948                             absinfo.value);
   949                 }
   950             }
   951             b++;
   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, code / 2, code % 2, events[i].value);
   990                     break;
   991                 default:
   992                     events[i].value =
   993                         AxisCorrect(joystick, code, events[i].value);
   994                     SDL_PrivateJoystickAxis(joystick,
   995                                             joystick->hwdata->abs_map[code],
   996                                             events[i].value);
   997                     break;
   998                 }
   999                 break;
  1000             case EV_REL:
  1001                 switch (code) {
  1002                 case REL_X:
  1003                 case REL_Y:
  1004                     code -= REL_X;
  1005                     HandleBall(joystick, code / 2, code % 2, events[i].value);
  1006                     break;
  1007                 default:
  1008                     break;
  1009                 }
  1010                 break;
  1011             case EV_SYN:
  1012                 switch (code) {
  1013                 case SYN_DROPPED :
  1014 #ifdef DEBUG_INPUT_EVENTS
  1015                     printf("Event SYN_DROPPED detected\n");
  1016 #endif
  1017                     PollAllValues(joystick);
  1018                     break;
  1019                 default:
  1020                     break;
  1021                 }
  1022             default:
  1023                 break;
  1024             }
  1025         }
  1026     }
  1027 }
  1028 
  1029 static void
  1030 LINUX_JoystickUpdate(SDL_Joystick * joystick)
  1031 {
  1032     int i;
  1033 
  1034     if (joystick->hwdata->m_bSteamController) {
  1035         SDL_UpdateSteamController(joystick);
  1036         return;
  1037     }
  1038 
  1039     HandleInputEvents(joystick);
  1040 
  1041     /* Deliver ball motion updates */
  1042     for (i = 0; i < joystick->nballs; ++i) {
  1043         int xrel, yrel;
  1044 
  1045         xrel = joystick->hwdata->balls[i].axis[0];
  1046         yrel = joystick->hwdata->balls[i].axis[1];
  1047         if (xrel || yrel) {
  1048             joystick->hwdata->balls[i].axis[0] = 0;
  1049             joystick->hwdata->balls[i].axis[1] = 0;
  1050             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
  1051         }
  1052     }
  1053 }
  1054 
  1055 /* Function to close a joystick after use */
  1056 static void
  1057 LINUX_JoystickClose(SDL_Joystick * joystick)
  1058 {
  1059     if (joystick->hwdata) {
  1060         if (joystick->hwdata->effect.id >= 0) {
  1061             ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
  1062             joystick->hwdata->effect.id = -1;
  1063         }
  1064         if (joystick->hwdata->fd >= 0) {
  1065             close(joystick->hwdata->fd);
  1066         }
  1067         if (joystick->hwdata->item) {
  1068             joystick->hwdata->item->hwdata = NULL;
  1069         }
  1070         SDL_free(joystick->hwdata->hats);
  1071         SDL_free(joystick->hwdata->balls);
  1072         SDL_free(joystick->hwdata->fname);
  1073         SDL_free(joystick->hwdata);
  1074     }
  1075 }
  1076 
  1077 /* Function to perform any system-specific joystick related cleanup */
  1078 static void
  1079 LINUX_JoystickQuit(void)
  1080 {
  1081     SDL_joylist_item *item = NULL;
  1082     SDL_joylist_item *next = NULL;
  1083 
  1084     for (item = SDL_joylist; item; item = next) {
  1085         next = item->next;
  1086         SDL_free(item->path);
  1087         SDL_free(item->name);
  1088         SDL_free(item);
  1089     }
  1090 
  1091     SDL_joylist = SDL_joylist_tail = NULL;
  1092 
  1093     numjoysticks = 0;
  1094 
  1095 #if SDL_USE_LIBUDEV
  1096     SDL_UDEV_DelCallback(joystick_udev_callback);
  1097     SDL_UDEV_Quit();
  1098 #endif
  1099 
  1100     SDL_QuitSteamControllers();
  1101 }
  1102 
  1103 SDL_JoystickDriver SDL_LINUX_JoystickDriver =
  1104 {
  1105     LINUX_JoystickInit,
  1106     LINUX_JoystickGetCount,
  1107     LINUX_JoystickDetect,
  1108     LINUX_JoystickGetDeviceName,
  1109     LINUX_JoystickGetDevicePlayerIndex,
  1110     LINUX_JoystickGetDeviceGUID,
  1111     LINUX_JoystickGetDeviceInstanceID,
  1112     LINUX_JoystickOpen,
  1113     LINUX_JoystickRumble,
  1114     LINUX_JoystickUpdate,
  1115     LINUX_JoystickClose,
  1116     LINUX_JoystickQuit,
  1117 };
  1118 
  1119 #endif /* SDL_JOYSTICK_LINUX */
  1120 
  1121 /* vi: set ts=4 sw=4 expandtab: */