src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 26 Aug 2016 12:18:08 -0700
changeset 10226 cb13d22b7f09
parent 10225 3134026517cb
child 10595 9da2701eeb4a
permissions -rw-r--r--
Added SDL_PrivateJoystickAdded() and SDL_PrivateJoystickRemoved()
Updated the removal code to iterate over all joystick add messages instead of just the first one.
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2016 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 <unistd.h>
    33 #include <fcntl.h>
    34 #include <sys/ioctl.h>
    35 #include <limits.h>             /* For the definition of PATH_MAX */
    36 #include <linux/joystick.h>
    37 
    38 #include "SDL_assert.h"
    39 #include "SDL_joystick.h"
    40 #include "SDL_endian.h"
    41 #include "../SDL_sysjoystick.h"
    42 #include "../SDL_joystick_c.h"
    43 #include "SDL_sysjoystick_c.h"
    44 
    45 /* This isn't defined in older Linux kernel headers */
    46 #ifndef SYN_DROPPED
    47 #define SYN_DROPPED 3
    48 #endif
    49 
    50 #include "../../core/linux/SDL_udev.h"
    51 
    52 static int MaybeAddDevice(const char *path);
    53 #if SDL_USE_LIBUDEV
    54 static int MaybeRemoveDevice(const char *path);
    55 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
    56 #endif /* SDL_USE_LIBUDEV */
    57 
    58 
    59 /* A linked list of available joysticks */
    60 typedef struct SDL_joylist_item
    61 {
    62     int device_instance;
    63     char *path;   /* "/dev/input/event2" or whatever */
    64     char *name;   /* "SideWinder 3D Pro" or whatever */
    65     SDL_JoystickGUID guid;
    66     dev_t devnum;
    67     struct joystick_hwdata *hwdata;
    68     struct SDL_joylist_item *next;
    69 } SDL_joylist_item;
    70 
    71 static SDL_joylist_item *SDL_joylist = NULL;
    72 static SDL_joylist_item *SDL_joylist_tail = NULL;
    73 static int numjoysticks = 0;
    74 static int instance_counter = 0;
    75 
    76 #define test_bit(nr, addr) \
    77     (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
    78 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
    79 
    80 static int
    81 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
    82 {
    83     struct input_id inpid;
    84     Uint16 *guid16 = (Uint16 *) ((char *) &guid->data);
    85 
    86 #if !SDL_USE_LIBUDEV
    87     /* When udev is enabled we only get joystick devices here, so there's no need to test them */
    88     unsigned long evbit[NBITS(EV_MAX)] = { 0 };
    89     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
    90     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
    91 
    92     if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
    93         (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
    94         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
    95         return (0);
    96     }
    97 
    98     if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
    99           test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
   100         return 0;
   101     }
   102 #endif
   103 
   104     if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
   105         return 0;
   106     }
   107 
   108     if (ioctl(fd, EVIOCGID, &inpid) < 0) {
   109         return 0;
   110     }
   111 
   112 #ifdef DEBUG_JOYSTICK
   113     printf("Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
   114 #endif
   115 
   116     SDL_memset(guid->data, 0, sizeof(guid->data));
   117 
   118     /* We only need 16 bits for each of these; space them out to fill 128. */
   119     /* Byteswap so devices get same GUID on little/big endian platforms. */
   120     *(guid16++) = SDL_SwapLE16(inpid.bustype);
   121     *(guid16++) = 0;
   122 
   123     if (inpid.vendor && inpid.product && inpid.version) {
   124         *(guid16++) = SDL_SwapLE16(inpid.vendor);
   125         *(guid16++) = 0;
   126         *(guid16++) = SDL_SwapLE16(inpid.product);
   127         *(guid16++) = 0;
   128         *(guid16++) = SDL_SwapLE16(inpid.version);
   129         *(guid16++) = 0;
   130     } else {
   131         SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
   132     }
   133 
   134     return 1;
   135 }
   136 
   137 #if SDL_USE_LIBUDEV
   138 void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
   139 {
   140     if (devpath == NULL) {
   141         return;
   142     }
   143 
   144     switch (udev_type) {
   145         case SDL_UDEV_DEVICEADDED:
   146             if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
   147                 return;
   148             }
   149             MaybeAddDevice(devpath);
   150             break;
   151             
   152         case SDL_UDEV_DEVICEREMOVED:
   153             MaybeRemoveDevice(devpath);
   154             break;
   155             
   156         default:
   157             break;
   158     }
   159     
   160 }
   161 #endif /* SDL_USE_LIBUDEV */
   162 
   163 
   164 /* !!! FIXME: I would love to dump this code and use libudev instead. */
   165 static int
   166 MaybeAddDevice(const char *path)
   167 {
   168     struct stat sb;
   169     int fd = -1;
   170     int isstick = 0;
   171     char namebuf[128];
   172     SDL_JoystickGUID guid;
   173     SDL_joylist_item *item;
   174 
   175     if (path == NULL) {
   176         return -1;
   177     }
   178 
   179     if (stat(path, &sb) == -1) {
   180         return -1;
   181     }
   182 
   183     /* Check to make sure it's not already in list. */
   184     for (item = SDL_joylist; item != NULL; item = item->next) {
   185         if (sb.st_rdev == item->devnum) {
   186             return -1;  /* already have this one */
   187         }
   188     }
   189 
   190     fd = open(path, O_RDONLY, 0);
   191     if (fd < 0) {
   192         return -1;
   193     }
   194 
   195 #ifdef DEBUG_INPUT_EVENTS
   196     printf("Checking %s\n", path);
   197 #endif
   198 
   199     isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
   200     close(fd);
   201     if (!isstick) {
   202         return -1;
   203     }
   204 
   205     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   206     if (item == NULL) {
   207         return -1;
   208     }
   209 
   210     SDL_zerop(item);
   211     item->devnum = sb.st_rdev;
   212     item->path = SDL_strdup(path);
   213     item->name = SDL_strdup(namebuf);
   214     item->guid = guid;
   215 
   216     if ( (item->path == NULL) || (item->name == NULL) ) {
   217          SDL_free(item->path);
   218          SDL_free(item->name);
   219          SDL_free(item);
   220          return -1;
   221     }
   222 
   223     item->device_instance = instance_counter++;
   224     if (SDL_joylist_tail == NULL) {
   225         SDL_joylist = SDL_joylist_tail = item;
   226     } else {
   227         SDL_joylist_tail->next = item;
   228         SDL_joylist_tail = item;
   229     }
   230 
   231     /* Need to increment the joystick count before we post the event */
   232     ++numjoysticks;
   233 
   234     SDL_PrivateJoystickAdded(numjoysticks - 1);
   235 
   236     return numjoysticks;
   237 }
   238 
   239 #if SDL_USE_LIBUDEV
   240 /* !!! FIXME: I would love to dump this code and use libudev instead. */
   241 static int
   242 MaybeRemoveDevice(const char *path)
   243 {
   244     SDL_joylist_item *item;
   245     SDL_joylist_item *prev = NULL;
   246 
   247     if (path == NULL) {
   248         return -1;
   249     }
   250 
   251     for (item = SDL_joylist; item != NULL; item = item->next) {
   252         /* found it, remove it. */
   253         if (SDL_strcmp(path, item->path) == 0) {
   254             const int retval = item->device_instance;
   255             if (item->hwdata) {
   256                 item->hwdata->item = NULL;
   257             }
   258             if (prev != NULL) {
   259                 prev->next = item->next;
   260             } else {
   261                 SDL_assert(SDL_joylist == item);
   262                 SDL_joylist = item->next;
   263             }
   264             if (item == SDL_joylist_tail) {
   265                 SDL_joylist_tail = prev;
   266             }
   267 
   268             /* Need to decrement the joystick count before we post the event */
   269             --numjoysticks;
   270 
   271             SDL_PrivateJoystickRemoved(item->device_instance);
   272 
   273             SDL_free(item->path);
   274             SDL_free(item->name);
   275             SDL_free(item);
   276             return retval;
   277         }
   278         prev = item;
   279     }
   280 
   281     return -1;
   282 }
   283 #endif
   284 
   285 static int
   286 JoystickInitWithoutUdev(void)
   287 {
   288     int i;
   289     char path[PATH_MAX];
   290 
   291     /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
   292     /* !!! FIXME:  we could at least readdir() through /dev/input...? */
   293     /* !!! FIXME:  (or delete this and rely on libudev?) */
   294     for (i = 0; i < 32; i++) {
   295         SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
   296         MaybeAddDevice(path);
   297     }
   298 
   299     return numjoysticks;
   300 }
   301 
   302 
   303 #if SDL_USE_LIBUDEV
   304 static int
   305 JoystickInitWithUdev(void)
   306 {
   307     if (SDL_UDEV_Init() < 0) {
   308         return SDL_SetError("Could not initialize UDEV");
   309     }
   310 
   311     /* Set up the udev callback */
   312     if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
   313         SDL_UDEV_Quit();
   314         return SDL_SetError("Could not set up joystick <-> udev callback");
   315     }
   316     
   317     /* Force a scan to build the initial device list */
   318     SDL_UDEV_Scan();
   319 
   320     return numjoysticks;
   321 }
   322 #endif
   323 
   324 int
   325 SDL_SYS_JoystickInit(void)
   326 {
   327     /* First see if the user specified one or more joysticks to use */
   328     if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
   329         char *envcopy, *envpath, *delim;
   330         envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
   331         envpath = envcopy;
   332         while (envpath != NULL) {
   333             delim = SDL_strchr(envpath, ':');
   334             if (delim != NULL) {
   335                 *delim++ = '\0';
   336             }
   337             MaybeAddDevice(envpath);
   338             envpath = delim;
   339         }
   340         SDL_free(envcopy);
   341     }
   342 
   343 #if SDL_USE_LIBUDEV
   344     return JoystickInitWithUdev();
   345 #endif
   346 
   347     return JoystickInitWithoutUdev();
   348 }
   349 
   350 int SDL_SYS_NumJoysticks()
   351 {
   352     return numjoysticks;
   353 }
   354 
   355 void SDL_SYS_JoystickDetect()
   356 {
   357 #if SDL_USE_LIBUDEV
   358     SDL_UDEV_Poll();
   359 #endif
   360     
   361 }
   362 
   363 static SDL_joylist_item *
   364 JoystickByDevIndex(int device_index)
   365 {
   366     SDL_joylist_item *item = SDL_joylist;
   367 
   368     if ((device_index < 0) || (device_index >= numjoysticks)) {
   369         return NULL;
   370     }
   371 
   372     while (device_index > 0) {
   373         SDL_assert(item != NULL);
   374         device_index--;
   375         item = item->next;
   376     }
   377 
   378     return item;
   379 }
   380 
   381 /* Function to get the device-dependent name of a joystick */
   382 const char *
   383 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   384 {
   385     return JoystickByDevIndex(device_index)->name;
   386 }
   387 
   388 /* Function to perform the mapping from device index to the instance id for this index */
   389 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   390 {
   391     return JoystickByDevIndex(device_index)->device_instance;
   392 }
   393 
   394 static int
   395 allocate_hatdata(SDL_Joystick * joystick)
   396 {
   397     int i;
   398 
   399     joystick->hwdata->hats =
   400         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   401                                          sizeof(struct hwdata_hat));
   402     if (joystick->hwdata->hats == NULL) {
   403         return (-1);
   404     }
   405     for (i = 0; i < joystick->nhats; ++i) {
   406         joystick->hwdata->hats[i].axis[0] = 1;
   407         joystick->hwdata->hats[i].axis[1] = 1;
   408     }
   409     return (0);
   410 }
   411 
   412 static int
   413 allocate_balldata(SDL_Joystick * joystick)
   414 {
   415     int i;
   416 
   417     joystick->hwdata->balls =
   418         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   419                                           sizeof(struct hwdata_ball));
   420     if (joystick->hwdata->balls == NULL) {
   421         return (-1);
   422     }
   423     for (i = 0; i < joystick->nballs; ++i) {
   424         joystick->hwdata->balls[i].axis[0] = 0;
   425         joystick->hwdata->balls[i].axis[1] = 0;
   426     }
   427     return (0);
   428 }
   429 
   430 static void
   431 ConfigJoystick(SDL_Joystick * joystick, int fd)
   432 {
   433     int i, t;
   434     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   435     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   436     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   437 
   438     /* See if this device uses the new unified event API */
   439     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   440         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   441         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   442 
   443         /* Get the number of buttons, axes, and other thingamajigs */
   444         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
   445             if (test_bit(i, keybit)) {
   446 #ifdef DEBUG_INPUT_EVENTS
   447                 printf("Joystick has button: 0x%x\n", i);
   448 #endif
   449                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   450                 ++joystick->nbuttons;
   451             }
   452         }
   453         for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
   454             if (test_bit(i, keybit)) {
   455 #ifdef DEBUG_INPUT_EVENTS
   456                 printf("Joystick has button: 0x%x\n", i);
   457 #endif
   458                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   459                 ++joystick->nbuttons;
   460             }
   461         }
   462         for (i = 0; i < ABS_MAX; ++i) {
   463             /* Skip hats */
   464             if (i == ABS_HAT0X) {
   465                 i = ABS_HAT3Y;
   466                 continue;
   467             }
   468             if (test_bit(i, absbit)) {
   469                 struct input_absinfo absinfo;
   470 
   471                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   472                     continue;
   473                 }
   474 #ifdef DEBUG_INPUT_EVENTS
   475                 printf("Joystick has absolute axis: 0x%.2x\n", i);
   476                 printf("Values = { %d, %d, %d, %d, %d }\n",
   477                        absinfo.value, absinfo.minimum, absinfo.maximum,
   478                        absinfo.fuzz, absinfo.flat);
   479 #endif /* DEBUG_INPUT_EVENTS */
   480                 joystick->hwdata->abs_map[i] = joystick->naxes;
   481                 if (absinfo.minimum == absinfo.maximum) {
   482                     joystick->hwdata->abs_correct[i].used = 0;
   483                 } else {
   484                     joystick->hwdata->abs_correct[i].used = 1;
   485                     joystick->hwdata->abs_correct[i].coef[0] =
   486                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   487                     joystick->hwdata->abs_correct[i].coef[1] =
   488                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   489                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   490                     if (t != 0) {
   491                         joystick->hwdata->abs_correct[i].coef[2] =
   492                             (1 << 28) / t;
   493                     } else {
   494                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   495                     }
   496                 }
   497                 ++joystick->naxes;
   498             }
   499         }
   500         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   501             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   502                 struct input_absinfo absinfo;
   503 
   504                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   505                     continue;
   506                 }
   507 #ifdef DEBUG_INPUT_EVENTS
   508                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   509                 printf("Values = { %d, %d, %d, %d, %d }\n",
   510                        absinfo.value, absinfo.minimum, absinfo.maximum,
   511                        absinfo.fuzz, absinfo.flat);
   512 #endif /* DEBUG_INPUT_EVENTS */
   513                 ++joystick->nhats;
   514             }
   515         }
   516         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   517             ++joystick->nballs;
   518         }
   519 
   520         /* Allocate data to keep track of these thingamajigs */
   521         if (joystick->nhats > 0) {
   522             if (allocate_hatdata(joystick) < 0) {
   523                 joystick->nhats = 0;
   524             }
   525         }
   526         if (joystick->nballs > 0) {
   527             if (allocate_balldata(joystick) < 0) {
   528                 joystick->nballs = 0;
   529             }
   530         }
   531     }
   532 }
   533 
   534 
   535 /* Function to open a joystick for use.
   536    The joystick to open is specified by the device index.
   537    This should fill the nbuttons and naxes fields of the joystick structure.
   538    It returns 0, or -1 if there is an error.
   539  */
   540 int
   541 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   542 {
   543     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   544     char *fname = NULL;
   545     int fd = -1;
   546 
   547     if (item == NULL) {
   548         return SDL_SetError("No such device");
   549     }
   550 
   551     fname = item->path;
   552     fd = open(fname, O_RDONLY, 0);
   553     if (fd < 0) {
   554         return SDL_SetError("Unable to open %s", fname);
   555     }
   556 
   557     joystick->instance_id = item->device_instance;
   558     joystick->hwdata = (struct joystick_hwdata *)
   559         SDL_malloc(sizeof(*joystick->hwdata));
   560     if (joystick->hwdata == NULL) {
   561         close(fd);
   562         return SDL_OutOfMemory();
   563     }
   564     SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   565     joystick->hwdata->item = item;
   566     joystick->hwdata->guid = item->guid;
   567     joystick->hwdata->fd = fd;
   568     joystick->hwdata->fname = SDL_strdup(item->path);
   569     if (joystick->hwdata->fname == NULL) {
   570         SDL_free(joystick->hwdata);
   571         joystick->hwdata = NULL;
   572         close(fd);
   573         return SDL_OutOfMemory();
   574     }
   575 
   576     SDL_assert(item->hwdata == NULL);
   577     item->hwdata = joystick->hwdata;
   578 
   579     /* Set the joystick to non-blocking read mode */
   580     fcntl(fd, F_SETFL, O_NONBLOCK);
   581 
   582     /* Get the number of buttons and axes on the joystick */
   583     ConfigJoystick(joystick, fd);
   584 
   585     /* mark joystick as fresh and ready */
   586     joystick->hwdata->fresh = 1;
   587 
   588     return (0);
   589 }
   590 
   591 /* Function to determine if this joystick is attached to the system right now */
   592 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   593 {
   594     return joystick->hwdata->item != NULL;
   595 }
   596 
   597 static SDL_INLINE void
   598 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   599 {
   600     struct hwdata_hat *the_hat;
   601     const Uint8 position_map[3][3] = {
   602         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   603         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   604         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   605     };
   606 
   607     the_hat = &stick->hwdata->hats[hat];
   608     if (value < 0) {
   609         value = 0;
   610     } else if (value == 0) {
   611         value = 1;
   612     } else if (value > 0) {
   613         value = 2;
   614     }
   615     if (value != the_hat->axis[axis]) {
   616         the_hat->axis[axis] = value;
   617         SDL_PrivateJoystickHat(stick, hat,
   618                                position_map[the_hat->
   619                                             axis[1]][the_hat->axis[0]]);
   620     }
   621 }
   622 
   623 static SDL_INLINE void
   624 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   625 {
   626     stick->hwdata->balls[ball].axis[axis] += value;
   627 }
   628 
   629 
   630 static SDL_INLINE int
   631 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   632 {
   633     struct axis_correct *correct;
   634 
   635     correct = &joystick->hwdata->abs_correct[which];
   636     if (correct->used) {
   637         value *= 2;
   638         if (value > correct->coef[0]) {
   639             if (value < correct->coef[1]) {
   640                 return 0;
   641             }
   642             value -= correct->coef[1];
   643         } else {
   644             value -= correct->coef[0];
   645         }
   646         value *= correct->coef[2];
   647         value >>= 13;
   648     }
   649 
   650     /* Clamp and return */
   651     if (value < -32768)
   652         return -32768;
   653     if (value > 32767)
   654         return 32767;
   655 
   656     return value;
   657 }
   658 
   659 static SDL_INLINE void
   660 PollAllValues(SDL_Joystick * joystick)
   661 {
   662     struct input_absinfo absinfo;
   663     int a, b = 0;
   664 
   665     /* Poll all axis */
   666     for (a = ABS_X; b < ABS_MAX; a++) {
   667         switch (a) {
   668         case ABS_HAT0X:
   669         case ABS_HAT0Y:
   670         case ABS_HAT1X:
   671         case ABS_HAT1Y:
   672         case ABS_HAT2X:
   673         case ABS_HAT2Y:
   674         case ABS_HAT3X:
   675         case ABS_HAT3Y:
   676             /* ingore hats */
   677             break;
   678         default:
   679             if (joystick->hwdata->abs_correct[b].used) {
   680                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   681                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   682 
   683 #ifdef DEBUG_INPUT_EVENTS
   684                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   685                         joystick->hwdata->abs_map[b], a, absinfo.value);
   686 #endif
   687                     SDL_PrivateJoystickAxis(joystick,
   688                             joystick->hwdata->abs_map[b],
   689                             absinfo.value);
   690                 }
   691             }
   692             b++;
   693         }
   694     }
   695 }
   696 
   697 static SDL_INLINE void
   698 HandleInputEvents(SDL_Joystick * joystick)
   699 {
   700     struct input_event events[32];
   701     int i, len;
   702     int code;
   703 
   704     if (joystick->hwdata->fresh) {
   705         PollAllValues(joystick);
   706         joystick->hwdata->fresh = 0;
   707     }
   708 
   709     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   710         len /= sizeof(events[0]);
   711         for (i = 0; i < len; ++i) {
   712             code = events[i].code;
   713             switch (events[i].type) {
   714             case EV_KEY:
   715                 if (code >= BTN_MISC) {
   716                     code -= BTN_MISC;
   717                     SDL_PrivateJoystickButton(joystick,
   718                                               joystick->hwdata->key_map[code],
   719                                               events[i].value);
   720                 }
   721                 break;
   722             case EV_ABS:
   723                 switch (code) {
   724                 case ABS_HAT0X:
   725                 case ABS_HAT0Y:
   726                 case ABS_HAT1X:
   727                 case ABS_HAT1Y:
   728                 case ABS_HAT2X:
   729                 case ABS_HAT2Y:
   730                 case ABS_HAT3X:
   731                 case ABS_HAT3Y:
   732                     code -= ABS_HAT0X;
   733                     HandleHat(joystick, code / 2, code % 2, events[i].value);
   734                     break;
   735                 default:
   736                     events[i].value =
   737                         AxisCorrect(joystick, code, events[i].value);
   738                     SDL_PrivateJoystickAxis(joystick,
   739                                             joystick->hwdata->abs_map[code],
   740                                             events[i].value);
   741                     break;
   742                 }
   743                 break;
   744             case EV_REL:
   745                 switch (code) {
   746                 case REL_X:
   747                 case REL_Y:
   748                     code -= REL_X;
   749                     HandleBall(joystick, code / 2, code % 2, events[i].value);
   750                     break;
   751                 default:
   752                     break;
   753                 }
   754                 break;
   755             case EV_SYN:
   756                 switch (code) {
   757                 case SYN_DROPPED :
   758 #ifdef DEBUG_INPUT_EVENTS
   759                     printf("Event SYN_DROPPED detected\n");
   760 #endif
   761                     PollAllValues(joystick);
   762                     break;
   763                 default:
   764                     break;
   765                 }
   766             default:
   767                 break;
   768             }
   769         }
   770     }
   771 }
   772 
   773 void
   774 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   775 {
   776     int i;
   777 
   778     HandleInputEvents(joystick);
   779 
   780     /* Deliver ball motion updates */
   781     for (i = 0; i < joystick->nballs; ++i) {
   782         int xrel, yrel;
   783 
   784         xrel = joystick->hwdata->balls[i].axis[0];
   785         yrel = joystick->hwdata->balls[i].axis[1];
   786         if (xrel || yrel) {
   787             joystick->hwdata->balls[i].axis[0] = 0;
   788             joystick->hwdata->balls[i].axis[1] = 0;
   789             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
   790         }
   791     }
   792 }
   793 
   794 /* Function to close a joystick after use */
   795 void
   796 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   797 {
   798     if (joystick->hwdata) {
   799         close(joystick->hwdata->fd);
   800         if (joystick->hwdata->item) {
   801             joystick->hwdata->item->hwdata = NULL;
   802         }
   803         SDL_free(joystick->hwdata->hats);
   804         SDL_free(joystick->hwdata->balls);
   805         SDL_free(joystick->hwdata->fname);
   806         SDL_free(joystick->hwdata);
   807     }
   808 }
   809 
   810 /* Function to perform any system-specific joystick related cleanup */
   811 void
   812 SDL_SYS_JoystickQuit(void)
   813 {
   814     SDL_joylist_item *item = NULL;
   815     SDL_joylist_item *next = NULL;
   816 
   817     for (item = SDL_joylist; item; item = next) {
   818         next = item->next;
   819         SDL_free(item->path);
   820         SDL_free(item->name);
   821         SDL_free(item);
   822     }
   823 
   824     SDL_joylist = SDL_joylist_tail = NULL;
   825 
   826     numjoysticks = 0;
   827     instance_counter = 0;
   828 
   829 #if SDL_USE_LIBUDEV
   830     SDL_UDEV_DelCallback(joystick_udev_callback);
   831     SDL_UDEV_Quit();
   832 #endif
   833 }
   834 
   835 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   836 {
   837     return JoystickByDevIndex(device_index)->guid;
   838 }
   839 
   840 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   841 {
   842     return joystick->hwdata->guid;
   843 }
   844 
   845 #endif /* SDL_JOYSTICK_LINUX */
   846 
   847 /* vi: set ts=4 sw=4 expandtab: */