src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 05 Dec 2018 14:46:03 -0800
changeset 12459 34266b6e578d
parent 12410 a7ee81795c75
child 12461 14205d7f7715
permissions -rw-r--r--
Fixed the ROCCAT Tyon mouse showing up as a joystick on Windows
slouken@0
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@11811
     3
  Copyright (C) 1997-2018 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
*/
icculus@8093
    21
#include "../../SDL_internal.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
philipp@8138
    29
/* This is the Linux implementation of the SDL joystick API */
slouken@0
    30
slouken@0
    31
#include <sys/stat.h>
slouken@12088
    32
#include <errno.h>              /* errno, strerror */
slouken@0
    33
#include <fcntl.h>
slouken@12088
    34
#include <limits.h>             /* For the definition of PATH_MAX */
slouken@0
    35
#include <sys/ioctl.h>
slouken@12088
    36
#include <unistd.h>
slouken@0
    37
#include <linux/joystick.h>
slouken@0
    38
icculus@6734
    39
#include "SDL_assert.h"
slouken@0
    40
#include "SDL_joystick.h"
icculus@6734
    41
#include "SDL_endian.h"
slouken@11532
    42
#include "../../events/SDL_events_c.h"
slouken@1361
    43
#include "../SDL_sysjoystick.h"
slouken@1361
    44
#include "../SDL_joystick_c.h"
slouken@11532
    45
#include "../steam/SDL_steamcontroller.h"
slouken@2713
    46
#include "SDL_sysjoystick_c.h"
slouken@12088
    47
#include "../hidapi/SDL_hidapijoystick_c.h"
slouken@0
    48
slouken@6910
    49
/* This isn't defined in older Linux kernel headers */
slouken@6910
    50
#ifndef SYN_DROPPED
slouken@6910
    51
#define SYN_DROPPED 3
slouken@6910
    52
#endif
slouken@6910
    53
gabomdq@7772
    54
#include "../../core/linux/SDL_udev.h"
icculus@6734
    55
gabomdq@7772
    56
static int MaybeAddDevice(const char *path);
gabomdq@7772
    57
#if SDL_USE_LIBUDEV
gabomdq@7772
    58
static int MaybeRemoveDevice(const char *path);
philipp@11094
    59
static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
gabomdq@7772
    60
#endif /* SDL_USE_LIBUDEV */
slouken@892
    61
slouken@0
    62
icculus@6734
    63
/* A linked list of available joysticks */
icculus@6734
    64
typedef struct SDL_joylist_item
icculus@6734
    65
{
icculus@6734
    66
    int device_instance;
icculus@6734
    67
    char *path;   /* "/dev/input/event2" or whatever */
icculus@6734
    68
    char *name;   /* "SideWinder 3D Pro" or whatever */
slouken@6743
    69
    SDL_JoystickGUID guid;
icculus@6734
    70
    dev_t devnum;
icculus@6734
    71
    struct joystick_hwdata *hwdata;
icculus@6734
    72
    struct SDL_joylist_item *next;
slouken@11532
    73
slouken@11532
    74
    /* Steam Controller support */
slouken@11532
    75
    SDL_bool m_bSteamController;
icculus@6734
    76
} SDL_joylist_item;
icculus@6734
    77
icculus@6734
    78
static SDL_joylist_item *SDL_joylist = NULL;
icculus@6734
    79
static SDL_joylist_item *SDL_joylist_tail = NULL;
icculus@6734
    80
static int numjoysticks = 0;
icculus@6734
    81
slouken@11532
    82
slouken@0
    83
#define test_bit(nr, addr) \
icculus@6734
    84
    (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
slouken@3404
    85
#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
slouken@0
    86
slouken@1895
    87
static int
slouken@6743
    88
IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
slouken@0
    89
{
gabomdq@7909
    90
    struct input_id inpid;
slouken@10966
    91
    Uint32 id;
slouken@10595
    92
    Uint16 *guid16 = (Uint16 *)guid->data;
gabomdq@7909
    93
gabomdq@7909
    94
#if !SDL_USE_LIBUDEV
gabomdq@7909
    95
    /* When udev is enabled we only get joystick devices here, so there's no need to test them */
slouken@3404
    96
    unsigned long evbit[NBITS(EV_MAX)] = { 0 };
slouken@3404
    97
    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
slouken@3404
    98
    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
slouken@0
    99
slouken@1895
   100
    if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
slouken@1895
   101
        (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
slouken@1895
   102
        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
slouken@1895
   103
        return (0);
slouken@1895
   104
    }
bobbens@3079
   105
slouken@1895
   106
    if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
bobbens@3079
   107
          test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
slouken@1895
   108
        return 0;
bobbens@3079
   109
    }
gabomdq@7909
   110
#endif
icculus@6734
   111
icculus@6734
   112
    if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
icculus@6734
   113
        return 0;
icculus@6734
   114
    }
icculus@6734
   115
icculus@6734
   116
    if (ioctl(fd, EVIOCGID, &inpid) < 0) {
icculus@6734
   117
        return 0;
icculus@6734
   118
    }
icculus@6734
   119
slouken@12088
   120
#ifdef SDL_JOYSTICK_HIDAPI
slouken@12115
   121
    if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) {
slouken@12088
   122
        /* The HIDAPI driver is taking care of this device */
slouken@12088
   123
        return 0;
slouken@12088
   124
    }
slouken@12088
   125
#endif
slouken@12088
   126
slouken@6831
   127
#ifdef DEBUG_JOYSTICK
slouken@10595
   128
    printf("Joystick: %s, bustype = %d, vendor = 0x%.4x, product = 0x%.4x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
slouken@6831
   129
#endif
slouken@6831
   130
slouken@6831
   131
    SDL_memset(guid->data, 0, sizeof(guid->data));
slouken@6831
   132
icculus@6734
   133
    /* We only need 16 bits for each of these; space them out to fill 128. */
icculus@6734
   134
    /* Byteswap so devices get same GUID on little/big endian platforms. */
slouken@10595
   135
    *guid16++ = SDL_SwapLE16(inpid.bustype);
slouken@10595
   136
    *guid16++ = 0;
slouken@6831
   137
slouken@10595
   138
    if (inpid.vendor && inpid.product) {
slouken@10595
   139
        *guid16++ = SDL_SwapLE16(inpid.vendor);
slouken@10595
   140
        *guid16++ = 0;
slouken@10595
   141
        *guid16++ = SDL_SwapLE16(inpid.product);
slouken@10595
   142
        *guid16++ = 0;
slouken@10595
   143
        *guid16++ = SDL_SwapLE16(inpid.version);
slouken@10595
   144
        *guid16++ = 0;
slouken@6831
   145
    } else {
slouken@6831
   146
        SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
slouken@6831
   147
    }
icculus@6734
   148
slouken@12088
   149
    if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
slouken@11201
   150
        return 0;
slouken@11201
   151
    }
