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