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