icculus@6734
   152
    return 1;
slouken@0
   153
}
slouken@0
   154
gabomdq@7772
   155
#if SDL_USE_LIBUDEV
philipp@11094
   156
static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
gabomdq@7772
   157
{
slouken@9321
   158
    if (devpath == NULL) {
gabomdq@7772
   159
        return;
gabomdq@7772
   160
    }
slouken@9321
   161
slouken@9321
   162
    switch (udev_type) {
gabomdq@7772
   163
        case SDL_UDEV_DEVICEADDED:
slouken@9321
   164
            if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
slouken@9321
   165
                return;
slouken@9321
   166
            }
slouken@7802
   167
            MaybeAddDevice(devpath);
gabomdq@7772
   168
            break;
gabomdq@7772
   169
            
gabomdq@7772
   170
        case SDL_UDEV_DEVICEREMOVED:
slouken@7802
   171
            MaybeRemoveDevice(devpath);
gabomdq@7772
   172
            break;
gabomdq@7772
   173
            
gabomdq@7772
   174
        default:
gabomdq@7772
   175
            break;
gabomdq@7772
   176
    }
gabomdq@7772
   177
    
gabomdq@7772
   178
}
gabomdq@7772
   179
#endif /* SDL_USE_LIBUDEV */
gabomdq@7772
   180
slouken@0
   181
icculus@6734
   182
/* !!! FIXME: I would love to dump this code and use libudev instead. */
icculus@6734
   183
static int
icculus@6734
   184
MaybeAddDevice(const char *path)
icculus@6734
   185
{
icculus@6734
   186
    struct stat sb;
icculus@6734
   187
    int fd = -1;
icculus@6734
   188
    int isstick = 0;
icculus@6734
   189
    char namebuf[128];
slouken@6743
   190
    SDL_JoystickGUID guid;
icculus@6734
   191
    SDL_joylist_item *item;
icculus@6734
   192
icculus@6734
   193
    if (path == NULL) {
icculus@6734
   194
        return -1;
icculus@6734
   195
    }
icculus@6734
   196
icculus@6734
   197
    if (stat(path, &sb) == -1) {
icculus@6734
   198
        return -1;
icculus@6734
   199
    }
icculus@6734
   200
icculus@6734
   201
    /* Check to make sure it's not already in list. */
icculus@6734
   202
    for (item = SDL_joylist; item != NULL; item = item->next) {
icculus@6734
   203
        if (sb.st_rdev == item->devnum) {
icculus@6734
   204
            return -1;  /* already have this one */
icculus@6734
   205
        }
icculus@6734
   206
    }
icculus@6734
   207
icculus@6734
   208
    fd = open(path, O_RDONLY, 0);
icculus@6734
   209
    if (fd < 0) {
icculus@6734
   210
        return -1;
icculus@6734
   211
    }
icculus@6734
   212
icculus@6734
   213
#ifdef DEBUG_INPUT_EVENTS
icculus@6734
   214
    printf("Checking %s\n", path);
icculus@6734
   215
#endif
icculus@6734
   216
icculus@6734
   217
    isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
icculus@6734
   218
    close(fd);
icculus@6734
   219
    if (!isstick) {
icculus@6734
   220
        return -1;
icculus@6734
   221
    }
icculus@6734
   222
icculus@6734
   223
    item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
icculus@6734
   224
    if (item == NULL) {
icculus@6734
   225
        return -1;
icculus@6734
   226
    }
icculus@6734
   227
icculus@6734
   228
    SDL_zerop(item);
icculus@6734
   229
    item->devnum = sb.st_rdev;
icculus@6734
   230
    item->path = SDL_strdup(path);
icculus@6734
   231
    item->name = SDL_strdup(namebuf);
icculus@6734
   232
    item->guid = guid;
icculus@6734
   233
slouken@12088
   234
    if ((item->path == NULL) || (item->name == NULL)) {
icculus@6734
   235
         SDL_free(item->path);
icculus@6734
   236
         SDL_free(item->name);
icculus@6734
   237
         SDL_free(item);
icculus@6734
   238
         return -1;
icculus@6734
   239
    }
icculus@6734
   240
slouken@12088
   241
    item->device_instance = SDL_GetNextJoystickInstanceID();
icculus@6734
   242
    if (SDL_joylist_tail == NULL) {
icculus@6734
   243
        SDL_joylist = SDL_joylist_tail = item;
icculus@6734
   244
    } else {
icculus@6734
   245
        SDL_joylist_tail->next = item;
icculus@6734
   246
        SDL_joylist_tail = item;
icculus@6734
   247
    }
icculus@6734
   248
slouken@7916
   249
    /* Need to increment the joystick count before we post the event */
slouken@7916
   250
    ++numjoysticks;
slouken@7916
   251
slouken@12088
   252
    SDL_PrivateJoystickAdded(item->device_instance);
slouken@7802
   253
slouken@7916
   254
    return numjoysticks;
icculus@6734
   255
}
icculus@6734
   256
icculus@6749
   257
#if SDL_USE_LIBUDEV
icculus@6734
   258
/* !!! FIXME: I would love to dump this code and use libudev instead. */
icculus@6734
   259
static int
icculus@6734
   260
