src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 26 Aug 2016 11:16:44 -0700
changeset 10225 3134026517cb
parent 9998 f67cf37e9cd4
child 10226 cb13d22b7f09
permissions -rw-r--r--
commit 1170112da3776fdb06425f62d57b63144c33dc51
Author: James Zipperer <james.zipperer@synapse.com>
Date: Sun Aug 21 01:19:19 2016 -0700

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