src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 02 Feb 2014 00:53:27 -0800
changeset 8149 681eb46b8ac4
parent 8138 0fbc97d82043
child 8860 c4133d635375
permissions -rw-r--r--
Fixed bug 2374 - Update copyright for 2014...

Is it that time already??
     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 SDL_bool SDL_SYS_JoystickNeedsPolling()
   396 {
   397 #if SDL_USE_LIBUDEV
   398     return SDL_TRUE;
   399 #endif
   400     
   401     return SDL_FALSE;
   402 }
   403 
   404 static SDL_joylist_item *
   405 JoystickByDevIndex(int device_index)
   406 {
   407     SDL_joylist_item *item = SDL_joylist;
   408 
   409     if ((device_index < 0) || (device_index >= numjoysticks)) {
   410         return NULL;
   411     }
   412 
   413     while (device_index > 0) {
   414         SDL_assert(item != NULL);
   415         device_index--;
   416         item = item->next;
   417     }
   418 
   419     return item;
   420 }
   421 
   422 /* Function to get the device-dependent name of a joystick */
   423 const char *
   424 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   425 {
   426     return JoystickByDevIndex(device_index)->name;
   427 }
   428 
   429 /* Function to perform the mapping from device index to the instance id for this index */
   430 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   431 {
   432     return JoystickByDevIndex(device_index)->device_instance;
   433 }
   434 
   435 static int
   436 allocate_hatdata(SDL_Joystick * joystick)
   437 {
   438     int i;
   439 
   440     joystick->hwdata->hats =
   441         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   442                                          sizeof(struct hwdata_hat));
   443     if (joystick->hwdata->hats == NULL) {
   444         return (-1);
   445     }
   446     for (i = 0; i < joystick->nhats; ++i) {
   447         joystick->hwdata->hats[i].axis[0] = 1;
   448         joystick->hwdata->hats[i].axis[1] = 1;
   449     }
   450     return (0);
   451 }
   452 
   453 static int
   454 allocate_balldata(SDL_Joystick * joystick)
   455 {
   456     int i;
   457 
   458     joystick->hwdata->balls =
   459         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   460                                           sizeof(struct hwdata_ball));
   461     if (joystick->hwdata->balls == NULL) {
   462         return (-1);
   463     }
   464     for (i = 0; i < joystick->nballs; ++i) {
   465         joystick->hwdata->balls[i].axis[0] = 0;
   466         joystick->hwdata->balls[i].axis[1] = 0;
   467     }
   468     return (0);
   469 }
   470 
   471 static void
   472 ConfigJoystick(SDL_Joystick * joystick, int fd)
   473 {
   474     int i, t;
   475     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   476     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   477     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   478 
   479     /* See if this device uses the new unified event API */
   480     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   481         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   482         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   483 
   484         /* Get the number of buttons, axes, and other thingamajigs */
   485         for (i = BTN_JOYSTICK; i < KEY_MAX; ++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 = BTN_MISC; i < BTN_JOYSTICK; ++i) {
   495             if (test_bit(i, keybit)) {
   496 #ifdef DEBUG_INPUT_EVENTS
   497                 printf("Joystick has button: 0x%x\n", i);
   498 #endif
   499                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   500                 ++joystick->nbuttons;
   501             }
   502         }
   503         for (i = 0; i < ABS_MISC; ++i) {
   504             /* Skip hats */
   505             if (i == ABS_HAT0X) {
   506                 i = ABS_HAT3Y;
   507                 continue;
   508             }
   509             if (test_bit(i, absbit)) {
   510                 struct input_absinfo absinfo;
   511 
   512                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   513                     continue;
   514                 }
   515 #ifdef DEBUG_INPUT_EVENTS
   516                 printf("Joystick has absolute axis: 0x%.2x\n", i);
   517                 printf("Values = { %d, %d, %d, %d, %d }\n",
   518                        absinfo.value, absinfo.minimum, absinfo.maximum,
   519                        absinfo.fuzz, absinfo.flat);
   520 #endif /* DEBUG_INPUT_EVENTS */
   521                 joystick->hwdata->abs_map[i] = joystick->naxes;
   522                 if (absinfo.minimum == absinfo.maximum) {
   523                     joystick->hwdata->abs_correct[i].used = 0;
   524                 } else {
   525                     joystick->hwdata->abs_correct[i].used = 1;
   526                     joystick->hwdata->abs_correct[i].coef[0] =
   527                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   528                     joystick->hwdata->abs_correct[i].coef[1] =
   529                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   530                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   531                     if (t != 0) {
   532                         joystick->hwdata->abs_correct[i].coef[2] =
   533                             (1 << 28) / t;
   534                     } else {
   535                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   536                     }
   537                 }
   538                 ++joystick->naxes;
   539             }
   540         }
   541         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   542             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   543                 struct input_absinfo absinfo;
   544 
   545                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
   546                     continue;
   547                 }
   548 #ifdef DEBUG_INPUT_EVENTS
   549                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   550                 printf("Values = { %d, %d, %d, %d, %d }\n",
   551                        absinfo.value, absinfo.minimum, absinfo.maximum,
   552                        absinfo.fuzz, absinfo.flat);
   553 #endif /* DEBUG_INPUT_EVENTS */
   554                 ++joystick->nhats;
   555             }
   556         }
   557         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   558             ++joystick->nballs;
   559         }
   560 
   561         /* Allocate data to keep track of these thingamajigs */
   562         if (joystick->nhats > 0) {
   563             if (allocate_hatdata(joystick) < 0) {
   564                 joystick->nhats = 0;
   565             }
   566         }
   567         if (joystick->nballs > 0) {
   568             if (allocate_balldata(joystick) < 0) {
   569                 joystick->nballs = 0;
   570             }
   571         }
   572     }
   573 }
   574 
   575 
   576 /* Function to open a joystick for use.
   577    The joystick to open is specified by the index field of the joystick.
   578    This should fill the nbuttons and naxes fields of the joystick structure.
   579    It returns 0, or -1 if there is an error.
   580  */
   581 int
   582 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   583 {
   584     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   585     char *fname = NULL;
   586     int fd = -1;
   587 
   588     if (item == NULL) {
   589         return SDL_SetError("No such device");
   590     }
   591 
   592     fname = item->path;
   593     fd = open(fname, O_RDONLY, 0);
   594     if (fd < 0) {
   595         return SDL_SetError("Unable to open %s", fname);
   596     }
   597 
   598     joystick->instance_id = item->device_instance;
   599     joystick->hwdata = (struct joystick_hwdata *)
   600         SDL_malloc(sizeof(*joystick->hwdata));
   601     if (joystick->hwdata == NULL) {
   602         close(fd);
   603         return SDL_OutOfMemory();
   604     }
   605     SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   606     joystick->hwdata->item = item;
   607     joystick->hwdata->guid = item->guid;
   608     joystick->hwdata->fd = fd;
   609     joystick->hwdata->fname = SDL_strdup(item->path);
   610     if (joystick->hwdata->fname == NULL) {
   611         SDL_free(joystick->hwdata);
   612         joystick->hwdata = NULL;
   613         close(fd);
   614         return SDL_OutOfMemory();
   615     }
   616 
   617     SDL_assert(item->hwdata == NULL);
   618     item->hwdata = joystick->hwdata;
   619 
   620     /* Set the joystick to non-blocking read mode */
   621     fcntl(fd, F_SETFL, O_NONBLOCK);
   622 
   623     /* Get the number of buttons and axes on the joystick */
   624     ConfigJoystick(joystick, fd);
   625 
   626     /* mark joystick as fresh and ready */
   627     joystick->hwdata->fresh = 1;
   628 
   629     return (0);
   630 }
   631 
   632 /* Function to determine is this joystick is attached to the system right now */
   633 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   634 {
   635     return !joystick->closed && (joystick->hwdata->item != NULL);
   636 }
   637 
   638 static SDL_INLINE void
   639 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   640 {
   641     struct hwdata_hat *the_hat;
   642     const Uint8 position_map[3][3] = {
   643         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   644         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   645         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   646     };
   647 
   648     the_hat = &stick->hwdata->hats[hat];
   649     if (value < 0) {
   650         value = 0;
   651     } else if (value == 0) {
   652         value = 1;
   653     } else if (value > 0) {
   654         value = 2;
   655     }
   656     if (value != the_hat->axis[axis]) {
   657         the_hat->axis[axis] = value;
   658         SDL_PrivateJoystickHat(stick, hat,
   659                                position_map[the_hat->
   660                                             axis[1]][the_hat->axis[0]]);
   661     }
   662 }
   663 
   664 static SDL_INLINE void
   665 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   666 {
   667     stick->hwdata->balls[ball].axis[axis] += value;
   668 }
   669 
   670 
   671 static SDL_INLINE int
   672 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   673 {
   674     struct axis_correct *correct;
   675 
   676     correct = &joystick->hwdata->abs_correct[which];
   677     if (correct->used) {
   678         value *= 2;
   679         if (value > correct->coef[0]) {
   680             if (value < correct->coef[1]) {
   681                 return 0;
   682             }
   683             value -= correct->coef[1];
   684         } else {
   685             value -= correct->coef[0];
   686         }
   687         value *= correct->coef[2];
   688         value >>= 13;
   689     }
   690 
   691     /* Clamp and return */
   692     if (value < -32768)
   693         return -32768;
   694     if (value > 32767)
   695         return 32767;
   696 
   697     return value;
   698 }
   699 
   700 static SDL_INLINE void
   701 PollAllValues(SDL_Joystick * joystick)
   702 {
   703     struct input_absinfo absinfo;
   704     int a, b = 0;
   705 
   706     /* Poll all axis */
   707     for (a = ABS_X; b < ABS_MAX; a++) {
   708         switch (a) {
   709         case ABS_HAT0X:
   710         case ABS_HAT0Y:
   711         case ABS_HAT1X:
   712         case ABS_HAT1Y:
   713         case ABS_HAT2X:
   714         case ABS_HAT2Y:
   715         case ABS_HAT3X:
   716         case ABS_HAT3Y:
   717             /* ingore hats */
   718             break;
   719         default:
   720             if (joystick->hwdata->abs_correct[b].used) {
   721                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   722                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   723 
   724 #ifdef DEBUG_INPUT_EVENTS
   725                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   726                         joystick->hwdata->abs_map[b], a, absinfo.value);
   727 #endif
   728                     SDL_PrivateJoystickAxis(joystick,
   729                             joystick->hwdata->abs_map[b],
   730                             absinfo.value);
   731                 }
   732             }
   733             b++;
   734         }
   735     }
   736 }
   737 
   738 static SDL_INLINE void
   739 HandleInputEvents(SDL_Joystick * joystick)
   740 {
   741     struct input_event events[32];
   742     int i, len;
   743     int code;
   744 
   745     if (joystick->hwdata->fresh) {
   746         PollAllValues(joystick);
   747         joystick->hwdata->fresh = 0;
   748     }
   749 
   750     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   751         len /= sizeof(events[0]);
   752         for (i = 0; i < len; ++i) {
   753             code = events[i].code;
   754             switch (events[i].type) {
   755             case EV_KEY:
   756                 if (code >= BTN_MISC) {
   757                     code -= BTN_MISC;
   758                     SDL_PrivateJoystickButton(joystick,
   759                                               joystick->hwdata->key_map[code],
   760                                               events[i].value);
   761                 }
   762                 break;
   763             case EV_ABS:
   764                 if (code >= ABS_MISC) {
   765                     break;
   766                 }
   767 
   768                 switch (code) {
   769                 case ABS_HAT0X:
   770                 case ABS_HAT0Y:
   771                 case ABS_HAT1X:
   772                 case ABS_HAT1Y:
   773                 case ABS_HAT2X:
   774                 case ABS_HAT2Y:
   775                 case ABS_HAT3X:
   776                 case ABS_HAT3Y:
   777                     code -= ABS_HAT0X;
   778                     HandleHat(joystick, code / 2, code % 2, events[i].value);
   779                     break;
   780                 default:
   781                     events[i].value =
   782                         AxisCorrect(joystick, code, events[i].value);
   783                     SDL_PrivateJoystickAxis(joystick,
   784                                             joystick->hwdata->abs_map[code],
   785                                             events[i].value);
   786                     break;
   787                 }
   788                 break;
   789             case EV_REL:
   790                 switch (code) {
   791                 case REL_X:
   792                 case REL_Y:
   793                     code -= REL_X;
   794                     HandleBall(joystick, code / 2, code % 2, events[i].value);
   795                     break;
   796                 default:
   797                     break;
   798                 }
   799                 break;
   800             case EV_SYN:
   801                 switch (code) {
   802                 case SYN_DROPPED :
   803 #ifdef DEBUG_INPUT_EVENTS
   804                     printf("Event SYN_DROPPED detected\n");
   805 #endif
   806                     PollAllValues(joystick);
   807                     break;
   808                 default:
   809                     break;
   810                 }
   811             default:
   812                 break;
   813             }
   814         }
   815     }
   816 }
   817 
   818 void
   819 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   820 {
   821     int i;
   822 
   823     HandleInputEvents(joystick);
   824 
   825     /* Deliver ball motion updates */
   826     for (i = 0; i < joystick->nballs; ++i) {
   827         int xrel, yrel;
   828 
   829         xrel = joystick->hwdata->balls[i].axis[0];
   830         yrel = joystick->hwdata->balls[i].axis[1];
   831         if (xrel || yrel) {
   832             joystick->hwdata->balls[i].axis[0] = 0;
   833             joystick->hwdata->balls[i].axis[1] = 0;
   834             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
   835         }
   836     }
   837 }
   838 
   839 /* Function to close a joystick after use */
   840 void
   841 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   842 {
   843     if (joystick->hwdata) {
   844         close(joystick->hwdata->fd);
   845         if (joystick->hwdata->item) {
   846             joystick->hwdata->item->hwdata = NULL;
   847         }
   848         SDL_free(joystick->hwdata->hats);
   849         SDL_free(joystick->hwdata->balls);
   850         SDL_free(joystick->hwdata->fname);
   851         SDL_free(joystick->hwdata);
   852         joystick->hwdata = NULL;
   853     }
   854     joystick->closed = 1;
   855 }
   856 
   857 /* Function to perform any system-specific joystick related cleanup */
   858 void
   859 SDL_SYS_JoystickQuit(void)
   860 {
   861     SDL_joylist_item *item = NULL;
   862     SDL_joylist_item *next = NULL;
   863 
   864     for (item = SDL_joylist; item; item = next) {
   865         next = item->next;
   866         SDL_free(item->path);
   867         SDL_free(item->name);
   868         SDL_free(item);
   869     }
   870 
   871     SDL_joylist = SDL_joylist_tail = NULL;
   872 
   873     numjoysticks = 0;
   874     instance_counter = 0;
   875 
   876 #if SDL_USE_LIBUDEV
   877     SDL_UDEV_DelCallback(joystick_udev_callback);
   878     SDL_UDEV_Quit();
   879 #endif
   880 }
   881 
   882 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
   883 {
   884     return JoystickByDevIndex(device_index)->guid;
   885 }
   886 
   887 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
   888 {
   889     return joystick->hwdata->guid;
   890 }
   891 
   892 #endif /* SDL_JOYSTICK_LINUX */
   893 
   894 /* vi: set ts=4 sw=4 expandtab: */