MaybeRemoveDevice(const char *path)
icculus@6734
   261
{
icculus@6734
   262
    SDL_joylist_item *item;
icculus@6734
   263
    SDL_joylist_item *prev = NULL;
icculus@6734
   264
icculus@6734
   265
    if (path == NULL) {
icculus@6734
   266
        return -1;
icculus@6734
   267
    }
slouken@6690
   268
icculus@6734
   269
    for (item = SDL_joylist; item != NULL; item = item->next) {
icculus@6734
   270
        /* found it, remove it. */
icculus@6734
   271
        if (SDL_strcmp(path, item->path) == 0) {
icculus@6734
   272
            const int retval = item->device_instance;
icculus@6734
   273
            if (item->hwdata) {
icculus@6752
   274
                item->hwdata->item = NULL;
icculus@6734
   275
            }
icculus@6734
   276
            if (prev != NULL) {
icculus@6734
   277
                prev->next = item->next;
icculus@6734
   278
            } else {
jorgen@6865
   279
                SDL_assert(SDL_joylist == item);
jorgen@6865
   280
                SDL_joylist = item->next;
jorgen@6865
   281
            }
jorgen@6865
   282
            if (item == SDL_joylist_tail) {
jorgen@6865
   283
                SDL_joylist_tail = prev;
icculus@6734
   284
            }
slouken@7802
   285
slouken@7916
   286
            /* Need to decrement the joystick count before we post the event */
slouken@7916
   287
            --numjoysticks;
slouken@7916
   288
slouken@10226
   289
            SDL_PrivateJoystickRemoved(item->device_instance);
slouken@7802
   290
icculus@6734
   291
            SDL_free(item->path);
icculus@6734
   292
            SDL_free(item->name);
icculus@6734
   293
            SDL_free(item);
icculus@6734
   294
            return retval;
icculus@6734
   295
        }
icculus@6734
   296
        prev = item;
icculus@6734
   297
    }
icculus@6734
   298
icculus@6734
   299
    return -1;
icculus@6734
   300
}
icculus@6749
   301
#endif
icculus@6734
   302
slouken@10609
   303
#if ! SDL_USE_LIBUDEV
icculus@6734
   304
static int
icculus@6734
   305
JoystickInitWithoutUdev(void)
icculus@6734
   306
{
icculus@6734
   307
    int i;
icculus@6734
   308
    char path[PATH_MAX];
icculus@6734
   309
icculus@6734
   310
    /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
icculus@6734
   311
    /* !!! FIXME:  we could at least readdir() through /dev/input...? */
icculus@6734
   312
    /* !!! FIXME:  (or delete this and rely on libudev?) */
icculus@6734
   313
    for (i = 0; i < 32; i++) {
icculus@6734
   314
        SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
icculus@6734
   315
        MaybeAddDevice(path);
icculus@6734
   316
    }
icculus@6734
   317
slouken@12088
   318
    return 0;
icculus@6734
   319
}
slouken@10609
   320
#endif
icculus@6734
   321
icculus@6734
   322
#if SDL_USE_LIBUDEV
icculus@6734
   323
static int
icculus@6734
   324
JoystickInitWithUdev(void)
icculus@6734
   325
{
gabomdq@7772
   326
    if (SDL_UDEV_Init() < 0) {
gabomdq@7772
   327
        return SDL_SetError("Could not initialize UDEV");
icculus@6734
   328
    }
icculus@6734
   329
gabomdq@7772
   330
    /* Set up the udev callback */
slouken@9321
   331
    if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
gabomdq@7772
   332
        SDL_UDEV_Quit();
gabomdq@7772
   333
        return SDL_SetError("Could not set up joystick <-> udev callback");
icculus@6734
   334
    }
gabomdq@7772
   335
    
gabomdq@7772
   336
    /* Force a scan to build the initial device list */
gabomdq@7772
   337
    SDL_UDEV_Scan();
icculus@6734
   338
slouken@12088
   339
    return 0;
icculus@6734
   340
}
icculus@6734
   341
#endif
icculus@6734
   342
slouken@11532
   343
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
slouken@11532
   344
{
slouken@11532
   345
    SDL_joylist_item *item;
slouken@11532
   346
slouken@11532
   347
    item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
slouken@11532
   348
    if (item == NULL) {
slouken@11532
   349
        return SDL_FALSE;
slouken@11532
   350
    }
slouken@11532
   351
slouken@11532
   352
    item->path = SDL_strdup("");
slouken@11532
   353
    item->name = SDL_strdup(name);
slouken@11532
   354
    item->guid = guid;
slouken@11532
   355
    item->m_bSteamController = SDL_TRUE;
slouken@11532
   356
slouken@11532
   357
    if ((item->path == NULL) || (item->name == NULL)) {
slouken@11532
   358
         SDL_free(item->path);
slouken@11532
   359
         SDL_free(item->name);
slouken@11532
   360
         SDL_free(item);
slouken@11532
   361
         return SDL_FALSE;
slouken@11532
   362
    }
slouken@11532
   363
slouken@12088
   364
    *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
slouken@11532
   365
    if (SDL_joylist_tail == NULL) {
slouken@11532
   366
        SDL_joylist = SDL_joylist_tail = item;
slouken@11532
   367
    } else {
slouken@11532
   368
        SDL_joylist_tail->next = item;
slouken@11532
   369
        SDL_joylist_tail = item;
slouken@11532
   370
    }
slouken@11532
   371
slouken@11532
   372
    /* Need to increment the joystick count before we post the event */
slouken@11532
   373
    ++numjoysticks;
slouken@11532
   374
slouken@12088
   375
    SDL_PrivateJoystickAdded(item->device_instance);
slouken@11532
   376
slouken@11532
   377
    return SDL_TRUE;
slouken@11532
   378
}
slouken@11532
   379
slouken@11532
   380
