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