src/joystick/linux/SDL_sysjoystick.c
author Ryan C. Gordon <icculus@icculus.org>
Sat, 14 Jun 2014 23:31:23 -0400
changeset 8860 c4133d635375
parent 8149 681eb46b8ac4
child 9321 01966f6feadc
permissions -rw-r--r--
Removed SDL_SYS_JoystickNeedsPolling().

It was simpler to just have the polling (actually: hotplug detection)
functions return immediately if it's not an appropriate time to poll.

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