static void SteamControllerDisconnectedCallback(int device_instance)
slouken@11532
   381
{
slouken@11532
   382
    SDL_joylist_item *item;
slouken@11532
   383
    SDL_joylist_item *prev = NULL;
slouken@11532
   384
slouken@11532
   385
    for (item = SDL_joylist; item != NULL; item = item->next) {
slouken@11532
   386
        /* found it, remove it. */
slouken@11532
   387
        if (item->device_instance == device_instance) {
slouken@11532
   388
            if (item->hwdata) {
slouken@11532
   389
                item->hwdata->item = NULL;
slouken@11532
   390
            }
slouken@11532
   391
            if (prev != NULL) {
slouken@11532
   392
                prev->next = item->next;
slouken@11532
   393
            } else {
slouken@11532
   394
                SDL_assert(SDL_joylist == item);
slouken@11532
   395
                SDL_joylist = item->next;
slouken@11532
   396
            }
slouken@11532
   397
            if (item == SDL_joylist_tail) {
slouken@11532
   398
                SDL_joylist_tail = prev;
slouken@11532
   399
            }
slouken@11532
   400
slouken@11532
   401
            /* Need to decrement the joystick count before we post the event */
slouken@11532
   402
            --numjoysticks;
slouken@11532
   403
slouken@11532
   404
            SDL_PrivateJoystickRemoved(item->device_instance);
slouken@11532
   405
slouken@11532
   406
            SDL_free(item->name);
slouken@11532
   407
            SDL_free(item);
slouken@11532
   408
            return;
slouken@11532
   409
        }
slouken@11532
   410
        prev = item;
slouken@11532
   411
    }
slouken@11532
   412
}
slouken@11532
   413
slouken@12088
   414
static int
slouken@12088
   415
LINUX_JoystickInit(void)
slouken@0
   416
{
slouken@5317
   417
    /* First see if the user specified one or more joysticks to use */
slouken@1895
   418
    if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
slouken@5317
   419
        char *envcopy, *envpath, *delim;
slouken@5317
   420
        envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
slouken@5317
   421
        envpath = envcopy;
slouken@5317
   422
        while (envpath != NULL) {
slouken@5317
   423
            delim = SDL_strchr(envpath, ':');
slouken@5317
   424
            if (delim != NULL) {
slouken@5317
   425
                *delim++ = '\0';
slouken@5317
   426
            }
icculus@6734
   427
            MaybeAddDevice(envpath);
slouken@5317
   428
            envpath = delim;
slouken@1895
   429
        }
slouken@5317
   430
        SDL_free(envcopy);
slouken@1895
   431
    }
slouken@554
   432
slouken@11532
   433
    SDL_InitSteamControllers(SteamControllerConnectedCallback,
slouken@11532
   434
                             SteamControllerDisconnectedCallback);
slouken@11532
   435
icculus@6734
   436
#if SDL_USE_LIBUDEV
gabomdq@7772
   437
    return JoystickInitWithUdev();
slouken@10609
   438
#else 
slouken@10609
   439
    return JoystickInitWithoutUdev();
slouken@0
   440
#endif
slouken@0
   441
}
slouken@0
   442
slouken@12088
   443
static int
slouken@12088
   444
LINUX_JoystickGetCount(void)
slouken@6707
   445
{
icculus@6734
   446
    return numjoysticks;
icculus@6734
   447
}
icculus@6734
   448
slouken@12088
   449
static void
slouken@12088
   450
LINUX_JoystickDetect(void)
slouken@6707
   451
{
icculus@6734
   452
#if SDL_USE_LIBUDEV
gabomdq@7772
   453
    SDL_UDEV_Poll();
icculus@6734
   454
#endif
slouken@11532
   455
slouken@11532
   456
    SDL_UpdateSteamControllers();
slouken@6707
   457
}
slouken@6707
   458
icculus@6734
   459
static SDL_joylist_item *
icculus@6734
   460
JoystickByDevIndex(int device_index)
icculus@6734
   461
{
icculus@6734
   462
    SDL_joylist_item *item = SDL_joylist;
icculus@6734
   463
icculus@6734
   464
    if ((device_index < 0) || (device_index >= numjoysticks)) {
icculus@6734
   465
        return NULL;
icculus@6734
   466
    }
icculus@6734
   467
icculus@6734
   468
    while (device_index > 0) {
icculus@6734
   469
        SDL_assert(item != NULL);
icculus@6734
   470
        device_index--;
icculus@6734
   471
        item = item->next;
icculus@6734
   472
    }
icculus@6734
   473
icculus@6734
   474
    return item;
slouken@6707
   475
}
slouken@6707
   476
slouken@0
   477
/* Function to get the device-dependent name of a joystick */
slouken@12088
   478
static const char *
slouken@12088
   479
LINUX_JoystickGetDeviceName(int device_index)
slouken@0
   480
{
icculus@6734
   481
    return JoystickByDevIndex(device_index)->name;
slouken@0
   482
}
slouken@0
   483
slouken@12359
   484
static int
slouken@12359
   485
LINUX_JoystickGetDevicePlayerIndex(int device_index)
slouken@12359
   486
{
slouken@12359
   487
    return -1;
slouken@12359
   488
}
slouken@12359
   489
slouken@12088
   490
static SDL_JoystickGUID
slouken@12088
   491
LINUX_JoystickGetDeviceGUID( int device_index )
slouken@12088
   492
{
slouken@12088
   493
    return JoystickByDevIndex(device_index)->guid;
slouken@12088
   494
}
slouken@12088
   495
slouken@6707
   496
/* Function to perform the mapping from device index to the instance id for this index */
slouken@12088
   497
static SDL_JoystickID
slouken@12088
   498
LINUX_JoystickGetDeviceInstanceID(int device_index)
slouken@6707
   499
{
icculus@6734
   500
    return JoystickByDevIndex(device_index)->device_instance;
slouken@6707
   501
}
slouken@6707
   502
slouken@1895
   503
static int
slouken@1895
   504
allocate_hatdata(SDL_Joystick * joystick)
slouken@0
   505
{
slouken@1895
   506
    int i;
slouken@0
   507
slouken@1895
   508
    joystick->hwdata->hats =
slouken@1895
   509
        (struct hwdata_hat *) SDL_malloc(joystick->nhats *
slouken@1895
   510
                                         sizeof(struct hwdata_hat));
slouken@1895
   511
    if (joystick->hwdata->hats == NULL) {
slouken@1895
   512
        return (-1);
slouken@1895
   513
    }
slouken@1895
   514
    for (i = 0; i < joystick->nhats; ++i) {
slouken@1895
   515
        joystick->hwdata->hats[i].axis[0] = 1;
slouken@1895
   516
        joystick->hwdata->hats[i].axis[1] = 1;
slouken@1895
   517
    }
slouken@1895
   518
    return (0);
slouken@0
   519
}
slouken@0
   520
