src/joystick/linux/SDL_sysjoystick.c
author Philipp Wiesemann <philipp.wiesemann@arcor.de>
Wed, 16 Nov 2016 22:08:51 +0100
changeset 10617 346c02ff71b6
parent 10609 d702ecbd8ba7
child 10641 ae818421bb1f
permissions -rw-r--r--
Fixed empty parameter list in signatures of internal functions.
     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 *)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%.4x, product = 0x%.4x, 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) {
   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 #if ! SDL_USE_LIBUDEV
   286 static int
   287 JoystickInitWithoutUdev(void)
   288 {
   289     int i;
   290     char path[PATH_MAX];
   291 
   292     /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
   293     /* !!! FIXME:  we could at least readdir() through /dev/input...? */
   294     /* !!! FIXME:  (or delete this and rely on libudev?) */
   295     for (i = 0; i < 32; i++) {
   296         SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
   297         MaybeAddDevice(path);
   298     }
   299 
   300     return numjoysticks;
   301 }
   302 #endif
   303 
   304 #if SDL_USE_LIBUDEV
   305 static int
   306 JoystickInitWithUdev(void)
   307 {
   308     if (SDL_UDEV_Init() < 0) {
   309         return SDL_SetError("Could not initialize UDEV");
   310     }
   311 
   312     /* Set up the udev callback */
   313     if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
   314         SDL_UDEV_Quit();
   315         return SDL_SetError("Could not set up joystick <-> udev callback");
   316     }
   317     
   318     /* Force a scan to build the initial device list */
   319     SDL_UDEV_Scan();
   320 
   321     return numjoysticks;
   322 }
   323 #endif
   324 
   325 int
   326 SDL_SYS_JoystickInit(void)
   327 {
   328     /* First see if the user specified one or more joysticks to use */
   329     if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
   330         char *envcopy, *envpath, *delim;
   331         envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
   332         envpath = envcopy;
   333         while (envpath != NULL) {
   334             delim = SDL_strchr(envpath, ':');
   335             if (delim != NULL) {
   336                 *delim++ = '\0';
   337             }
   338             MaybeAddDevice(envpath);
   339             envpath = delim;
   340         }
   341         SDL_free(envcopy);
   342     }
   343 
   344 #if SDL_USE_LIBUDEV
   345     return JoystickInitWithUdev();
   346 #else 
   347     return JoystickInitWithoutUdev();
   348 #endif
   349 }
   350 
   351 int
   352 SDL_SYS_NumJoysticks(void)
   353 {
   354     return numjoysticks;
   355 }
   356 
   357 void
   358 SDL_SYS_JoystickDetect(void)
   359 {
   360 #if SDL_USE_LIBUDEV
   361     SDL_UDEV_Poll();
   362 #endif
   363     
   364 }
   365 
   366 static SDL_joylist_item *
   367 JoystickByDevIndex(int device_index)
   368 {
   369     SDL_joylist_item *item = SDL_joylist;
   370 
   371     if ((device_index < 0) || (device_index >= numjoysticks)) {
   372         return NULL;
   373     }
   374 
   375     while (device_index > 0) {
   376         SDL_assert(item != NULL);
   377         device_index--;
   378         item = item->next;
   379     }
   380 
   381     return item;
   382 }
   383 
   384 /* Function to get the device-dependent name of a joystick */
   385 const char *
   386 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   387 {
   388     return JoystickByDevIndex(device_index)->name;
   389 }
   390 
   391 /* Function to perform the mapping from device index to the instance id for this index */
   392 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   393 {
   394     return JoystickByDevIndex(device_index)->device_instance;
   395 }
   396 
   397 static int
   398 allocate_hatdata(SDL_Joystick * joystick)
   399 {
   400     int i;
   401 
   402     joystick->hwdata->hats =
   403         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   404                                          sizeof(struct hwdata_hat));
   405     if (joystick->hwdata->hats == NULL) {
   406         return (-1);
   407     }
   408     for (i = 0; i < joystick->nhats; ++i) {
   409         joystick->hwdata->hats[i].axis[0] = 1;
   410         joystick->hwdata->hats[i].axis[1] = 1;
   411     }
   412     return (0);
   413 }
   414 
   415 static int
   416 allocate_balldata(SDL_Joystick * joystick)
   417 {
   418     int i;
   419 
   420     joystick->hwdata->balls =
   421         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   422                                           sizeof(struct hwdata_ball));
   423     if (joystick->hwdata->balls == NULL) {
   424         return (-1);
   425     }
   426     for (i = 0; i < joystick->nballs; ++i) {
   427         joystick->hwdata->balls[i].axis[0] = 0;
   428         joystick->hwdata->balls[i].axis[1] = 0;
   429     }
   430     return (0);
   431 }
   432 
   433 static void
   434 ConfigJoystick(SDL_Joystick * joystick, int fd)
   435 {
   436     int i, t;
   437     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   438     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   439     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   440 
   441     /* See if this device uses the new unified event API */
   442     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   443         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   444         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   445 
   446         /* Get the number of buttons, axes, and other thingamajigs */
   447         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
   448             if (test_bit(i, keybit)) {
   449 #ifdef DEBUG_INPUT_EVENTS
   450                 printf("Joystick has button: 0x%x\n", i);
   451 #endif
   452                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   453                 ++joystick->nbuttons;
   454             }
   455         }
   456         for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
   457             if (test_bit(i, keybit)) {
   458 #ifdef DEBUG_INPUT_EVENTS
   459                 printf("Joystick has button: 0x%x\n", i);
   460 #endif
   461                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   462                 ++joystick->nbuttons;
   463             }
   464         }
   465         for (i = 0; i < ABS_MAX; ++i) {
   466             /* Skip hats */
   467             if (i == ABS_HAT0X) {
   468                 i = ABS_HAT3Y;
   469                 continue;
   470             }
   471             if (test_bit(i, absbit)) {
   472                 struct input_absinfo absinfo;
   473 
   474                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   475                     continue;
   476                 }
   477 #ifdef DEBUG_INPUT_EVENTS
   478                 printf("Joystick has absolute axis: 0x%.2x\n", i);
   479                 printf("Values = { %d, %d, %d, %d, %d }\n",
   480                        absinfo.value, absinfo.minimum, absinfo.maximum,
   481                        absinfo.fuzz, absinfo.flat);
   482 #endif /* DEBUG_INPUT_EVENTS */
   483                 joystick->hwdata->abs_map[i] = joystick->naxes;
   484                 if (absinfo.minimum == absinfo.maximum) {
   485                     joystick->hwdata->abs_correct[i].used = 0;
   486                 } else {
   487                     joystick->hwdata->abs_correct[i].used = 1;
   488                     joystick->hwdata->abs_correct[i].coef[0] =
   489                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   490                     joystick->hwdata->abs_correct[i].coef[1] =
   491                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   492                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   493                     if (t != 0) {
   494                         joystick->hwdata->abs_correct[i].coef[2] =
   495                             (1 << 28) / t;
   496                     } else {
   497                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   498                     }
   499                 }
   500                 ++joystick->naxes;
   501             }
   502         }
   503         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   504             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   505                 struct input_absinfo absinfo;
   506 
   507                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   508                     continue;
   509                 }
   510 #ifdef DEBUG_INPUT_EVENTS
   511                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   512                 printf("Values = { %d, %d, %d, %d, %d }\n",
   513                        absinfo.value, absinfo.minimum, absinfo.maximum,
   514                        absinfo.fuzz, absinfo.flat);
   515 #endif /* DEBUG_INPUT_EVENTS */
   516                 ++joystick->nhats;
   517             }
   518         }
   519         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   520             ++joystick->nballs;
   521         }
   522 
   523         /* Allocate data to keep track of these thingamajigs */
   524         if (joystick->nhats > 0) {
   525             if (allocate_hatdata(joystick) < 0) {
   526                 joystick->nhats = 0;
   527             }
   528         }
   529         if (joystick->nballs > 0) {
   530             if (allocate_balldata(joystick) < 0) {
   531                 joystick->nballs = 0;
   532             }
   533         }
   534     }
   535 }
   536 
   537 
   538 /* Function to open a joystick for use.
   539    The joystick to open is specified by the device index.
   540    This should fill the nbuttons and naxes fields of the joystick structure.
   541    It returns 0, or -1 if there is an error.
   542  */
   543 int
   544 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   545 {
   546     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   547     char *fname = NULL;
   548     int fd = -1;
   549 
   550     if (item == NULL) {
   551         return SDL_SetError("No such device");
   552     }
   553 
   554     fname = item->path;
   555     fd = open(fname, O_RDONLY, 0);
   556     if (fd < 0) {
   557         return SDL_SetError("Unable to open %s", fname);
   558     }
   559 
   560     joystick->instance_id = item->device_instance;
   561     joystick->hwdata = (struct joystick_hwdata *)
   562         SDL_malloc(sizeof(*joystick->hwdata));
   563     if (joystick->hwdata == NULL) {
   564         close(fd);
   565         return SDL_OutOfMemory();
   566     }
   567     SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   568     joystick->hwdata->item = item;
   569     joystick->hwdata->guid = item->guid;
   570     joystick->hwdata->fd = fd;
   571     joystick->hwdata->fname = SDL_strdup(item->path);
   572     if (joystick->hwdata->fname == NULL) {
   573         SDL_free(joystick->hwdata);
   574         joystick->hwdata = NULL;
   575         close(fd);
   576         return SDL_OutOfMemory();
   577     }
   578 
   579     SDL_assert(item->hwdata == NULL);
   580     item->hwdata = joystick->hwdata;
   581 
   582     /* Set the joystick to non-blocking read mode */
   583     fcntl(fd, F_SETFL, O_NONBLOCK);
   584 
   585     /* Get the number of buttons and axes on the joystick */
   586     ConfigJoystick(joystick, fd);
   587 
   588     /* mark joystick as fresh and ready */
   589     joystick->hwdata->fresh = 1;
   590 
   591     return (0);
   592 }
   593 
   594 /* Function to determine if this joystick is attached to the system right now */
   595 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   596 {
   597     return joystick->hwdata->item != NULL;
   598 }
   599 
   600 static SDL_INLINE void
   601 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   602 {
   603     struct hwdata_hat *the_hat;
   604     const Uint8 position_map[3][3] = {
   605         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   606         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   607         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   608     };
   609 
   610     the_hat = &stick->hwdata->hats[hat];
   611     if (value < 0) {
   612         value = 0;
   613     } else if (value == 0) {
   614         value = 1;
   615     } else if (value > 0) {
   616         value = 2;
   617     }
   618     if (value != the_hat->axis[axis]) {
   619         the_hat->axis[axis] = value;
   620         SDL_PrivateJoystickHat(stick, hat,
   621                                position_map[the_hat->
   622                                             axis[1]][the_hat->axis[0]]);
   623     }
   624 }
   625 
   626 static SDL_INLINE void
   627 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   628 {
   629     stick->hwdata->balls[ball].axis[axis] += value;
   630 }
   631 
   632 
   633 static SDL_INLINE int
   634 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   635 {
   636     struct axis_correct *correct;
   637 
   638     correct = &joystick->hwdata->abs_correct[which];
   639     if (correct->used) {
   640         value *= 2;
   641         if (value > correct->coef[0]) {
   642             if (value < correct->coef[1]) {
   643                 return 0;
   644             }
   645             value -= correct->coef[1];
   646         } else {
   647             value -= correct->coef[0];
   648         }
   649         value *= correct->coef[2];
   650         value >>= 13;
   651     }
   652 
   653     /* Clamp and return */
   654     if (value < -32768)
   655         return -32768;
   656     if (value > 32767)
   657         return 32767;
   658 
   659     return value;
   660 }
   661 
   662 static SDL_INLINE void
   663 PollAllValues(SDL_Joystick * joystick)
   664 {
   665     struct input_absinfo absinfo;
   666     int a, b = 0;
   667 
   668     /* Poll all axis */
   669     for (a = ABS_X; b < ABS_MAX; a++) {
   670         switch (a) {
   671         case ABS_HAT0X:
   672         case ABS_HAT0Y:
   673         case ABS_HAT1X:
   674         case ABS_HAT1Y:
   675         case ABS_HAT2X:
   676         case ABS_HAT2Y:
   677         case ABS_HAT3X:
   678         case ABS_HAT3Y:
   679             /* ingore hats */
   680             break;
   681         default:
   682             if (joystick->hwdata->abs_correct[b].used) {
   683                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   684                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   685 
   686 #ifdef DEBUG_INPUT_EVENTS
   687                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   688                         joystick->hwdata->abs_map[b], a, absinfo.value);
   689 #endif
   690                     SDL_PrivateJoystickAxis(joystick,
   691                             joystick->hwdata->abs_map[b],
   692                             absinfo.value);
   693                 }
   694             }
   695             b++;
   696         }
   697     }
   698 }
   699 
   700 static SDL_INLINE void
   701 HandleInputEvents(SDL_Joystick * joystick)
   702 {
   703     struct input_event events[32];
   704     int i, len;
   705     int code;
   706 
   707     if (joystick->hwdata->fresh) {
   708         PollAllValues(joystick);
   709         joystick->hwdata->fresh = 0;
   710     }
   711 
   712     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   713         len /= sizeof(events[0]);
   714         for (i = 0; i < len; ++i) {
   715             code = events[i].code;
   716             switch (events[i].type) {
   717             case EV_KEY:
   718                 if (code >= BTN_MISC) {
   719                     code -= BTN_MISC;
   720                     SDL_PrivateJoystickButton(joystick,
   721                                               joystick->hwdata->key_map[code],
   722                                               events[i].value);
   723                 }
   724                 break;
   725             case EV_ABS:
   726                 switch (code) {
   727                 case ABS_HAT0X:
   728                 case ABS_HAT0Y:
   729                 case ABS_HAT1X:
   730                 case ABS_HAT1Y:
   731                 case ABS_HAT2X:
   732                 case ABS_HAT2Y:
   733                 case ABS_HAT3X:
   734                 case ABS_HAT3Y:
   735                     code -= ABS_HAT0X;
   736                     HandleHat(joystick, code / 2, code % 2, events[i].value);
   737                     break;
   738                 default:
   739                     events[i].value =
   740                         AxisCorrect(joystick, code, events[i].value);
   741                     SDL_PrivateJoystickAxis(joystick,
   742                                             joystick->hwdata->abs_map[code],
   743                                             events[i].value);
   744                     break;
   745                 }
   746                 break;
   747             case EV_REL:
   748                 switch (code) {
   749                 case REL_X:
   750                 case REL_Y:
   751                     code -= REL_X;
   752                     HandleBall(joystick, code / 2, code % 2, events[i].value);
   753                     break;
   754                 default:
   755                     break;
   756                 }
   757                 break;
   758             case EV_SYN:
   759                 switch (code) {
   760                 case SYN_DROPPED :
   761 #ifdef DEBUG_INPUT_EVENTS
   762                     printf("Event SYN_DROPPED detected\n");
   763 #endif
   764                     PollAllValues(joystick);
   765                     break;
   766                 default:
   767                     break;
   768                 }
   769             default:
   770                 break;
   771             }
   772         }
   773     }
   774 }
   775 
   776 void
   777 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   778 {
   779     int i;
   780 
   781     HandleInputEvents(joystick);
   782 
   783     /* Deliver ball motion updates */
   784     for (i = 0; i < joystick->nballs; ++i) {
   785         int xrel, yrel;
   786 
   787         xrel = joystick->hwdata->balls[i].axis[0];
   788         yrel = joystick->hwdata->balls[i].axis[1];
   789         if (xrel || yrel) {
   790             joystick->hwdata->balls[i].axis[0] = 0;
   791             joystick->hwdata->balls[i].axis[1] = 0;
   792             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
   793         }
   794     }
   795 }
   796 
   797 /* Function to close a joystick after use */
   798 void
   799 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   800 {
   801     if (joystick->hwdata) {
   802         close(joystick->hwdata->fd);
   803         if (joystick->hwdata->item) {
   804             joystick->hwdata->item->hwdata = NULL;
   805         }
   806         SDL_free(joystick->hwdata->hats);
   807         SDL_free(joystick->hwdata->balls);
   808         SDL_free(joystick->hwdata->fname);
   809         SDL_free(joystick->hwdata);
   810     }
   811 }
   812 
   813 /* Function to perform any system-specific joystick related cleanup */
   814 void
   815 SDL_SYS_JoystickQuit(void)
   816 {
   817     SDL_joylist_item *item = NULL;
   818     SDL_joylist_item *next = NULL;
   819 
   820     for (item = SDL_joylist; item; item = next) {
   821         next = item->next;
   822         SDL_free(item->path);
   823         SDL_free(item->name);
   824         SDL_free(item);
   825     }
   826 
   827     SDL_joylist = SDL_joylist_tail = NULL;
   828 
   829     numjoysticks = 0;
   830     instance_counter = 0;
   831 
   832 #if SDL_USE_LIBUDEV
   833     SDL_UDEV_DelCallback(joystick_udev_callback);
   834     SDL_UDEV_Quit();
   835 #endif
   836 }
   837 
   838 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   839 {
   840     return JoystickByDevIndex(device_index)->guid;
   841 }
   842 
   843 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   844 {
   845     return joystick->hwdata->guid;
   846 }
   847 
   848 #endif /* SDL_JOYSTICK_LINUX */
   849 
   850 /* vi: set ts=4 sw=4 expandtab: */