src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Sun, 24 Feb 2013 12:55:51 -0800
changeset 6910 a3d4fd1ba315
parent 6885 700f1b25f77f
child 6911 c683ff6484b0
permissions -rw-r--r--
Fixed compiling on older Linux systems without libudev
     1 /*
     2   Simple DirectMedia Layer
     3   Copyright (C) 1997-2013 Sam Lantinga <slouken@libsdl.org>
     4 
     5   This software is provided 'as-is', without any express or implied
     6   warranty.  In no event will the authors be held liable for any damages
     7   arising from the use of this software.
     8 
     9   Permission is granted to anyone to use this software for any purpose,
    10   including commercial applications, and to alter it and redistribute it
    11   freely, subject to the following restrictions:
    12 
    13   1. The origin of this software must not be misrepresented; you must not
    14      claim that you wrote the original software. If you use this software
    15      in a product, an acknowledgment in the product documentation would be
    16      appreciated but is not required.
    17   2. Altered source versions must be plainly marked as such, and must not be
    18      misrepresented as being the original software.
    19   3. This notice may not be removed or altered from any source distribution.
    20 */
    21 #include "SDL_config.h"
    22 
    23 #ifdef SDL_JOYSTICK_LINUX
    24 
    25 #ifndef SDL_INPUT_LINUXEV
    26 #error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
    27 #endif
    28 
    29 /* This is the system specific header for the SDL joystick API */
    30 
    31 #include <sys/stat.h>
    32 #include <unistd.h>
    33 #include <fcntl.h>
    34 #include <sys/ioctl.h>
    35 #include <limits.h>             /* For the definition of PATH_MAX */
    36 #include <linux/joystick.h>
    37 
    38 #include "SDL_assert.h"
    39 #include "SDL_joystick.h"
    40 #include "SDL_endian.h"
    41 #include "../SDL_sysjoystick.h"
    42 #include "../SDL_joystick_c.h"
    43 #include "SDL_sysjoystick_c.h"
    44 
    45 /* !!! FIXME: move this somewhere else. */
    46 #if !SDL_EVENTS_DISABLED
    47 #include "../../events/SDL_events_c.h"
    48 #endif
    49 
    50 /* This isn't defined in older Linux kernel headers */
    51 #ifndef SYN_DROPPED
    52 #define SYN_DROPPED 3
    53 #endif
    54 
    55 /*
    56  * !!! FIXME: move all the udev stuff to src/core/linux, so I can reuse it
    57  * !!! FIXME:  for audio hardware disconnects.
    58  */
    59 #ifdef HAVE_LIBUDEV_H
    60 #define SDL_USE_LIBUDEV 1
    61 #include "SDL_loadso.h"
    62 #include <libudev.h>
    63 #include <sys/time.h>
    64 #include <sys/types.h>
    65 #include <unistd.h>
    66 
    67 /* we never link directly to libudev. */
    68 /* !!! FIXME: can we generalize this? ALSA, etc, do the same things. */
    69 static const char *udev_library = "libudev.so.0";
    70 static void *udev_handle = NULL;
    71 
    72 /* !!! FIXME: this is kinda ugly. */
    73 static SDL_bool
    74 load_udev_sym(const char *fn, void **addr)
    75 {
    76     *addr = SDL_LoadFunction(udev_handle, fn);
    77     if (*addr == NULL) {
    78         /* Don't call SDL_SetError(): SDL_LoadFunction already did. */
    79         return SDL_FALSE;
    80     }
    81 
    82     return SDL_TRUE;
    83 }
    84 
    85 /* libudev entry points... */
    86 static const char *(*UDEV_udev_device_get_action)(struct udev_device *) = NULL;
    87 static const char *(*UDEV_udev_device_get_devnode)(struct udev_device *) = NULL;
    88 static const char *(*UDEV_udev_device_get_property_value)(struct udev_device *, const char *) = NULL;
    89 static struct udev_device *(*UDEV_udev_device_new_from_syspath)(struct udev *, const char *) = NULL;
    90 static void (*UDEV_udev_device_unref)(struct udev_device *) = NULL;
    91 static int (*UDEV_udev_enumerate_add_match_property)(struct udev_enumerate *, const char *, const char *) = NULL;
    92 static int (*UDEV_udev_enumerate_add_match_subsystem)(struct udev_enumerate *, const char *) = NULL;
    93 static struct udev_list_entry *(*UDEV_udev_enumerate_get_list_entry)(struct udev_enumerate *) = NULL;
    94 static struct udev_enumerate *(*UDEV_udev_enumerate_new)(struct udev *) = NULL;
    95 static int (*UDEV_udev_enumerate_scan_devices)(struct udev_enumerate *) = NULL;
    96 static void (*UDEV_udev_enumerate_unref)(struct udev_enumerate *) = NULL;
    97 static const char *(*UDEV_udev_list_entry_get_name)(struct udev_list_entry *) = NULL;
    98 static struct udev_list_entry *(*UDEV_udev_list_entry_get_next)(struct udev_list_entry *) = NULL;
    99 static int (*UDEV_udev_monitor_enable_receiving)(struct udev_monitor *) = NULL;
   100 static int (*UDEV_udev_monitor_filter_add_match_subsystem_devtype)(struct udev_monitor *, const char *, const char *) = NULL;
   101 static int (*UDEV_udev_monitor_get_fd)(struct udev_monitor *) = NULL;
   102 static struct udev_monitor *(*UDEV_udev_monitor_new_from_netlink)(struct udev *, const char *) = NULL;
   103 static struct udev_device *(*UDEV_udev_monitor_receive_device)(struct udev_monitor *) = NULL;
   104 static void (*UDEV_udev_monitor_unref)(struct udev_monitor *) = NULL;
   105 static struct udev *(*UDEV_udev_new)(void) = NULL;
   106 static void (*UDEV_udev_unref)(struct udev *) = NULL;
   107 
   108 static int
   109 load_udev_syms(void)
   110 {
   111     /* cast funcs to char* first, to please GCC's strict aliasing rules. */
   112     #define SDL_UDEV_SYM(x) \
   113         if (!load_udev_sym(#x, (void **) (char *) &UDEV_##x)) return -1
   114 
   115     SDL_UDEV_SYM(udev_device_get_action);
   116     SDL_UDEV_SYM(udev_device_get_devnode);
   117     SDL_UDEV_SYM(udev_device_get_property_value);
   118     SDL_UDEV_SYM(udev_device_new_from_syspath);
   119     SDL_UDEV_SYM(udev_device_unref);
   120     SDL_UDEV_SYM(udev_enumerate_add_match_property);
   121     SDL_UDEV_SYM(udev_enumerate_add_match_subsystem);
   122     SDL_UDEV_SYM(udev_enumerate_get_list_entry);
   123     SDL_UDEV_SYM(udev_enumerate_new);
   124     SDL_UDEV_SYM(udev_enumerate_scan_devices);
   125     SDL_UDEV_SYM(udev_enumerate_unref);
   126     SDL_UDEV_SYM(udev_list_entry_get_name);
   127     SDL_UDEV_SYM(udev_list_entry_get_next);
   128     SDL_UDEV_SYM(udev_monitor_enable_receiving);
   129     SDL_UDEV_SYM(udev_monitor_filter_add_match_subsystem_devtype);
   130     SDL_UDEV_SYM(udev_monitor_get_fd);
   131     SDL_UDEV_SYM(udev_monitor_new_from_netlink);
   132     SDL_UDEV_SYM(udev_monitor_receive_device);
   133     SDL_UDEV_SYM(udev_monitor_unref);
   134     SDL_UDEV_SYM(udev_new);
   135     SDL_UDEV_SYM(udev_unref);
   136 
   137     #undef SDL_UDEV_SYM
   138 
   139     return 0;
   140 }
   141 
   142 static void
   143 UnloadUDEVLibrary(void)
   144 {
   145     if (udev_handle != NULL) {
   146         SDL_UnloadObject(udev_handle);
   147         udev_handle = NULL;
   148     }
   149 }
   150 
   151 static int
   152 LoadUDEVLibrary(void)
   153 {
   154     int retval = 0;
   155     if (udev_handle == NULL) {
   156         udev_handle = SDL_LoadObject(udev_library);
   157         if (udev_handle == NULL) {
   158             retval = -1;
   159             /* Don't call SDL_SetError(): SDL_LoadObject already did. */
   160         } else {
   161             retval = load_udev_syms();
   162             if (retval < 0) {
   163                 UnloadUDEVLibrary();
   164             }
   165         }
   166     }
   167 
   168     return retval;
   169 }
   170 
   171 static struct udev *udev = NULL;
   172 static struct udev_monitor *udev_mon = NULL;
   173 #endif
   174 
   175 
   176 /* A linked list of available joysticks */
   177 typedef struct SDL_joylist_item
   178 {
   179     int device_instance;
   180     char *path;   /* "/dev/input/event2" or whatever */
   181     char *name;   /* "SideWinder 3D Pro" or whatever */
   182     SDL_JoystickGUID guid;
   183     dev_t devnum;
   184     struct joystick_hwdata *hwdata;
   185     struct SDL_joylist_item *next;
   186 } SDL_joylist_item;
   187 
   188 static SDL_joylist_item *SDL_joylist = NULL;
   189 static SDL_joylist_item *SDL_joylist_tail = NULL;
   190 static int numjoysticks = 0;
   191 static int instance_counter = 0;
   192 
   193 #define test_bit(nr, addr) \
   194     (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
   195 #define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
   196 
   197 static int
   198 IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
   199 {
   200     unsigned long evbit[NBITS(EV_MAX)] = { 0 };
   201     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   202     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   203     struct input_id inpid;
   204     Uint16 *guid16 = (Uint16 *) ((char *) &guid->data);
   205 
   206     if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
   207         (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
   208         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
   209         return (0);
   210     }
   211 
   212     if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
   213           test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
   214         return 0;
   215     }
   216 
   217     if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
   218         return 0;
   219     }
   220 
   221     if (ioctl(fd, EVIOCGID, &inpid) < 0) {
   222         return 0;
   223     }
   224 
   225 #ifdef DEBUG_JOYSTICK
   226     printf("Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
   227 #endif
   228 
   229     SDL_memset(guid->data, 0, sizeof(guid->data));
   230 
   231     /* We only need 16 bits for each of these; space them out to fill 128. */
   232     /* Byteswap so devices get same GUID on little/big endian platforms. */
   233     *(guid16++) = SDL_SwapLE16(inpid.bustype);
   234     *(guid16++) = 0;
   235 
   236     if (inpid.vendor && inpid.product && inpid.version) {
   237         *(guid16++) = SDL_SwapLE16(inpid.vendor);
   238         *(guid16++) = 0;
   239         *(guid16++) = SDL_SwapLE16(inpid.product);
   240         *(guid16++) = 0;
   241         *(guid16++) = SDL_SwapLE16(inpid.version);
   242         *(guid16++) = 0;
   243     } else {
   244         SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
   245     }
   246 
   247     return 1;
   248 }
   249 
   250 
   251 /* !!! FIXME: I would love to dump this code and use libudev instead. */
   252 static int
   253 MaybeAddDevice(const char *path)
   254 {
   255     struct stat sb;
   256     int fd = -1;
   257     int isstick = 0;
   258     char namebuf[128];
   259     SDL_JoystickGUID guid;
   260     SDL_joylist_item *item;
   261 
   262     if (path == NULL) {
   263         return -1;
   264     }
   265 
   266     if (stat(path, &sb) == -1) {
   267         return -1;
   268     }
   269 
   270     /* Check to make sure it's not already in list. */
   271     for (item = SDL_joylist; item != NULL; item = item->next) {
   272         if (sb.st_rdev == item->devnum) {
   273             return -1;  /* already have this one */
   274         }
   275     }
   276 
   277     fd = open(path, O_RDONLY, 0);
   278     if (fd < 0) {
   279         return -1;
   280     }
   281 
   282 #ifdef DEBUG_INPUT_EVENTS
   283     printf("Checking %s\n", path);
   284 #endif
   285 
   286     isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
   287     close(fd);
   288     if (!isstick) {
   289         return -1;
   290     }
   291 
   292     item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
   293     if (item == NULL) {
   294         return -1;
   295     }
   296 
   297     SDL_zerop(item);
   298     item->devnum = sb.st_rdev;
   299     item->path = SDL_strdup(path);
   300     item->name = SDL_strdup(namebuf);
   301     item->guid = guid;
   302 
   303     if ( (item->path == NULL) || (item->name == NULL) ) {
   304          SDL_free(item->path);
   305          SDL_free(item->name);
   306          SDL_free(item);
   307          return -1;
   308     }
   309 
   310     item->device_instance = instance_counter++;
   311     if (SDL_joylist_tail == NULL) {
   312         SDL_joylist = SDL_joylist_tail = item;
   313     } else {
   314         SDL_joylist_tail->next = item;
   315         SDL_joylist_tail = item;
   316     }
   317 
   318     return numjoysticks++;
   319 }
   320 
   321 #if SDL_USE_LIBUDEV
   322 /* !!! FIXME: I would love to dump this code and use libudev instead. */
   323 static int
   324 MaybeRemoveDevice(const char *path)
   325 {
   326     SDL_joylist_item *item;
   327     SDL_joylist_item *prev = NULL;
   328 
   329     if (path == NULL) {
   330         return -1;
   331     }
   332 
   333     for (item = SDL_joylist; item != NULL; item = item->next) {
   334         /* found it, remove it. */
   335         if (SDL_strcmp(path, item->path) == 0) {
   336             const int retval = item->device_instance;
   337             if (item->hwdata) {
   338                 item->hwdata->item = NULL;
   339             }
   340             if (prev != NULL) {
   341                 prev->next = item->next;
   342             } else {
   343                 SDL_assert(SDL_joylist == item);
   344                 SDL_joylist = item->next;
   345             }
   346             if (item == SDL_joylist_tail) {
   347                 SDL_joylist_tail = prev;
   348             }
   349             SDL_free(item->path);
   350             SDL_free(item->name);
   351             SDL_free(item);
   352             numjoysticks--;
   353             return retval;
   354         }
   355         prev = item;
   356     }
   357 
   358     return -1;
   359 }
   360 #endif
   361 
   362 static int
   363 JoystickInitWithoutUdev(void)
   364 {
   365     int i;
   366     char path[PATH_MAX];
   367 
   368     /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
   369     /* !!! FIXME:  we could at least readdir() through /dev/input...? */
   370     /* !!! FIXME:  (or delete this and rely on libudev?) */
   371     for (i = 0; i < 32; i++) {
   372         SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
   373         MaybeAddDevice(path);
   374     }
   375 
   376     return numjoysticks;
   377 }
   378 
   379 
   380 #if SDL_USE_LIBUDEV
   381 static int
   382 JoystickInitWithUdev(void)
   383 {
   384     struct udev_enumerate *enumerate = NULL;
   385     struct udev_list_entry *devs = NULL;
   386     struct udev_list_entry *item = NULL;
   387 
   388     SDL_assert(udev == NULL);
   389     udev = UDEV_udev_new();
   390     if (udev == NULL) {
   391         SDL_SetError("udev_new() failed");
   392         return -1;
   393     }
   394 
   395     udev_mon = UDEV_udev_monitor_new_from_netlink(udev, "udev");
   396     if (udev_mon != NULL) {  /* okay if it's NULL, we just lose hotplugging. */
   397         UDEV_udev_monitor_filter_add_match_subsystem_devtype(udev_mon,
   398                                                              "input", NULL);
   399         UDEV_udev_monitor_enable_receiving(udev_mon);
   400     }
   401 
   402     enumerate = UDEV_udev_enumerate_new(udev);
   403     if (enumerate == NULL) {
   404         SDL_SetError("udev_enumerate_new() failed");
   405         return -1;
   406     }
   407 
   408     UDEV_udev_enumerate_add_match_subsystem(enumerate, "input");
   409     UDEV_udev_enumerate_add_match_property(enumerate, "ID_INPUT_JOYSTICK", "1");
   410     UDEV_udev_enumerate_scan_devices(enumerate);
   411     devs = UDEV_udev_enumerate_get_list_entry(enumerate);
   412     for (item = devs; item; item = UDEV_udev_list_entry_get_next(item)) {
   413         const char *path = UDEV_udev_list_entry_get_name(item);
   414         struct udev_device *dev = UDEV_udev_device_new_from_syspath(udev, path);
   415         MaybeAddDevice(UDEV_udev_device_get_devnode(dev));
   416         UDEV_udev_device_unref(dev);
   417     }
   418 
   419     UDEV_udev_enumerate_unref(enumerate);
   420 
   421     return numjoysticks;
   422 }
   423 #endif
   424 
   425 int
   426 SDL_SYS_JoystickInit(void)
   427 {
   428     /* First see if the user specified one or more joysticks to use */
   429     if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
   430         char *envcopy, *envpath, *delim;
   431         envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
   432         envpath = envcopy;
   433         while (envpath != NULL) {
   434             delim = SDL_strchr(envpath, ':');
   435             if (delim != NULL) {
   436                 *delim++ = '\0';
   437             }
   438             MaybeAddDevice(envpath);
   439             envpath = delim;
   440         }
   441         SDL_free(envcopy);
   442     }
   443 
   444 #if SDL_USE_LIBUDEV
   445     if (LoadUDEVLibrary() == 0) {   /* okay if this fails, FOR NOW. */
   446         return JoystickInitWithUdev();
   447     }
   448 #endif
   449 
   450     return JoystickInitWithoutUdev();
   451 }
   452 
   453 int SDL_SYS_NumJoysticks()
   454 {
   455     return numjoysticks;
   456 }
   457 
   458 static SDL_bool
   459 HotplugUpdateAvailable(void)
   460 {
   461 #if SDL_USE_LIBUDEV
   462     if (udev_mon != NULL) {
   463         const int fd = UDEV_udev_monitor_get_fd(udev_mon);
   464         fd_set fds;
   465         struct timeval tv;
   466 
   467         FD_ZERO(&fds);
   468         FD_SET(fd, &fds);
   469         tv.tv_sec = 0;
   470         tv.tv_usec = 0;
   471         if ((select(fd+1, &fds, NULL, NULL, &tv) > 0) && (FD_ISSET(fd, &fds))) {
   472             return SDL_TRUE;
   473         }
   474     }
   475 #endif
   476 
   477     return SDL_FALSE;
   478 }
   479 
   480 void SDL_SYS_JoystickDetect()
   481 {
   482 #if SDL_USE_LIBUDEV
   483     struct udev_device *dev = NULL;
   484     const char *devnode = NULL;
   485     const char *action = NULL;
   486     const char *val = NULL;
   487 
   488     while (HotplugUpdateAvailable()) {
   489         dev = UDEV_udev_monitor_receive_device(udev_mon);
   490         if (dev == NULL) {
   491             break;
   492         }
   493         val = UDEV_udev_device_get_property_value(dev, "ID_INPUT_JOYSTICK");
   494         if ((!val) || (SDL_strcmp(val, "1") != 0)) {
   495             continue;
   496         }
   497 
   498         action = UDEV_udev_device_get_action(dev);
   499         devnode = UDEV_udev_device_get_devnode(dev);
   500 
   501         if (SDL_strcmp(action, "add") == 0) {
   502             const int device_index = MaybeAddDevice(devnode);
   503             if (device_index != -1) {
   504                 /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */
   505                 #if !SDL_EVENTS_DISABLED
   506                 SDL_Event event;
   507                 event.type = SDL_JOYDEVICEADDED;
   508 
   509                 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   510                     event.jdevice.which = device_index;
   511                     if ( (SDL_EventOK == NULL) ||
   512                          (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   513                         SDL_PushEvent(&event);
   514                     }
   515                 }
   516                 #endif // !SDL_EVENTS_DISABLED
   517             }
   518         } else if (SDL_strcmp(action, "remove") == 0) {
   519             const int inst = MaybeRemoveDevice(devnode);
   520             if (inst != -1) {
   521                 /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */
   522                 #if !SDL_EVENTS_DISABLED
   523                 SDL_Event event;
   524                 event.type = SDL_JOYDEVICEREMOVED;
   525 
   526                 if (SDL_GetEventState(event.type) == SDL_ENABLE) {
   527                     event.jdevice.which = inst;
   528                     if ( (SDL_EventOK == NULL) ||
   529                          (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
   530                         SDL_PushEvent(&event);
   531                     }
   532                 }
   533                 #endif // !SDL_EVENTS_DISABLED 
   534             }
   535         }
   536         UDEV_udev_device_unref(dev);
   537     }
   538 #endif
   539 }
   540 
   541 SDL_bool SDL_SYS_JoystickNeedsPolling()
   542 {
   543     /*
   544      * This results in a select() call, so technically we're polling to
   545      *  decide if we should poll, but I think this function is here because
   546      *  Windows has to do an enormous amount of work to detect new sticks,
   547      *  whereas libudev just needs to see if there's more data available on
   548      *  a socket...so this should be acceptable, I hope.
   549      */
   550     return HotplugUpdateAvailable();
   551 }
   552 
   553 static SDL_joylist_item *
   554 JoystickByDevIndex(int device_index)
   555 {
   556     SDL_joylist_item *item = SDL_joylist;
   557 
   558     if ((device_index < 0) || (device_index >= numjoysticks)) {
   559         return NULL;
   560     }
   561 
   562     while (device_index > 0) {
   563         SDL_assert(item != NULL);
   564         device_index--;
   565         item = item->next;
   566     }
   567 
   568     return item;
   569 }
   570 
   571 /* Function to get the device-dependent name of a joystick */
   572 const char *
   573 SDL_SYS_JoystickNameForDeviceIndex(int device_index)
   574 {
   575     return JoystickByDevIndex(device_index)->name;
   576 }
   577 
   578 /* Function to perform the mapping from device index to the instance id for this index */
   579 SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
   580 {
   581     return JoystickByDevIndex(device_index)->device_instance;
   582 }
   583 
   584 static int
   585 allocate_hatdata(SDL_Joystick * joystick)
   586 {
   587     int i;
   588 
   589     joystick->hwdata->hats =
   590         (struct hwdata_hat *) SDL_malloc(joystick->nhats *
   591                                          sizeof(struct hwdata_hat));
   592     if (joystick->hwdata->hats == NULL) {
   593         return (-1);
   594     }
   595     for (i = 0; i < joystick->nhats; ++i) {
   596         joystick->hwdata->hats[i].axis[0] = 1;
   597         joystick->hwdata->hats[i].axis[1] = 1;
   598     }
   599     return (0);
   600 }
   601 
   602 static int
   603 allocate_balldata(SDL_Joystick * joystick)
   604 {
   605     int i;
   606 
   607     joystick->hwdata->balls =
   608         (struct hwdata_ball *) SDL_malloc(joystick->nballs *
   609                                           sizeof(struct hwdata_ball));
   610     if (joystick->hwdata->balls == NULL) {
   611         return (-1);
   612     }
   613     for (i = 0; i < joystick->nballs; ++i) {
   614         joystick->hwdata->balls[i].axis[0] = 0;
   615         joystick->hwdata->balls[i].axis[1] = 0;
   616     }
   617     return (0);
   618 }
   619 
   620 static void
   621 ConfigJoystick(SDL_Joystick * joystick, int fd)
   622 {
   623     int i, t;
   624     unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
   625     unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
   626     unsigned long relbit[NBITS(REL_MAX)] = { 0 };
   627 
   628     /* See if this device uses the new unified event API */
   629     if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
   630         (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
   631         (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
   632 
   633         /* Get the number of buttons, axes, and other thingamajigs */
   634         for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
   635             if (test_bit(i, keybit)) {
   636 #ifdef DEBUG_INPUT_EVENTS
   637                 printf("Joystick has button: 0x%x\n", i);
   638 #endif
   639                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   640                 ++joystick->nbuttons;
   641             }
   642         }
   643         for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
   644             if (test_bit(i, keybit)) {
   645 #ifdef DEBUG_INPUT_EVENTS
   646                 printf("Joystick has button: 0x%x\n", i);
   647 #endif
   648                 joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
   649                 ++joystick->nbuttons;
   650             }
   651         }
   652         for (i = 0; i < ABS_MISC; ++i) {
   653             /* Skip hats */
   654             if (i == ABS_HAT0X) {
   655                 i = ABS_HAT3Y;
   656                 continue;
   657             }
   658             if (test_bit(i, absbit)) {
   659                 struct input_absinfo absinfo;
   660 
   661                 if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0)
   662                     continue;
   663 #ifdef DEBUG_INPUT_EVENTS
   664                 printf("Joystick has absolute axis: %x\n", i);
   665                 printf("Values = { %d, %d, %d, %d, %d }\n",
   666                        absinfo.value, absinfo.minimum, absinfo.maximum,
   667                        absinfo.fuzz, absinfo.flat);
   668 #endif /* DEBUG_INPUT_EVENTS */
   669                 joystick->hwdata->abs_map[i] = joystick->naxes;
   670                 if (absinfo.minimum == absinfo.maximum) {
   671                     joystick->hwdata->abs_correct[i].used = 0;
   672                 } else {
   673                     joystick->hwdata->abs_correct[i].used = 1;
   674                     joystick->hwdata->abs_correct[i].coef[0] =
   675                         (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
   676                     joystick->hwdata->abs_correct[i].coef[1] =
   677                         (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
   678                     t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
   679                     if (t != 0) {
   680                         joystick->hwdata->abs_correct[i].coef[2] =
   681                             (1 << 28) / t;
   682                     } else {
   683                         joystick->hwdata->abs_correct[i].coef[2] = 0;
   684                     }
   685                 }
   686                 ++joystick->naxes;
   687             }
   688         }
   689         for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
   690             if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
   691 #ifdef DEBUG_INPUT_EVENTS
   692                 printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
   693 #endif
   694                 ++joystick->nhats;
   695             }
   696         }
   697         if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
   698             ++joystick->nballs;
   699         }
   700 
   701         /* Allocate data to keep track of these thingamajigs */
   702         if (joystick->nhats > 0) {
   703             if (allocate_hatdata(joystick) < 0) {
   704                 joystick->nhats = 0;
   705             }
   706         }
   707         if (joystick->nballs > 0) {
   708             if (allocate_balldata(joystick) < 0) {
   709                 joystick->nballs = 0;
   710             }
   711         }
   712     }
   713 }
   714 
   715 
   716 /* Function to open a joystick for use.
   717    The joystick to open is specified by the index field of the joystick.
   718    This should fill the nbuttons and naxes fields of the joystick structure.
   719    It returns 0, or -1 if there is an error.
   720  */
   721 int
   722 SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
   723 {
   724     SDL_joylist_item *item = JoystickByDevIndex(device_index);
   725     char *fname = NULL;
   726     int fd = -1;
   727 
   728     if (item == NULL) {
   729         SDL_SetError("No such device");
   730         return -1;
   731     }
   732 
   733     fname = item->path;
   734     fd = open(fname, O_RDONLY, 0);
   735     if (fd < 0) {
   736         SDL_SetError("Unable to open %s", fname);
   737         return -1;
   738     }
   739 
   740     joystick->instance_id = item->device_instance;
   741     joystick->hwdata = (struct joystick_hwdata *)
   742         SDL_malloc(sizeof(*joystick->hwdata));
   743     if (joystick->hwdata == NULL) {
   744         close(fd);
   745         SDL_OutOfMemory();
   746         return (-1);
   747     }
   748     SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
   749     joystick->hwdata->item = item;
   750     joystick->hwdata->guid = item->guid;
   751     joystick->hwdata->fd = fd;
   752     joystick->hwdata->fname = SDL_strdup(item->path);
   753     if (joystick->hwdata->fname == NULL) {
   754         SDL_free(joystick->hwdata);
   755         joystick->hwdata = NULL;
   756         close(fd);
   757         SDL_OutOfMemory();
   758         return (-1);
   759     }
   760 
   761     SDL_assert(item->hwdata == NULL);
   762     item->hwdata = joystick->hwdata;
   763 
   764     /* Set the joystick to non-blocking read mode */
   765     fcntl(fd, F_SETFL, O_NONBLOCK);
   766 
   767     /* Get the number of buttons and axes on the joystick */
   768     ConfigJoystick(joystick, fd);
   769 
   770     // mark joystick as fresh and ready
   771     joystick->hwdata->fresh = 1;
   772 
   773     return (0);
   774 }
   775 
   776 /* Function to determine is this joystick is attached to the system right now */
   777 SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
   778 {
   779     return !joystick->closed && (joystick->hwdata->item != NULL);
   780 }
   781 
   782 static __inline__ void
   783 HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
   784 {
   785     struct hwdata_hat *the_hat;
   786     const Uint8 position_map[3][3] = {
   787         {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
   788         {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
   789         {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
   790     };
   791 
   792     the_hat = &stick->hwdata->hats[hat];
   793     if (value < 0) {
   794         value = 0;
   795     } else if (value == 0) {
   796         value = 1;
   797     } else if (value > 0) {
   798         value = 2;
   799     }
   800     if (value != the_hat->axis[axis]) {
   801         the_hat->axis[axis] = value;
   802         SDL_PrivateJoystickHat(stick, hat,
   803                                position_map[the_hat->
   804                                             axis[1]][the_hat->axis[0]]);
   805     }
   806 }
   807 
   808 static __inline__ void
   809 HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
   810 {
   811     stick->hwdata->balls[ball].axis[axis] += value;
   812 }
   813 
   814 
   815 static __inline__ int
   816 AxisCorrect(SDL_Joystick * joystick, int which, int value)
   817 {
   818     struct axis_correct *correct;
   819 
   820     correct = &joystick->hwdata->abs_correct[which];
   821     if (correct->used) {
   822         value *= 2;
   823         if (value > correct->coef[0]) {
   824             if (value < correct->coef[1]) {
   825                 return 0;
   826             }
   827             value -= correct->coef[1];
   828         } else {
   829             value -= correct->coef[0];
   830         }
   831         value *= correct->coef[2];
   832         value >>= 13;
   833     }
   834 
   835     /* Clamp and return */
   836     if (value < -32768)
   837         return -32768;
   838     if (value > 32767)
   839         return 32767;
   840 
   841     return value;
   842 }
   843 
   844 static __inline__ void
   845 PollAllValues(SDL_Joystick * joystick)
   846 {
   847     struct input_absinfo absinfo;
   848     int a, b = 0;
   849 
   850     // Poll all axis
   851     for (a = ABS_X; b < ABS_MAX; a++) {
   852         switch (a) {
   853         case ABS_HAT0X:
   854         case ABS_HAT0Y:
   855         case ABS_HAT1X:
   856         case ABS_HAT1Y:
   857         case ABS_HAT2X:
   858         case ABS_HAT2Y:
   859         case ABS_HAT3X:
   860         case ABS_HAT3Y:
   861             // ingore hats
   862             break;
   863         default:
   864             if (joystick->hwdata->abs_correct[b].used) {
   865                 if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
   866                     absinfo.value = AxisCorrect(joystick, b, absinfo.value);
   867 
   868 #ifdef DEBUG_INPUT_EVENTS
   869                     printf("Joystick : Re-read Axis %d (%d) val= %d\n",
   870                         joystick->hwdata->abs_map[b], a, absinfo.value);
   871 #endif
   872                     SDL_PrivateJoystickAxis(joystick,
   873                             joystick->hwdata->abs_map[b],
   874                             absinfo.value);
   875                 }
   876             }
   877             b++;
   878         }
   879     }
   880 }
   881 
   882 static __inline__ void
   883 HandleInputEvents(SDL_Joystick * joystick)
   884 {
   885     struct input_event events[32];
   886     int i, len;
   887     int code;
   888 
   889     if (joystick->hwdata->fresh) {
   890         PollAllValues(joystick);
   891         joystick->hwdata->fresh = 0;
   892     }
   893 
   894     while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
   895         len /= sizeof(events[0]);
   896         for (i = 0; i < len; ++i) {
   897             code = events[i].code;
   898             switch (events[i].type) {
   899             case EV_KEY:
   900                 if (code >= BTN_MISC) {
   901                     code -= BTN_MISC;
   902                     SDL_PrivateJoystickButton(joystick,
   903                                               joystick->hwdata->key_map[code],
   904                                               events[i].value);
   905                 }
   906                 break;
   907             case EV_ABS:
   908                 if (code >= ABS_MISC) {
   909                     break;
   910                 }
   911 
   912                 switch (code) {
   913                 case ABS_HAT0X:
   914                 case ABS_HAT0Y:
   915                 case ABS_HAT1X:
   916                 case ABS_HAT1Y:
   917                 case ABS_HAT2X:
   918                 case ABS_HAT2Y:
   919                 case ABS_HAT3X:
   920                 case ABS_HAT3Y:
   921                     code -= ABS_HAT0X;
   922                     HandleHat(joystick, code / 2, code % 2, events[i].value);
   923                     break;
   924                 default:
   925                     events[i].value =
   926                         AxisCorrect(joystick, code, events[i].value);
   927                     SDL_PrivateJoystickAxis(joystick,
   928                                             joystick->hwdata->abs_map[code],
   929                                             events[i].value);
   930                     break;
   931                 }
   932                 break;
   933             case EV_REL:
   934                 switch (code) {
   935                 case REL_X:
   936                 case REL_Y:
   937                     code -= REL_X;
   938                     HandleBall(joystick, code / 2, code % 2, events[i].value);
   939                     break;
   940                 default:
   941                     break;
   942                 }
   943                 break;
   944             case EV_SYN:
   945                 switch (code) {
   946                 case SYN_DROPPED :
   947 #ifdef DEBUG_INPUT_EVENTS
   948                     printf("Event SYN_DROPPED dectected\n");
   949 #endif
   950                     PollAllValues(joystick);
   951                     break;
   952                 default:
   953                     break;
   954                 }
   955             default:
   956                 break;
   957             }
   958         }
   959     }
   960 }
   961 
   962 void
   963 SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
   964 {
   965     int i;
   966 
   967     HandleInputEvents(joystick);
   968 
   969     /* Deliver ball motion updates */
   970     for (i = 0; i < joystick->nballs; ++i) {
   971         int xrel, yrel;
   972 
   973         xrel = joystick->hwdata->balls[i].axis[0];
   974         yrel = joystick->hwdata->balls[i].axis[1];
   975         if (xrel || yrel) {
   976             joystick->hwdata->balls[i].axis[0] = 0;
   977             joystick->hwdata->balls[i].axis[1] = 0;
   978             SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
   979         }
   980     }
   981 }
   982 
   983 /* Function to close a joystick after use */
   984 void
   985 SDL_SYS_JoystickClose(SDL_Joystick * joystick)
   986 {
   987     if (joystick->hwdata) {
   988         close(joystick->hwdata->fd);
   989         if (joystick->hwdata->item) {
   990             joystick->hwdata->item->hwdata = NULL;
   991         }
   992         SDL_free(joystick->hwdata->hats);
   993         SDL_free(joystick->hwdata->balls);
   994         SDL_free(joystick->hwdata->fname);
   995         SDL_free(joystick->hwdata);
   996         joystick->hwdata = NULL;
   997     }
   998     joystick->closed = 1;
   999 }
  1000 
  1001 /* Function to perform any system-specific joystick related cleanup */
  1002 void
  1003 SDL_SYS_JoystickQuit(void)
  1004 {
  1005     SDL_joylist_item *item = NULL;
  1006     SDL_joylist_item *next = NULL;
  1007 
  1008     for (item = SDL_joylist; item; item = next) {
  1009         next = item->next;
  1010         SDL_free(item->path);
  1011         SDL_free(item->name);
  1012         SDL_free(item);
  1013     }
  1014 
  1015     SDL_joylist = SDL_joylist_tail = NULL;
  1016 
  1017     numjoysticks = 0;
  1018     instance_counter = 0;
  1019 
  1020 #if SDL_USE_LIBUDEV
  1021     if (udev_mon != NULL) {
  1022         UDEV_udev_monitor_unref(udev_mon);
  1023         udev_mon = NULL;
  1024     }
  1025     if (udev != NULL) {
  1026         UDEV_udev_unref(udev);
  1027         udev = NULL;
  1028     }
  1029     UnloadUDEVLibrary();
  1030 #endif
  1031 }
  1032 
  1033 SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
  1034 {
  1035     return JoystickByDevIndex(device_index)->guid;
  1036 }
  1037 
  1038 SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
  1039 {
  1040     return joystick->hwdata->guid;
  1041 }
  1042 
  1043 #endif /* SDL_JOYSTICK_LINUX */
  1044 
  1045 /* vi: set ts=4 sw=4 expandtab: */