slouken@1895
   521
static int
slouken@1895
   522
allocate_balldata(SDL_Joystick * joystick)
slouken@0
   523
{
slouken@1895
   524
    int i;
slouken@0
   525
slouken@1895
   526
    joystick->hwdata->balls =
slouken@1895
   527
        (struct hwdata_ball *) SDL_malloc(joystick->nballs *
slouken@1895
   528
                                          sizeof(struct hwdata_ball));
slouken@1895
   529
    if (joystick->hwdata->balls == NULL) {
slouken@1895
   530
        return (-1);
slouken@1895
   531
    }
slouken@1895
   532
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
   533
        joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
   534
        joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
   535
    }
slouken@1895
   536
    return (0);
slouken@0
   537
}
slouken@0
   538
icculus@6729
   539
static void
icculus@6729
   540
ConfigJoystick(SDL_Joystick * joystick, int fd)
slouken@0
   541
{
slouken@1895
   542
    int i, t;
slouken@3404
   543
    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
slouken@3404
   544
    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
slouken@3404
   545
    unsigned long relbit[NBITS(REL_MAX)] = { 0 };
slouken@12088
   546
    unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
slouken@0
   547
slouken@1895
   548
    /* See if this device uses the new unified event API */
slouken@1895
   549
    if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
slouken@1895
   550
        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
slouken@1895
   551
        (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
slouken@0
   552
slouken@1895
   553
        /* Get the number of buttons, axes, and other thingamajigs */
slouken@1895
   554
        for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
slouken@1895
   555
            if (test_bit(i, keybit)) {
slouken@0
   556
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   557
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   558
#endif
slouken@10641
   559
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   560
                ++joystick->nbuttons;
slouken@1895
   561
            }
slouken@1895
   562
        }
slouken@10641
   563
        for (i = 0; i < BTN_JOYSTICK; ++i) {
slouken@1895
   564
            if (test_bit(i, keybit)) {
slouken@0
   565
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   566
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   567
#endif
slouken@10641
   568
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   569
                ++joystick->nbuttons;
slouken@1895
   570
            }
slouken@1895
   571
        }
icculus@9630
   572
        for (i = 0; i < ABS_MAX; ++i) {
slouken@1895
   573
            /* Skip hats */
slouken@1895
   574
            if (i == ABS_HAT0X) {
slouken@1895
   575
                i = ABS_HAT3Y;
slouken@1895
   576
                continue;
slouken@1895
   577
            }
slouken@1895
   578
            if (test_bit(i, absbit)) {
slouken@5084
   579
                struct input_absinfo absinfo;
slouken@0
   580
slouken@8053
   581
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@1895
   582
                    continue;
slouken@8053
   583
                }
slouken@0
   584
#ifdef DEBUG_INPUT_EVENTS
slouken@8053
   585
                printf("Joystick has absolute axis: 0x%.2x\n", i);
slouken@1895
   586
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@5084
   587
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@5084
   588
                       absinfo.fuzz, absinfo.flat);
slouken@0
   589
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   590
                joystick->hwdata->abs_map[i] = joystick->naxes;
slouken@5084
   591
                if (absinfo.minimum == absinfo.maximum) {
slouken@1895
   592
                    joystick->hwdata->abs_correct[i].used = 0;
slouken@1895
   593
                } else {
slouken@1895
   594
                    joystick->hwdata->abs_correct[i].used = 1;
slouken@1895
   595
                    joystick->hwdata->abs_correct[i].coef[0] =
slouken@6845
   596
                        (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
slouken@1895
   597
                    joystick->hwdata->abs_correct[i].coef[1] =
slouken@6845
   598
                        (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
slouken@6845
   599
                    t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
slouken@1895
   600
                    if (t != 0) {
slouken@1895
   601
                        joystick->hwdata->abs_correct[i].coef[2] =
slouken@6845
   602
                            (1 << 28) / t;
slouken@1895
   603
                    } else {
slouken@1895
   604
                        joystick->hwdata->abs_correct[i].coef[2] = 0;
slouken@1895
   605
                    }
slouken@1895
   606
                }
slouken@1895
   607
                ++joystick->naxes;
slouken@1895
   608
            }
slouken@1895
   609
        }
slouken@1895
   610
        for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
slouken@1895
   611
            if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
slouken@8053
   612
                struct input_absinfo absinfo;
slouken@8053
   613
slouken@8053
   614
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@8053
   615
                    continue;
slouken@8053
   616
                }
slouken@0
   617
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   618
                printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
slouken@8053
   619
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@8053
   620
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@8053
   621
                       absinfo.fuzz, absinfo.flat);
slouken@8053
   622
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   623
                ++joystick->nhats;
slouken@1895
   624
            }
slouken@1895
   625
        }
slouken@1895
   626
        if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
slouken@1895
   627
            ++joystick->nballs;
slouken@1895
   628
        }
slouken@0
   629
slouken@1895
   630
        /* Allocate data to keep track of these thingamajigs */
slouken@1895
   631
        if (joystick->nhats > 0) {
slouken@1895
   632
            if (allocate_hatdata(joystick) < 0) {
slouken@1895
   633
                joystick->nhats = 0;
slouken@1895
   634
            }
slouken@1895
   635
        }
slouken@1895
   636
        if (joystick->nballs > 0) {
slouken@1895
   637
            if (allocate_balldata(joystick) < 0) {
slouken@1895
   638
                joystick->nballs = 0;
slouken@1895
   639
            }
slouken@1895
   640
        }
slouken@1895
   641
    }
slouken@12088
   642
slouken@12088
   643
    if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
slouken@12088
   644
        if (test_bit(FF_RUMBLE, ffbit)) {
slouken@12088
   645
            joystick->hwdata->ff_rumble = SDL_TRUE;
slouken@12088
   646
        }
slouken@12088
   647
        if (test_bit(FF_SINE, ffbit)) {
slouken@12088
   648
            joystick->hwdata->ff_sine = SDL_TRUE;
slouken@12088
   649
        }
slouken@12088
   650
    }
slouken@0
   651
}
slouken@0
   652
slouken@892
   653
slouken@0
   654
/* Function to open a joystick for use.
philipp@9380
   655
   The joystick to open is specified by the device index.
slouken@0
   656
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@0
   657
   It returns 0, or -1 if there is an error.
slouken@0
   658
 */
slouken@12088
   659
static int
slouken@12088
   660
LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@0
   661
{
icculus@6734
   662
    SDL_joylist_item *item = JoystickByDevIndex(device_index);
slouken@892
   663
icculus@6734
   664
    if (item == NULL) {
icculus@7037
   665
        return SDL_SetError("No such device");
icculus@6734
   666
    }
slouken@892
   667
icculus@6751
   668
    joystick->instance_id = item->device_instance;
slouken@1895
   669
    joystick->hwdata = (struct joystick_hwdata *)
slouken@11532
   670
        SDL_calloc(1, sizeof(*joystick->hwdata));
slouken@1895
   671
    if (joystick->hwdata == NULL) {
icculus@7037
   672
        return SDL_OutOfMemory();
slouken@1895
   673
    }
icculus@6752
   674
    joystick->hwdata->item = item;
icculus@6734
   675
    joystick->hwdata->guid = item->guid;
slouken@12088
   676
    joystick->hwdata->effect.id = -1;
slouken@11532
   677
    joystick->hwdata->m_bSteamController = item->m_bSteamController;
slouken@12410
   678
    SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
slouken@11532
   679
slouken@11532
   680
    if (item->m_bSteamController) {
slouken@11532
   681
        joystick->hwdata->fd = -1;
slouken@11532
   682
        SDL_GetSteamControllerInputs(&joystick->nbuttons,
slouken@11532
   683
                                     &joystick->naxes,
slouken@11532
   684
                                     &joystick->nhats);
slouken@11532
   685
    } else {
slouken@12088
   686
        int fd = open(item->path, O_RDWR, 0);
slouken@11532
   687
        if (fd < 0) {
slouken@11532
   688
            SDL_free(joystick->hwdata);
slouken@11532
   689
            joystick->hwdata = NULL;
slouken@11532
   690
            return SDL_SetError("Unable to open %s", item->path);
slouken@11532
   691
        }
slouken@11532
   692
slouken@11532
   693
        joystick->hwdata->fd = fd;
slouken@11532
   694
        joystick->hwdata->fname = SDL_strdup(item->path);
slouken@11532
   695
        if (joystick->hwdata->fname == NULL) {
slouken@11532
   696
            SDL_free(joystick->hwdata);
slouken@11532
   697
            joystick->hwdata = NULL;
slouken@11532
   698
            close(fd);
slouken@11532
   699
            return SDL_OutOfMemory();
slouken@11532
   700
        }
slouken@11532
   701
slouken@11532
   702
        /* Set the joystick to non-blocking read mode */
slouken@11532
   703
        fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@11532
   704
slouken@11532
   705
        /* Get the number of buttons and axes on the joystick */
slouken@11532
   706
        ConfigJoystick(joystick, fd);
icculus@6734
   707
    }
icculus@6734
   708
icculus@6734
   709
    SDL_assert(item->hwdata == NULL);
icculus@6734
   710
    item->hwdata = joystick->hwdata;
slouken@0
   711
slouken@7191
   712
    /* mark joystick as fresh and ready */
slouken@6844
   713
    joystick->hwdata->fresh = 1;
slouken@6844
   714
slouken@1895
   715
    return (0);
slouken@0
   716
}
slouken@0
   717
slouken@12088
   718
static int
slouken@12088
   719
LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   720
{
slouken@12088
   721
    struct input_event event;
slouken@12088
   722
slouken@12333
   723
    if (joystick->hwdata->ff_rumble) {
slouken@12333
   724
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   725
slouken@12333
   726
        effect->type = FF_RUMBLE;
slouken@12333
   727
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   728
        effect->u.rumble.strong_magnitude = low_frequency_rumble;
slouken@12333
   729
        effect->u.rumble.weak_magnitude = high_frequency_rumble;
slouken@12333
   730
    } else if (joystick->hwdata->ff_sine) {
slouken@12333
   731
        /* Scale and average the two rumble strengths */
slouken@12333
   732
        Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
slouken@12333
   733
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   734
slouken@12333
   735
        effect->type = FF_PERIODIC;
slouken@12333
   736
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   737
        effect->u.periodic.waveform = FF_SINE;
slouken@12333
   738
        effect->u.periodic.magnitude = magnitude;
slouken@12333
   739
    } else {
slouken@12333
   740
        return SDL_Unsupported();
slouken@12088
   741
    }
slouken@12088
   742
slouken@12088
   743
    if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
slouken@12088
   744
        return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
slouken@12088
   745
    }
slouken@12088
   746
slouken@12088
   747
    event.type = EV_FF;
slouken@12088
   748
    event.code = joystick->hwdata->effect.id;
slouken@12088
   749
    event.value = 1;
slouken@12088
   750
    if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
slouken@12088
   751
        return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
slouken@12088
   752
    }
slouken@12088
   753
    return 0;
slouken@12088
   754
}
slouken@12088
   755
slouken@7860
   756
static SDL_INLINE void
slouken@1895
   757
HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
slouken@0
   758
{
slouken@1895
   759
    struct hwdata_hat *the_hat;
slouken@1895
   760
    const Uint8 position_map[3][3] = {
slouken@1895
   761
        {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
slouken@1895
   762
        {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
slouken@1895
   763
        {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
slouken@1895
   764
    };
slouken@0
   765
slouken@1895
   766
    the_hat = &stick->hwdata->hats[hat];
slouken@1895
   767
    if (value < 0) {
slouken@1895
   768
        value = 0;
slouken@1895
   769
    } else if (value == 0) {
slouken@1895
   770
        value = 1;
slouken@1895
   771
    } else if (value > 0) {
slouken@1895
   772
        value = 2;
slouken@1895
   773
    }
slouken@1895
   774
    if (value != the_hat->axis[axis]) {
slouken@1895
   775
        the_hat->axis[axis] = value;
slouken@1895
   776
        SDL_PrivateJoystickHat(stick, hat,
slouken@3013
   777
                               position_map[the_hat->
slouken@3013
   778
                                            axis[1]][the_hat->axis[0]]);
slouken@1895
   779
    }
slouken@0
   780
}
slouken@0
   781
slouken@7860
   782
static SDL_INLINE void
slouken@1895
   783
HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
slouken@0
   784
{
slouken@1895
   785
    stick->hwdata->balls[ball].axis[axis] += value;
slouken@0
   786
}
slouken@0
   787
slouken@0
   788
slouken@7860
   789
static SDL_INLINE int
icculus@6729
   790
AxisCorrect(SDL_Joystick * joystick, int which, int value)
slouken@0
   791
{
slouken@1895
   792
    struct axis_correct *correct;
slouken@0
   793
slouken@1895
   794
    correct = &joystick->hwdata->abs_correct[which];
slouken@1895
   795
    if (correct->used) {
slouken@6845
   796
        value *= 2;
slouken@1895
   797
        if (value > correct->coef[0]) {
slouken@1895
   798
            if (value < correct->coef[1]) {
slouken@1895
   799
                return 0;
slouken@1895
   800
            }
slouken@1895
   801
            value -= correct->coef[1];
slouken@1895
   802
        } else {
slouken@1895
   803
            value -= correct->coef[0];
slouken@1895
   804
        }
slouken@1895
   805
        value *= correct->coef[2];
slouken@6845
   806
        value >>= 13;
slouken@1895
   807
    }
slouken@554
   808
slouken@1895
   809
    /* Clamp and return */
slouken@1895
   810
    if (value < -32768)
slouken@1895
   811
        return -32768;
slouken@1895
   812
    if (value > 32767)
slouken@1895
   813
        return 32767;
slouken@554
   814
slouken@1895
   815
    return value;
slouken@0
   816
}
slouken@0
   817
slouken@7860
   818
static SDL_INLINE void
slouken@6844
   819
PollAllValues(SDL_Joystick * joystick)
slouken@6844
   820
{
slouken@6844
   821
    struct input_absinfo absinfo;
slouken@6844
   822
    int a, b = 0;
slouken@6844
   823
slouken@7191
   824
    /* Poll all axis */
slouken@6844
   825
    for (a = ABS_X; b < ABS_MAX; a++) {
slouken@6844
   826
        switch (a) {
slouken@6844
   827
        case ABS_HAT0X:
slouken@6844
   828
        case ABS_HAT0Y:
slouken@6844
   829
        case ABS_HAT1X:
slouken@6844
   830
        case ABS_HAT1Y:
slouken@6844
   831
        case ABS_HAT2X:
slouken@6844
   832
        case ABS_HAT2Y:
slouken@6844
   833
        case ABS_HAT3X:
slouken@6844
   834
        case ABS_HAT3Y:
slouken@7191
   835
            /* ingore hats */
slouken@6844
   836
            break;
slouken@6844
   837
        default:
slouken@6844
   838
            if (joystick->hwdata->abs_correct[b].used) {
slouken@6844
   839
                if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
slouken@6844
   840
                    absinfo.value = AxisCorrect(joystick, b, absinfo.value);
slouken@6844
   841
slouken@6844
   842
#ifdef DEBUG_INPUT_EVENTS
slouken@6844
   843
                    printf("Joystick : Re-read Axis %d (%d) val= %d\n",
slouken@6844
   844
                        joystick->hwdata->abs_map[b], a, absinfo.value);
slouken@6844
   845
#endif
slouken@6844
   846
                    SDL_PrivateJoystickAxis(joystick,
slouken@6844
   847
                            joystick->hwdata->abs_map[b],
slouken@6844
   848
                            absinfo.value);
slouken@6844
   849
                }
slouken@6844
   850
            }
slouken@6844
   851
            b++;
slouken@6844
   852
        }
slouken@6844
   853
    }
slouken@6844
   854
}
slouken@6844
   855
slouken@7860
   856
static SDL_INLINE void
icculus@6729
   857
HandleInputEvents(SDL_Joystick * joystick)
slouken@0
   858
{
slouken@1895
   859
    struct input_event events[32];
slouken@1895
   860
    int i, len;
slouken@1895
   861
    int code;
slouken@0
   862
slouken@6844
   863
    if (joystick->hwdata->fresh) {
slouken@6844
   864
        PollAllValues(joystick);
slouken@6844
   865
        joystick->hwdata->fresh = 0;
slouken@6844
   866
    }
slouken@6844
   867
slouken@1895
   868
    while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
slouken@1895
   869
        len /= sizeof(events[0]);
slouken@1895
   870
        for (i = 0; i < len; ++i) {
slouken@1895
   871
            code = events[i].code;
slouken@1895
   872
            switch (events[i].type) {
slouken@1895
   873
            case EV_KEY:
slouken@10641
   874
                SDL_PrivateJoystickButton(joystick,
slouken@10641
   875
                                          joystick->hwdata->key_map[code],
slouken@10641
   876
                                          events[i].value);
slouken@1895
   877
                break;
slouken@1895
   878
            case EV_ABS:
slouken@1895
   879
                switch (code) {
slouken@1895
   880
                case ABS_HAT0X:
slouken@1895
   881
                case ABS_HAT0Y:
slouken@1895
   882
                case ABS_HAT1X:
slouken@1895
   883
                case ABS_HAT1Y:
slouken@1895
   884
                case ABS_HAT2X:
slouken@1895
   885
                case ABS_HAT2Y:
slouken@1895
   886
                case ABS_HAT3X:
slouken@1895
   887
                case ABS_HAT3Y:
slouken@1895
   888
                    code -= ABS_HAT0X;
slouken@1895
   889
                    HandleHat(joystick, code / 2, code % 2, events[i].value);
slouken@1895
   890
                    break;
slouken@1895
   891
                default:
slouken@12410
   892
                    if (joystick->hwdata->abs_map[code] != 0xFF) {
slouken@12410
   893
                        events[i].value =
slouken@12410
   894
                            AxisCorrect(joystick, code, events[i].value);
slouken@12410
   895
                        SDL_PrivateJoystickAxis(joystick,
slouken@12410
   896
                                                joystick->hwdata->abs_map[code],
slouken@12410
   897
                                                events[i].value);
slouken@12410
   898
                    }
slouken@1895
   899
                    break;
slouken@1895
   900
                }
slouken@1895
   901
                break;
slouken@1895
   902
            case EV_REL:
slouken@1895
   903
                switch (code) {
slouken@1895
   904
                case REL_X:
slouken@1895
   905
                case REL_Y:
slouken@1895
   906
                    code -= REL_X;
slouken@1895
   907
                    HandleBall(joystick, code / 2, code % 2, events[i].value);
slouken@1895
   908
                    break;
slouken@1895
   909
                default:
slouken@1895
   910
                    break;
slouken@1895
   911
                }
slouken@1895
   912
                break;
slouken@6844
   913
            case EV_SYN:
slouken@6844
   914
                switch (code) {
slouken@6844
   915
                case SYN_DROPPED :
slouken@6844
   916
#ifdef DEBUG_INPUT_EVENTS
philipp@7133
   917
                    printf("Event SYN_DROPPED detected\n");
slouken@6844
   918
#endif
slouken@6844
   919
                    PollAllValues(joystick);
slouken@6844
   920
                    break;
slouken@6844
   921
                default:
slouken@6844
   922
                    break;
slouken@6844
   923
                }
slouken@1895
   924
            default:
slouken@1895
   925
                break;
slouken@1895
   926
            }
slouken@1895
   927
        }
slouken@1895
   928
    }
slouken@0
   929
}
slouken@0
   930
slouken@12088
   931
static void
slouken@12088
   932
LINUX_JoystickUpdate(SDL_Joystick * joystick)
slouken@0
   933
{
slouken@1895
   934
    int i;
slouken@1895
   935
slouken@11532
   936
    if (joystick->hwdata->m_bSteamController) {
slouken@11532
   937
        SDL_UpdateSteamController(joystick);
slouken@11532
   938
        return;
slouken@11532
   939
    }
slouken@11532
   940
icculus@6729
   941
    HandleInputEvents(joystick);
slouken@0
   942
slouken@1895
   943
    /* Deliver ball motion updates */
slouken@1895
   944
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
   945
        int xrel, yrel;
slouken@0
   946
slouken@1895
   947
        xrel = joystick->hwdata->balls[i].axis[0];
slouken@1895
   948
        yrel = joystick->hwdata->balls[i].axis[1];
slouken@1895
   949
        if (xrel || yrel) {
slouken@1895
   950
            joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
   951
            joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
   952
            SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
slouken@1895
   953
        }
slouken@1895
   954
    }
slouken@0
   955
}
slouken@0
   956
slouken@0
   957
/* Function to close a joystick after use */
slouken@12088
   958
static void
slouken@12088
   959
LINUX_JoystickClose(SDL_Joystick * joystick)
slouken@0
   960
{
slouken@1895
   961
    if (joystick->hwdata) {
slouken@12088
   962
        if (joystick->hwdata->effect.id >= 0) {
slouken@12088
   963
            ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
slouken@12088
   964
            joystick->hwdata->effect.id = -1;
slouken@12088
   965
        }
slouken@11532
   966
        if (joystick->hwdata->fd >= 0) {
slouken@11532
   967
            close(joystick->hwdata->fd);
slouken@11532
   968
        }
icculus@6752
   969
        if (joystick->hwdata->item) {
icculus@6752
   970
            joystick->hwdata->item->hwdata = NULL;
icculus@6752
   971
        }
icculus@6734
   972
        SDL_free(joystick->hwdata->hats);
icculus@6734
   973
        SDL_free(joystick->hwdata->balls);
icculus@6734
   974
        SDL_free(joystick->hwdata->fname);
slouken@1895
   975
        SDL_free(joystick->hwdata);
slouken@1895
   976
    }
slouken@0
   977
}
slouken@0
   978
slouken@0
   979
/* Function to perform any system-specific joystick related cleanup */
slouken@12088
   980
static void
slouken@12088
   981
LINUX_JoystickQuit(void)
slouken@0
   982
{
icculus@6734
   983
    SDL_joylist_item *item = NULL;
icculus@6734
   984
    SDL_joylist_item *next = NULL;
icculus@6734
   985
icculus@6734
   986
    for (item = SDL_joylist; item; item = next) {
icculus@6734
   987
        next = item->next;
icculus@6734
   988
        SDL_free(item->path);
icculus@6734
   989
        SDL_free(item->name);
icculus@6734
   990
        SDL_free(item);
icculus@6734
   991
    }
icculus@6734
   992
icculus@6734
   993
    SDL_joylist = SDL_joylist_tail = NULL;
slouken@0
   994
icculus@6734
   995
    numjoysticks = 0;
icculus@6734
   996
icculus@6734
   997
#if SDL_USE_LIBUDEV
gabomdq@7772
   998
    SDL_UDEV_DelCallback(joystick_udev_callback);
gabomdq@7772
   999
    SDL_UDEV_Quit();
icculus@6734
  1000
#endif
slouken@11532
  1001
slouken@11532
  1002
    SDL_QuitSteamControllers();
slouken@0
  1003
}
slouken@0
  1004
slouken@12088
  1005
SDL_JoystickDriver SDL_LINUX_JoystickDriver =
slouken@6690
  1006
{
slouken@12088
  1007
    LINUX_JoystickInit,
slouken@12088
  1008
    LINUX_JoystickGetCount,
slouken@12088
  1009
    LINUX_JoystickDetect,
slouken@12088
  1010
    LINUX_JoystickGetDeviceName,
slouken@12359
  1011
    LINUX_JoystickGetDevicePlayerIndex,
slouken@12088
  1012
    LINUX_JoystickGetDeviceGUID,
slouken@12088
  1013
    LINUX_JoystickGetDeviceInstanceID,
slouken@12088
  1014
    LINUX_JoystickOpen,
slouken@12088
  1015
    LINUX_JoystickRumble,
slouken@12088
  1016
    LINUX_JoystickUpdate,
slouken@12088
  1017
    LINUX_JoystickClose,
slouken@12088
  1018
    LINUX_JoystickQuit,
slouken@12088
  1019
};
slouken@6690
  1020
slouken@1635
  1021
#endif /* SDL_JOYSTICK_LINUX */
slouken@6693
  1022
slouken@1895
  1023
/* vi: set ts=4 sw=4 expandtab: */