src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Wed, 14 Nov 2018 13:37:22 -0800
changeset 12410 a7ee81795c75
parent 12359 691c32a30fb9
child 12459 34266b6e578d
permissions -rw-r--r--
Fixed bug 3193 - Dualshock 3's motion sensors overwrite analog stick

maxxus

The Dualshock 3's motion sensors don't seem to be reported by the call to EVIOCGBIT but they still send EV_ABS events. Because they're not reported by EVIOCGBIT they're not assigned a proper axis ids and the default of 0 is used, which is the valid id for the left analog sticks left/right axis.
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
{
slouken@10966
    90
    /* This list is taken from:
slouken@10966
    91
       https://raw.githubusercontent.com/denilsonsa/udev-joystick-blacklist/master/generate_rules.py
slouken@10966
    92
     */
slouken@10966
    93
    static Uint32 joystick_blacklist[] = {
slouken@10966
    94
        /* Microsoft Microsoft Wireless Optical Desktop® 2.10 */
slouken@10966
    95
        /* Microsoft Wireless Desktop - Comfort Edition */
slouken@10966
    96
        MAKE_VIDPID(0x045e, 0x009d),
slouken@10966
    97
slouken@10966
    98
        /* Microsoft Microsoft® Digital Media Pro Keyboard */
slouken@10966
    99
        /* Microsoft Corp. Digital Media Pro Keyboard */
slouken@10966
   100
        MAKE_VIDPID(0x045e, 0x00b0),
slouken@10966
   101
slouken@10966
   102
        /* Microsoft Microsoft® Digital Media Keyboard */
slouken@10966
   103
        /* Microsoft Corp. Digital Media Keyboard 1.0A */
slouken@10966
   104
        MAKE_VIDPID(0x045e, 0x00b4),
slouken@10966
   105
slouken@10966
   106
        /* Microsoft Microsoft® Digital Media Keyboard 3000 */
slouken@10966
   107
        MAKE_VIDPID(0x045e, 0x0730),
slouken@10966
   108
slouken@10966
   109
        /* Microsoft Microsoft® 2.4GHz Transceiver v6.0 */
slouken@10966
   110
        /* Microsoft Microsoft® 2.4GHz Transceiver v8.0 */
slouken@10966
   111
        /* Microsoft Corp. Nano Transceiver v1.0 for Bluetooth */
slouken@10966
   112
        /* Microsoft Wireless Mobile Mouse 1000 */
slouken@10966
   113
        /* Microsoft Wireless Desktop 3000 */
slouken@10966
   114
        MAKE_VIDPID(0x045e, 0x0745),
slouken@10966
   115
slouken@10966
   116
        /* Microsoft® SideWinder(TM) 2.4GHz Transceiver */
slouken@10966
   117
        MAKE_VIDPID(0x045e, 0x0748),
slouken@10966
   118
slouken@10966
   119
        /* Microsoft Corp. Wired Keyboard 600 */
slouken@10966
   120
        MAKE_VIDPID(0x045e, 0x0750),
slouken@10966
   121
slouken@10966
   122
        /* Microsoft Corp. Sidewinder X4 keyboard */
slouken@10966
   123
        MAKE_VIDPID(0x045e, 0x0768),
slouken@10966
   124
slouken@10966
   125
        /* Microsoft Corp. Arc Touch Mouse Transceiver */
slouken@10966
   126
        MAKE_VIDPID(0x045e, 0x0773),
slouken@10966
   127
slouken@10966
   128
        /* Microsoft® 2.4GHz Transceiver v9.0 */
slouken@10966
   129
        /* Microsoft® Nano Transceiver v2.1 */
slouken@10966
   130
        /* Microsoft Sculpt Ergonomic Keyboard (5KV-00001) */
slouken@10966
   131
        MAKE_VIDPID(0x045e, 0x07a5),
slouken@10966
   132
slouken@10966
   133
        /* Microsoft® Nano Transceiver v1.0 */
slouken@10966
   134
        /* Microsoft Wireless Keyboard 800 */
slouken@10966
   135
        MAKE_VIDPID(0x045e, 0x07b2),
slouken@10966
   136
slouken@10966
   137
        /* Microsoft® Nano Transceiver v2.0 */
slouken@10966
   138
        MAKE_VIDPID(0x045e, 0x0800),
slouken@10966
   139
slouken@10966
   140
        /* List of Wacom devices at: http://linuxwacom.sourceforge.net/wiki/index.php/Device_IDs */
slouken@10966
   141
        MAKE_VIDPID(0x056a, 0x0010),  /* Wacom ET-0405 Graphire */
slouken@10966
   142
        MAKE_VIDPID(0x056a, 0x0011),  /* Wacom ET-0405A Graphire2 (4x5) */
slouken@10966
   143
        MAKE_VIDPID(0x056a, 0x0012),  /* Wacom ET-0507A Graphire2 (5x7) */
slouken@10966
   144
        MAKE_VIDPID(0x056a, 0x0013),  /* Wacom CTE-430 Graphire3 (4x5) */
slouken@10966
   145
        MAKE_VIDPID(0x056a, 0x0014),  /* Wacom CTE-630 Graphire3 (6x8) */
slouken@10966
   146
        MAKE_VIDPID(0x056a, 0x0015),  /* Wacom CTE-440 Graphire4 (4x5) */
slouken@10966
   147
        MAKE_VIDPID(0x056a, 0x0016),  /* Wacom CTE-640 Graphire4 (6x8) */
slouken@10966
   148
        MAKE_VIDPID(0x056a, 0x0017),  /* Wacom CTE-450 Bamboo Fun (4x5) */
slouken@10966
   149
        MAKE_VIDPID(0x056a, 0x0016),  /* Wacom CTE-640 Graphire 4 6x8 */
slouken@10966
   150
        MAKE_VIDPID(0x056a, 0x0017),  /* Wacom CTE-450 Bamboo Fun 4x5 */
slouken@10966
   151
        MAKE_VIDPID(0x056a, 0x0018),  /* Wacom CTE-650 Bamboo Fun 6x8 */
slouken@10966
   152
        MAKE_VIDPID(0x056a, 0x0019),  /* Wacom CTE-631 Bamboo One */
slouken@10966
   153
        MAKE_VIDPID(0x056a, 0x00d1),  /* Wacom Bamboo Pen and Touch CTH-460 */
slouken@10966
   154
slouken@10966
   155
        MAKE_VIDPID(0x09da, 0x054f),  /* A4 Tech Co., G7 750 mouse */
slouken@10966
   156
        MAKE_VIDPID(0x09da, 0x3043),  /* A4 Tech Co., Ltd Bloody R8A Gaming Mouse */
slouken@10966
   157
        MAKE_VIDPID(0x09da, 0x31b5),  /* A4 Tech Co., Ltd Bloody TL80 Terminator Laser Gaming Mouse */
slouken@10966
   158
        MAKE_VIDPID(0x09da, 0x3997),  /* A4 Tech Co., Ltd Bloody RT7 Terminator Wireless */
slouken@10966
   159
        MAKE_VIDPID(0x09da, 0x3f8b),  /* A4 Tech Co., Ltd Bloody V8 mouse */
slouken@10966
   160
        MAKE_VIDPID(0x09da, 0x51f4),  /* Modecom MC-5006 Keyboard */
slouken@10966
   161
        MAKE_VIDPID(0x09da, 0x5589),  /* A4 Tech Co., Ltd Terminator TL9 Laser Gaming Mouse */
slouken@10966
   162
        MAKE_VIDPID(0x09da, 0x7b22),  /* A4 Tech Co., Ltd Bloody V5 */
slouken@10966
   163
        MAKE_VIDPID(0x09da, 0x7f2d),  /* A4 Tech Co., Ltd Bloody R3 mouse */
slouken@10966
   164
        MAKE_VIDPID(0x09da, 0x8090),  /* A4 Tech Co., Ltd X-718BK Oscar Optical Gaming Mouse */
slouken@10966
   165
        MAKE_VIDPID(0x09da, 0x9066),  /* A4 Tech Co., Sharkoon Fireglider Optical */
slouken@10966
   166
        MAKE_VIDPID(0x09da, 0x9090),  /* A4 Tech Co., Ltd XL-730K / XL-750BK / XL-755BK Laser Mouse */
slouken@10966
   167
        MAKE_VIDPID(0x09da, 0x90c0),  /* A4 Tech Co., Ltd X7 G800V keyboard */
slouken@10966
   168
        MAKE_VIDPID(0x09da, 0xf012),  /* A4 Tech Co., Ltd Bloody V7 mouse */
slouken@10966
   169
        MAKE_VIDPID(0x09da, 0xf32a),  /* A4 Tech Co., Ltd Bloody B540 keyboard */
slouken@10966
   170
        MAKE_VIDPID(0x09da, 0xf613),  /* A4 Tech Co., Ltd Bloody V2 mouse */
slouken@10966
   171
        MAKE_VIDPID(0x09da, 0xf624),  /* A4 Tech Co., Ltd Bloody B120 Keyboard */
slouken@10966
   172
slouken@10966
   173
        MAKE_VIDPID(0x1d57, 0xad03),  /* [T3] 2.4GHz and IR Air Mouse Remote Control */
slouken@10966
   174
slouken@10966
   175
        MAKE_VIDPID(0x1e7d, 0x2e4a),  /* Roccat Tyon Mouse */
slouken@10966
   176
slouken@10966
   177
        MAKE_VIDPID(0x20a0, 0x422d),  /* Winkeyless.kr Keyboards */
slouken@10966
   178
slouken@10966
   179
        MAKE_VIDPID(0x2516, 0x001f),  /* Cooler Master Storm Mizar Mouse */
slouken@10966
   180
        MAKE_VIDPID(0x2516, 0x0028),  /* Cooler Master Storm Alcor Mouse */
slouken@10966
   181
    };
gabomdq@7909
   182
    struct input_id inpid;
slouken@10966
   183
    int i;
slouken@10966
   184
    Uint32 id;
slouken@10595
   185
    Uint16 *guid16 = (Uint16 *)guid->data;
gabomdq@7909
   186
gabomdq@7909
   187
#if !SDL_USE_LIBUDEV
gabomdq@7909
   188
    /* When udev is enabled we only get joystick devices here, so there's no need to test them */
slouken@3404
   189
    unsigned long evbit[NBITS(EV_MAX)] = { 0 };
slouken@3404
   190
    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
slouken@3404
   191
    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
slouken@0
   192
slouken@1895
   193
    if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
slouken@1895
   194
        (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
slouken@1895
   195
        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
slouken@1895
   196
        return (0);
slouken@1895
   197
    }
bobbens@3079
   198
slouken@1895
   199
    if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
bobbens@3079
   200
          test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
slouken@1895
   201
        return 0;
bobbens@3079
   202
    }
gabomdq@7909
   203
#endif
icculus@6734
   204
icculus@6734
   205
    if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
icculus@6734
   206
        return 0;
icculus@6734
   207
    }
icculus@6734
   208
icculus@6734
   209
    if (ioctl(fd, EVIOCGID, &inpid) < 0) {
icculus@6734
   210
        return 0;
icculus@6734
   211
    }
icculus@6734
   212
slouken@12088
   213
#ifdef SDL_JOYSTICK_HIDAPI
slouken@12115
   214
    if (HIDAPI_IsDevicePresent(inpid.vendor, inpid.product, inpid.version)) {
slouken@12088
   215
        /* The HIDAPI driver is taking care of this device */
slouken@12088
   216
        return 0;
slouken@12088
   217
    }
slouken@12088
   218
#endif
slouken@12088
   219
slouken@10966
   220
    /* Check the joystick blacklist */
slouken@10966
   221
    id = MAKE_VIDPID(inpid.vendor, inpid.product);
slouken@10966
   222
    for (i = 0; i < SDL_arraysize(joystick_blacklist); ++i) {
slouken@10966
   223
        if (id == joystick_blacklist[i]) {
slouken@10966
   224
            return 0;
slouken@10966
   225
        }
slouken@10966
   226
    }
slouken@10966
   227
slouken@6831
   228
#ifdef DEBUG_JOYSTICK
slouken@10595
   229
    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
   230
#endif
slouken@6831
   231
slouken@6831
   232
    SDL_memset(guid->data, 0, sizeof(guid->data));
slouken@6831
   233
icculus@6734
   234
    /* We only need 16 bits for each of these; space them out to fill 128. */
icculus@6734
   235
    /* Byteswap so devices get same GUID on little/big endian platforms. */
slouken@10595
   236
    *guid16++ = SDL_SwapLE16(inpid.bustype);
slouken@10595
   237
    *guid16++ = 0;
slouken@6831
   238
slouken@10595
   239
    if (inpid.vendor && inpid.product) {
slouken@10595
   240
        *guid16++ = SDL_SwapLE16(inpid.vendor);
slouken@10595
   241
        *guid16++ = 0;
slouken@10595
   242
        *guid16++ = SDL_SwapLE16(inpid.product);
slouken@10595
   243
        *guid16++ = 0;
slouken@10595
   244
        *guid16++ = SDL_SwapLE16(inpid.version);
slouken@10595
   245
        *guid16++ = 0;
slouken@6831
   246
    } else {
slouken@6831
   247
        SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
slouken@6831
   248
    }
icculus@6734
   249
slouken@12088
   250
    if (SDL_ShouldIgnoreJoystick(namebuf, *guid)) {
slouken@11201
   251
        return 0;
slouken@11201
   252
    }
icculus@6734
   253
    return 1;
slouken@0
   254
}
slouken@0
   255
gabomdq@7772
   256
#if SDL_USE_LIBUDEV
philipp@11094
   257
static void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
gabomdq@7772
   258
{
slouken@9321
   259
    if (devpath == NULL) {
gabomdq@7772
   260
        return;
gabomdq@7772
   261
    }
slouken@9321
   262
slouken@9321
   263
    switch (udev_type) {
gabomdq@7772
   264
        case SDL_UDEV_DEVICEADDED:
slouken@9321
   265
            if (!(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
slouken@9321
   266
                return;
slouken@9321
   267
            }
slouken@7802
   268
            MaybeAddDevice(devpath);
gabomdq@7772
   269
            break;
gabomdq@7772
   270
            
gabomdq@7772
   271
        case SDL_UDEV_DEVICEREMOVED:
slouken@7802
   272
            MaybeRemoveDevice(devpath);
gabomdq@7772
   273
            break;
gabomdq@7772
   274
            
gabomdq@7772
   275
        default:
gabomdq@7772
   276
            break;
gabomdq@7772
   277
    }
gabomdq@7772
   278
    
gabomdq@7772
   279
}
gabomdq@7772
   280
#endif /* SDL_USE_LIBUDEV */
gabomdq@7772
   281
slouken@0
   282
icculus@6734
   283
/* !!! FIXME: I would love to dump this code and use libudev instead. */
icculus@6734
   284
static int
icculus@6734
   285
MaybeAddDevice(const char *path)
icculus@6734
   286
{
icculus@6734
   287
    struct stat sb;
icculus@6734
   288
    int fd = -1;
icculus@6734
   289
    int isstick = 0;
icculus@6734
   290
    char namebuf[128];
slouken@6743
   291
    SDL_JoystickGUID guid;
icculus@6734
   292
    SDL_joylist_item *item;
icculus@6734
   293
icculus@6734
   294
    if (path == NULL) {
icculus@6734
   295
        return -1;
icculus@6734
   296
    }
icculus@6734
   297
icculus@6734
   298
    if (stat(path, &sb) == -1) {
icculus@6734
   299
        return -1;
icculus@6734
   300
    }
icculus@6734
   301
icculus@6734
   302
    /* Check to make sure it's not already in list. */
icculus@6734
   303
    for (item = SDL_joylist; item != NULL; item = item->next) {
icculus@6734
   304
        if (sb.st_rdev == item->devnum) {
icculus@6734
   305
            return -1;  /* already have this one */
icculus@6734
   306
        }
icculus@6734
   307
    }
icculus@6734
   308
icculus@6734
   309
    fd = open(path, O_RDONLY, 0);
icculus@6734
   310
    if (fd < 0) {
icculus@6734
   311
        return -1;
icculus@6734
   312
    }
icculus@6734
   313
icculus@6734
   314
#ifdef DEBUG_INPUT_EVENTS
icculus@6734
   315
    printf("Checking %s\n", path);
icculus@6734
   316
#endif
icculus@6734
   317
icculus@6734
   318
    isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
icculus@6734
   319
    close(fd);
icculus@6734
   320
    if (!isstick) {
icculus@6734
   321
        return -1;
icculus@6734
   322
    }
icculus@6734
   323
icculus@6734
   324
    item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
icculus@6734
   325
    if (item == NULL) {
icculus@6734
   326
        return -1;
icculus@6734
   327
    }
icculus@6734
   328
icculus@6734
   329
    SDL_zerop(item);
icculus@6734
   330
    item->devnum = sb.st_rdev;
icculus@6734
   331
    item->path = SDL_strdup(path);
icculus@6734
   332
    item->name = SDL_strdup(namebuf);
icculus@6734
   333
    item->guid = guid;
icculus@6734
   334
slouken@12088
   335
    if ((item->path == NULL) || (item->name == NULL)) {
icculus@6734
   336
         SDL_free(item->path);
icculus@6734
   337
         SDL_free(item->name);
icculus@6734
   338
         SDL_free(item);
icculus@6734
   339
         return -1;
icculus@6734
   340
    }
icculus@6734
   341
slouken@12088
   342
    item->device_instance = SDL_GetNextJoystickInstanceID();
icculus@6734
   343
    if (SDL_joylist_tail == NULL) {
icculus@6734
   344
        SDL_joylist = SDL_joylist_tail = item;
icculus@6734
   345
    } else {
icculus@6734
   346
        SDL_joylist_tail->next = item;
icculus@6734
   347
        SDL_joylist_tail = item;
icculus@6734
   348
    }
icculus@6734
   349
slouken@7916
   350
    /* Need to increment the joystick count before we post the event */
slouken@7916
   351
    ++numjoysticks;
slouken@7916
   352
slouken@12088
   353
    SDL_PrivateJoystickAdded(item->device_instance);
slouken@7802
   354
slouken@7916
   355
    return numjoysticks;
icculus@6734
   356
}
icculus@6734
   357
icculus@6749
   358
#if SDL_USE_LIBUDEV
icculus@6734
   359
/* !!! FIXME: I would love to dump this code and use libudev instead. */
icculus@6734
   360
static int
icculus@6734
   361
MaybeRemoveDevice(const char *path)
icculus@6734
   362
{
icculus@6734
   363
    SDL_joylist_item *item;
icculus@6734
   364
    SDL_joylist_item *prev = NULL;
icculus@6734
   365
icculus@6734
   366
    if (path == NULL) {
icculus@6734
   367
        return -1;
icculus@6734
   368
    }
slouken@6690
   369
icculus@6734
   370
    for (item = SDL_joylist; item != NULL; item = item->next) {
icculus@6734
   371
        /* found it, remove it. */
icculus@6734
   372
        if (SDL_strcmp(path, item->path) == 0) {
icculus@6734
   373
            const int retval = item->device_instance;
icculus@6734
   374
            if (item->hwdata) {
icculus@6752
   375
                item->hwdata->item = NULL;
icculus@6734
   376
            }
icculus@6734
   377
            if (prev != NULL) {
icculus@6734
   378
                prev->next = item->next;
icculus@6734
   379
            } else {
jorgen@6865
   380
                SDL_assert(SDL_joylist == item);
jorgen@6865
   381
                SDL_joylist = item->next;
jorgen@6865
   382
            }
jorgen@6865
   383
            if (item == SDL_joylist_tail) {
jorgen@6865
   384
                SDL_joylist_tail = prev;
icculus@6734
   385
            }
slouken@7802
   386
slouken@7916
   387
            /* Need to decrement the joystick count before we post the event */
slouken@7916
   388
            --numjoysticks;
slouken@7916
   389
slouken@10226
   390
            SDL_PrivateJoystickRemoved(item->device_instance);
slouken@7802
   391
icculus@6734
   392
            SDL_free(item->path);
icculus@6734
   393
            SDL_free(item->name);
icculus@6734
   394
            SDL_free(item);
icculus@6734
   395
            return retval;
icculus@6734
   396
        }
icculus@6734
   397
        prev = item;
icculus@6734
   398
    }
icculus@6734
   399
icculus@6734
   400
    return -1;
icculus@6734
   401
}
icculus@6749
   402
#endif
icculus@6734
   403
slouken@10609
   404
#if ! SDL_USE_LIBUDEV
icculus@6734
   405
static int
icculus@6734
   406
JoystickInitWithoutUdev(void)
icculus@6734
   407
{
icculus@6734
   408
    int i;
icculus@6734
   409
    char path[PATH_MAX];
icculus@6734
   410
icculus@6734
   411
    /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
icculus@6734
   412
    /* !!! FIXME:  we could at least readdir() through /dev/input...? */
icculus@6734
   413
    /* !!! FIXME:  (or delete this and rely on libudev?) */
icculus@6734
   414
    for (i = 0; i < 32; i++) {
icculus@6734
   415
        SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
icculus@6734
   416
        MaybeAddDevice(path);
icculus@6734
   417
    }
icculus@6734
   418
slouken@12088
   419
    return 0;
icculus@6734
   420
}
slouken@10609
   421
#endif
icculus@6734
   422
icculus@6734
   423
#if SDL_USE_LIBUDEV
icculus@6734
   424
static int
icculus@6734
   425
JoystickInitWithUdev(void)
icculus@6734
   426
{
gabomdq@7772
   427
    if (SDL_UDEV_Init() < 0) {
gabomdq@7772
   428
        return SDL_SetError("Could not initialize UDEV");
icculus@6734
   429
    }
icculus@6734
   430
gabomdq@7772
   431
    /* Set up the udev callback */
slouken@9321
   432
    if (SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
gabomdq@7772
   433
        SDL_UDEV_Quit();
gabomdq@7772
   434
        return SDL_SetError("Could not set up joystick <-> udev callback");
icculus@6734
   435
    }
gabomdq@7772
   436
    
gabomdq@7772
   437
    /* Force a scan to build the initial device list */
gabomdq@7772
   438
    SDL_UDEV_Scan();
icculus@6734
   439
slouken@12088
   440
    return 0;
icculus@6734
   441
}
icculus@6734
   442
#endif
icculus@6734
   443
slouken@11532
   444
static SDL_bool SteamControllerConnectedCallback(const char *name, SDL_JoystickGUID guid, int *device_instance)
slouken@11532
   445
{
slouken@11532
   446
    SDL_joylist_item *item;
slouken@11532
   447
slouken@11532
   448
    item = (SDL_joylist_item *) SDL_calloc(1, sizeof (SDL_joylist_item));
slouken@11532
   449
    if (item == NULL) {
slouken@11532
   450
        return SDL_FALSE;
slouken@11532
   451
    }
slouken@11532
   452
slouken@11532
   453
    item->path = SDL_strdup("");
slouken@11532
   454
    item->name = SDL_strdup(name);
slouken@11532
   455
    item->guid = guid;
slouken@11532
   456
    item->m_bSteamController = SDL_TRUE;
slouken@11532
   457
slouken@11532
   458
    if ((item->path == NULL) || (item->name == NULL)) {
slouken@11532
   459
         SDL_free(item->path);
slouken@11532
   460
         SDL_free(item->name);
slouken@11532
   461
         SDL_free(item);
slouken@11532
   462
         return SDL_FALSE;
slouken@11532
   463
    }
slouken@11532
   464
slouken@12088
   465
    *device_instance = item->device_instance = SDL_GetNextJoystickInstanceID();
slouken@11532
   466
    if (SDL_joylist_tail == NULL) {
slouken@11532
   467
        SDL_joylist = SDL_joylist_tail = item;
slouken@11532
   468
    } else {
slouken@11532
   469
        SDL_joylist_tail->next = item;
slouken@11532
   470
        SDL_joylist_tail = item;
slouken@11532
   471
    }
slouken@11532
   472
slouken@11532
   473
    /* Need to increment the joystick count before we post the event */
slouken@11532
   474
    ++numjoysticks;
slouken@11532
   475
slouken@12088
   476
    SDL_PrivateJoystickAdded(item->device_instance);
slouken@11532
   477
slouken@11532
   478
    return SDL_TRUE;
slouken@11532
   479
}
slouken@11532
   480
slouken@11532
   481
static void SteamControllerDisconnectedCallback(int device_instance)
slouken@11532
   482
{
slouken@11532
   483
    SDL_joylist_item *item;
slouken@11532
   484
    SDL_joylist_item *prev = NULL;
slouken@11532
   485
slouken@11532
   486
    for (item = SDL_joylist; item != NULL; item = item->next) {
slouken@11532
   487
        /* found it, remove it. */
slouken@11532
   488
        if (item->device_instance == device_instance) {
slouken@11532
   489
            if (item->hwdata) {
slouken@11532
   490
                item->hwdata->item = NULL;
slouken@11532
   491
            }
slouken@11532
   492
            if (prev != NULL) {
slouken@11532
   493
                prev->next = item->next;
slouken@11532
   494
            } else {
slouken@11532
   495
                SDL_assert(SDL_joylist == item);
slouken@11532
   496
                SDL_joylist = item->next;
slouken@11532
   497
            }
slouken@11532
   498
            if (item == SDL_joylist_tail) {
slouken@11532
   499
                SDL_joylist_tail = prev;
slouken@11532
   500
            }
slouken@11532
   501
slouken@11532
   502
            /* Need to decrement the joystick count before we post the event */
slouken@11532
   503
            --numjoysticks;
slouken@11532
   504
slouken@11532
   505
            SDL_PrivateJoystickRemoved(item->device_instance);
slouken@11532
   506
slouken@11532
   507
            SDL_free(item->name);
slouken@11532
   508
            SDL_free(item);
slouken@11532
   509
            return;
slouken@11532
   510
        }
slouken@11532
   511
        prev = item;
slouken@11532
   512
    }
slouken@11532
   513
}
slouken@11532
   514
slouken@12088
   515
static int
slouken@12088
   516
LINUX_JoystickInit(void)
slouken@0
   517
{
slouken@5317
   518
    /* First see if the user specified one or more joysticks to use */
slouken@1895
   519
    if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
slouken@5317
   520
        char *envcopy, *envpath, *delim;
slouken@5317
   521
        envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
slouken@5317
   522
        envpath = envcopy;
slouken@5317
   523
        while (envpath != NULL) {
slouken@5317
   524
            delim = SDL_strchr(envpath, ':');
slouken@5317
   525
            if (delim != NULL) {
slouken@5317
   526
                *delim++ = '\0';
slouken@5317
   527
            }
icculus@6734
   528
            MaybeAddDevice(envpath);
slouken@5317
   529
            envpath = delim;
slouken@1895
   530
        }
slouken@5317
   531
        SDL_free(envcopy);
slouken@1895
   532
    }
slouken@554
   533
slouken@11532
   534
    SDL_InitSteamControllers(SteamControllerConnectedCallback,
slouken@11532
   535
                             SteamControllerDisconnectedCallback);
slouken@11532
   536
icculus@6734
   537
#if SDL_USE_LIBUDEV
gabomdq@7772
   538
    return JoystickInitWithUdev();
slouken@10609
   539
#else 
slouken@10609
   540
    return JoystickInitWithoutUdev();
slouken@0
   541
#endif
slouken@0
   542
}
slouken@0
   543
slouken@12088
   544
static int
slouken@12088
   545
LINUX_JoystickGetCount(void)
slouken@6707
   546
{
icculus@6734
   547
    return numjoysticks;
icculus@6734
   548
}
icculus@6734
   549
slouken@12088
   550
static void
slouken@12088
   551
LINUX_JoystickDetect(void)
slouken@6707
   552
{
icculus@6734
   553
#if SDL_USE_LIBUDEV
gabomdq@7772
   554
    SDL_UDEV_Poll();
icculus@6734
   555
#endif
slouken@11532
   556
slouken@11532
   557
    SDL_UpdateSteamControllers();
slouken@6707
   558
}
slouken@6707
   559
icculus@6734
   560
static SDL_joylist_item *
icculus@6734
   561
JoystickByDevIndex(int device_index)
icculus@6734
   562
{
icculus@6734
   563
    SDL_joylist_item *item = SDL_joylist;
icculus@6734
   564
icculus@6734
   565
    if ((device_index < 0) || (device_index >= numjoysticks)) {
icculus@6734
   566
        return NULL;
icculus@6734
   567
    }
icculus@6734
   568
icculus@6734
   569
    while (device_index > 0) {
icculus@6734
   570
        SDL_assert(item != NULL);
icculus@6734
   571
        device_index--;
icculus@6734
   572
        item = item->next;
icculus@6734
   573
    }
icculus@6734
   574
icculus@6734
   575
    return item;
slouken@6707
   576
}
slouken@6707
   577
slouken@0
   578
/* Function to get the device-dependent name of a joystick */
slouken@12088
   579
static const char *
slouken@12088
   580
LINUX_JoystickGetDeviceName(int device_index)
slouken@0
   581
{
icculus@6734
   582
    return JoystickByDevIndex(device_index)->name;
slouken@0
   583
}
slouken@0
   584
slouken@12359
   585
static int
slouken@12359
   586
LINUX_JoystickGetDevicePlayerIndex(int device_index)
slouken@12359
   587
{
slouken@12359
   588
    return -1;
slouken@12359
   589
}
slouken@12359
   590
slouken@12088
   591
static SDL_JoystickGUID
slouken@12088
   592
LINUX_JoystickGetDeviceGUID( int device_index )
slouken@12088
   593
{
slouken@12088
   594
    return JoystickByDevIndex(device_index)->guid;
slouken@12088
   595
}
slouken@12088
   596
slouken@6707
   597
/* Function to perform the mapping from device index to the instance id for this index */
slouken@12088
   598
static SDL_JoystickID
slouken@12088
   599
LINUX_JoystickGetDeviceInstanceID(int device_index)
slouken@6707
   600
{
icculus@6734
   601
    return JoystickByDevIndex(device_index)->device_instance;
slouken@6707
   602
}
slouken@6707
   603
slouken@1895
   604
static int
slouken@1895
   605
allocate_hatdata(SDL_Joystick * joystick)
slouken@0
   606
{
slouken@1895
   607
    int i;
slouken@0
   608
slouken@1895
   609
    joystick->hwdata->hats =
slouken@1895
   610
        (struct hwdata_hat *) SDL_malloc(joystick->nhats *
slouken@1895
   611
                                         sizeof(struct hwdata_hat));
slouken@1895
   612
    if (joystick->hwdata->hats == NULL) {
slouken@1895
   613
        return (-1);
slouken@1895
   614
    }
slouken@1895
   615
    for (i = 0; i < joystick->nhats; ++i) {
slouken@1895
   616
        joystick->hwdata->hats[i].axis[0] = 1;
slouken@1895
   617
        joystick->hwdata->hats[i].axis[1] = 1;
slouken@1895
   618
    }
slouken@1895
   619
    return (0);
slouken@0
   620
}
slouken@0
   621
slouken@1895
   622
static int
slouken@1895
   623
allocate_balldata(SDL_Joystick * joystick)
slouken@0
   624
{
slouken@1895
   625
    int i;
slouken@0
   626
slouken@1895
   627
    joystick->hwdata->balls =
slouken@1895
   628
        (struct hwdata_ball *) SDL_malloc(joystick->nballs *
slouken@1895
   629
                                          sizeof(struct hwdata_ball));
slouken@1895
   630
    if (joystick->hwdata->balls == NULL) {
slouken@1895
   631
        return (-1);
slouken@1895
   632
    }
slouken@1895
   633
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
   634
        joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
   635
        joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
   636
    }
slouken@1895
   637
    return (0);
slouken@0
   638
}
slouken@0
   639
icculus@6729
   640
static void
icculus@6729
   641
ConfigJoystick(SDL_Joystick * joystick, int fd)
slouken@0
   642
{
slouken@1895
   643
    int i, t;
slouken@3404
   644
    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
slouken@3404
   645
    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
slouken@3404
   646
    unsigned long relbit[NBITS(REL_MAX)] = { 0 };
slouken@12088
   647
    unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
slouken@0
   648
slouken@1895
   649
    /* See if this device uses the new unified event API */
slouken@1895
   650
    if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
slouken@1895
   651
        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
slouken@1895
   652
        (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
slouken@0
   653
slouken@1895
   654
        /* Get the number of buttons, axes, and other thingamajigs */
slouken@1895
   655
        for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
slouken@1895
   656
            if (test_bit(i, keybit)) {
slouken@0
   657
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   658
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   659
#endif
slouken@10641
   660
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   661
                ++joystick->nbuttons;
slouken@1895
   662
            }
slouken@1895
   663
        }
slouken@10641
   664
        for (i = 0; i < BTN_JOYSTICK; ++i) {
slouken@1895
   665
            if (test_bit(i, keybit)) {
slouken@0
   666
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   667
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   668
#endif
slouken@10641
   669
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   670
                ++joystick->nbuttons;
slouken@1895
   671
            }
slouken@1895
   672
        }
icculus@9630
   673
        for (i = 0; i < ABS_MAX; ++i) {
slouken@1895
   674
            /* Skip hats */
slouken@1895
   675
            if (i == ABS_HAT0X) {
slouken@1895
   676
                i = ABS_HAT3Y;
slouken@1895
   677
                continue;
slouken@1895
   678
            }
slouken@1895
   679
            if (test_bit(i, absbit)) {
slouken@5084
   680
                struct input_absinfo absinfo;
slouken@0
   681
slouken@8053
   682
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@1895
   683
                    continue;
slouken@8053
   684
                }
slouken@0
   685
#ifdef DEBUG_INPUT_EVENTS
slouken@8053
   686
                printf("Joystick has absolute axis: 0x%.2x\n", i);
slouken@1895
   687
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@5084
   688
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@5084
   689
                       absinfo.fuzz, absinfo.flat);
slouken@0
   690
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   691
                joystick->hwdata->abs_map[i] = joystick->naxes;
slouken@5084
   692
                if (absinfo.minimum == absinfo.maximum) {
slouken@1895
   693
                    joystick->hwdata->abs_correct[i].used = 0;
slouken@1895
   694
                } else {
slouken@1895
   695
                    joystick->hwdata->abs_correct[i].used = 1;
slouken@1895
   696
                    joystick->hwdata->abs_correct[i].coef[0] =
slouken@6845
   697
                        (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
slouken@1895
   698
                    joystick->hwdata->abs_correct[i].coef[1] =
slouken@6845
   699
                        (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
slouken@6845
   700
                    t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
slouken@1895
   701
                    if (t != 0) {
slouken@1895
   702
                        joystick->hwdata->abs_correct[i].coef[2] =
slouken@6845
   703
                            (1 << 28) / t;
slouken@1895
   704
                    } else {
slouken@1895
   705
                        joystick->hwdata->abs_correct[i].coef[2] = 0;
slouken@1895
   706
                    }
slouken@1895
   707
                }
slouken@1895
   708
                ++joystick->naxes;
slouken@1895
   709
            }
slouken@1895
   710
        }
slouken@1895
   711
        for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
slouken@1895
   712
            if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
slouken@8053
   713
                struct input_absinfo absinfo;
slouken@8053
   714
slouken@8053
   715
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@8053
   716
                    continue;
slouken@8053
   717
                }
slouken@0
   718
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   719
                printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
slouken@8053
   720
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@8053
   721
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@8053
   722
                       absinfo.fuzz, absinfo.flat);
slouken@8053
   723
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   724
                ++joystick->nhats;
slouken@1895
   725
            }
slouken@1895
   726
        }
slouken@1895
   727
        if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
slouken@1895
   728
            ++joystick->nballs;
slouken@1895
   729
        }
slouken@0
   730
slouken@1895
   731
        /* Allocate data to keep track of these thingamajigs */
slouken@1895
   732
        if (joystick->nhats > 0) {
slouken@1895
   733
            if (allocate_hatdata(joystick) < 0) {
slouken@1895
   734
                joystick->nhats = 0;
slouken@1895
   735
            }
slouken@1895
   736
        }
slouken@1895
   737
        if (joystick->nballs > 0) {
slouken@1895
   738
            if (allocate_balldata(joystick) < 0) {
slouken@1895
   739
                joystick->nballs = 0;
slouken@1895
   740
            }
slouken@1895
   741
        }
slouken@1895
   742
    }
slouken@12088
   743
slouken@12088
   744
    if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
slouken@12088
   745
        if (test_bit(FF_RUMBLE, ffbit)) {
slouken@12088
   746
            joystick->hwdata->ff_rumble = SDL_TRUE;
slouken@12088
   747
        }
slouken@12088
   748
        if (test_bit(FF_SINE, ffbit)) {
slouken@12088
   749
            joystick->hwdata->ff_sine = SDL_TRUE;
slouken@12088
   750
        }
slouken@12088
   751
    }
slouken@0
   752
}
slouken@0
   753
slouken@892
   754
slouken@0
   755
/* Function to open a joystick for use.
philipp@9380
   756
   The joystick to open is specified by the device index.
slouken@0
   757
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@0
   758
   It returns 0, or -1 if there is an error.
slouken@0
   759
 */
slouken@12088
   760
static int
slouken@12088
   761
LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@0
   762
{
icculus@6734
   763
    SDL_joylist_item *item = JoystickByDevIndex(device_index);
slouken@892
   764
icculus@6734
   765
    if (item == NULL) {
icculus@7037
   766
        return SDL_SetError("No such device");
icculus@6734
   767
    }
slouken@892
   768
icculus@6751
   769
    joystick->instance_id = item->device_instance;
slouken@1895
   770
    joystick->hwdata = (struct joystick_hwdata *)
slouken@11532
   771
        SDL_calloc(1, sizeof(*joystick->hwdata));
slouken@1895
   772
    if (joystick->hwdata == NULL) {
icculus@7037
   773
        return SDL_OutOfMemory();
slouken@1895
   774
    }
icculus@6752
   775
    joystick->hwdata->item = item;
icculus@6734
   776
    joystick->hwdata->guid = item->guid;
slouken@12088
   777
    joystick->hwdata->effect.id = -1;
slouken@11532
   778
    joystick->hwdata->m_bSteamController = item->m_bSteamController;
slouken@12410
   779
    SDL_memset(joystick->hwdata->abs_map, 0xFF, sizeof(joystick->hwdata->abs_map));
slouken@11532
   780
slouken@11532
   781
    if (item->m_bSteamController) {
slouken@11532
   782
        joystick->hwdata->fd = -1;
slouken@11532
   783
        SDL_GetSteamControllerInputs(&joystick->nbuttons,
slouken@11532
   784
                                     &joystick->naxes,
slouken@11532
   785
                                     &joystick->nhats);
slouken@11532
   786
    } else {
slouken@12088
   787
        int fd = open(item->path, O_RDWR, 0);
slouken@11532
   788
        if (fd < 0) {
slouken@11532
   789
            SDL_free(joystick->hwdata);
slouken@11532
   790
            joystick->hwdata = NULL;
slouken@11532
   791
            return SDL_SetError("Unable to open %s", item->path);
slouken@11532
   792
        }
slouken@11532
   793
slouken@11532
   794
        joystick->hwdata->fd = fd;
slouken@11532
   795
        joystick->hwdata->fname = SDL_strdup(item->path);
slouken@11532
   796
        if (joystick->hwdata->fname == NULL) {
slouken@11532
   797
            SDL_free(joystick->hwdata);
slouken@11532
   798
            joystick->hwdata = NULL;
slouken@11532
   799
            close(fd);
slouken@11532
   800
            return SDL_OutOfMemory();
slouken@11532
   801
        }
slouken@11532
   802
slouken@11532
   803
        /* Set the joystick to non-blocking read mode */
slouken@11532
   804
        fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@11532
   805
slouken@11532
   806
        /* Get the number of buttons and axes on the joystick */
slouken@11532
   807
        ConfigJoystick(joystick, fd);
icculus@6734
   808
    }
icculus@6734
   809
icculus@6734
   810
    SDL_assert(item->hwdata == NULL);
icculus@6734
   811
    item->hwdata = joystick->hwdata;
slouken@0
   812
slouken@7191
   813
    /* mark joystick as fresh and ready */
slouken@6844
   814
    joystick->hwdata->fresh = 1;
slouken@6844
   815
slouken@1895
   816
    return (0);
slouken@0
   817
}
slouken@0
   818
slouken@12088
   819
static int
slouken@12088
   820
LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   821
{
slouken@12088
   822
    struct input_event event;
slouken@12088
   823
slouken@12333
   824
    if (joystick->hwdata->ff_rumble) {
slouken@12333
   825
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   826
slouken@12333
   827
        effect->type = FF_RUMBLE;
slouken@12333
   828
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   829
        effect->u.rumble.strong_magnitude = low_frequency_rumble;
slouken@12333
   830
        effect->u.rumble.weak_magnitude = high_frequency_rumble;
slouken@12333
   831
    } else if (joystick->hwdata->ff_sine) {
slouken@12333
   832
        /* Scale and average the two rumble strengths */
slouken@12333
   833
        Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
slouken@12333
   834
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   835
slouken@12333
   836
        effect->type = FF_PERIODIC;
slouken@12333
   837
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   838
        effect->u.periodic.waveform = FF_SINE;
slouken@12333
   839
        effect->u.periodic.magnitude = magnitude;
slouken@12333
   840
    } else {
slouken@12333
   841
        return SDL_Unsupported();
slouken@12088
   842
    }
slouken@12088
   843
slouken@12088
   844
    if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
slouken@12088
   845
        return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
slouken@12088
   846
    }
slouken@12088
   847
slouken@12088
   848
    event.type = EV_FF;
slouken@12088
   849
    event.code = joystick->hwdata->effect.id;
slouken@12088
   850
    event.value = 1;
slouken@12088
   851
    if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
slouken@12088
   852
        return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
slouken@12088
   853
    }
slouken@12088
   854
    return 0;
slouken@12088
   855
}
slouken@12088
   856
slouken@7860
   857
static SDL_INLINE void
slouken@1895
   858
HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
slouken@0
   859
{
slouken@1895
   860
    struct hwdata_hat *the_hat;
slouken@1895
   861
    const Uint8 position_map[3][3] = {
slouken@1895
   862
        {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
slouken@1895
   863
        {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
slouken@1895
   864
        {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
slouken@1895
   865
    };
slouken@0
   866
slouken@1895
   867
    the_hat = &stick->hwdata->hats[hat];
slouken@1895
   868
    if (value < 0) {
slouken@1895
   869
        value = 0;
slouken@1895
   870
    } else if (value == 0) {
slouken@1895
   871
        value = 1;
slouken@1895
   872
    } else if (value > 0) {
slouken@1895
   873
        value = 2;
slouken@1895
   874
    }
slouken@1895
   875
    if (value != the_hat->axis[axis]) {
slouken@1895
   876
        the_hat->axis[axis] = value;
slouken@1895
   877
        SDL_PrivateJoystickHat(stick, hat,
slouken@3013
   878
                               position_map[the_hat->
slouken@3013
   879
                                            axis[1]][the_hat->axis[0]]);
slouken@1895
   880
    }
slouken@0
   881
}
slouken@0
   882
slouken@7860
   883
static SDL_INLINE void
slouken@1895
   884
HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
slouken@0
   885
{
slouken@1895
   886
    stick->hwdata->balls[ball].axis[axis] += value;
slouken@0
   887
}
slouken@0
   888
slouken@0
   889
slouken@7860
   890
static SDL_INLINE int
icculus@6729
   891
AxisCorrect(SDL_Joystick * joystick, int which, int value)
slouken@0
   892
{
slouken@1895
   893
    struct axis_correct *correct;
slouken@0
   894
slouken@1895
   895
    correct = &joystick->hwdata->abs_correct[which];
slouken@1895
   896
    if (correct->used) {
slouken@6845
   897
        value *= 2;
slouken@1895
   898
        if (value > correct->coef[0]) {
slouken@1895
   899
            if (value < correct->coef[1]) {
slouken@1895
   900
                return 0;
slouken@1895
   901
            }
slouken@1895
   902
            value -= correct->coef[1];
slouken@1895
   903
        } else {
slouken@1895
   904
            value -= correct->coef[0];
slouken@1895
   905
        }
slouken@1895
   906
        value *= correct->coef[2];
slouken@6845
   907
        value >>= 13;
slouken@1895
   908
    }
slouken@554
   909
slouken@1895
   910
    /* Clamp and return */
slouken@1895
   911
    if (value < -32768)
slouken@1895
   912
        return -32768;
slouken@1895
   913
    if (value > 32767)
slouken@1895
   914
        return 32767;
slouken@554
   915
slouken@1895
   916
    return value;
slouken@0
   917
}
slouken@0
   918
slouken@7860
   919
static SDL_INLINE void
slouken@6844
   920
PollAllValues(SDL_Joystick * joystick)
slouken@6844
   921
{
slouken@6844
   922
    struct input_absinfo absinfo;
slouken@6844
   923
    int a, b = 0;
slouken@6844
   924
slouken@7191
   925
    /* Poll all axis */
slouken@6844
   926
    for (a = ABS_X; b < ABS_MAX; a++) {
slouken@6844
   927
        switch (a) {
slouken@6844
   928
        case ABS_HAT0X:
slouken@6844
   929
        case ABS_HAT0Y:
slouken@6844
   930
        case ABS_HAT1X:
slouken@6844
   931
        case ABS_HAT1Y:
slouken@6844
   932
        case ABS_HAT2X:
slouken@6844
   933
        case ABS_HAT2Y:
slouken@6844
   934
        case ABS_HAT3X:
slouken@6844
   935
        case ABS_HAT3Y:
slouken@7191
   936
            /* ingore hats */
slouken@6844
   937
            break;
slouken@6844
   938
        default:
slouken@6844
   939
            if (joystick->hwdata->abs_correct[b].used) {
slouken@6844
   940
                if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
slouken@6844
   941
                    absinfo.value = AxisCorrect(joystick, b, absinfo.value);
slouken@6844
   942
slouken@6844
   943
#ifdef DEBUG_INPUT_EVENTS
slouken@6844
   944
                    printf("Joystick : Re-read Axis %d (%d) val= %d\n",
slouken@6844
   945
                        joystick->hwdata->abs_map[b], a, absinfo.value);
slouken@6844
   946
#endif
slouken@6844
   947
                    SDL_PrivateJoystickAxis(joystick,
slouken@6844
   948
                            joystick->hwdata->abs_map[b],
slouken@6844
   949
                            absinfo.value);
slouken@6844
   950
                }
slouken@6844
   951
            }
slouken@6844
   952
            b++;
slouken@6844
   953
        }
slouken@6844
   954
    }
slouken@6844
   955
}
slouken@6844
   956
slouken@7860
   957
static SDL_INLINE void
icculus@6729
   958
HandleInputEvents(SDL_Joystick * joystick)
slouken@0
   959
{
slouken@1895
   960
    struct input_event events[32];
slouken@1895
   961
    int i, len;
slouken@1895
   962
    int code;
slouken@0
   963
slouken@6844
   964
    if (joystick->hwdata->fresh) {
slouken@6844
   965
        PollAllValues(joystick);
slouken@6844
   966
        joystick->hwdata->fresh = 0;
slouken@6844
   967
    }
slouken@6844
   968
slouken@1895
   969
    while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
slouken@1895
   970
        len /= sizeof(events[0]);
slouken@1895
   971
        for (i = 0; i < len; ++i) {
slouken@1895
   972
            code = events[i].code;
slouken@1895
   973
            switch (events[i].type) {
slouken@1895
   974
            case EV_KEY:
slouken@10641
   975
                SDL_PrivateJoystickButton(joystick,
slouken@10641
   976
                                          joystick->hwdata->key_map[code],
slouken@10641
   977
                                          events[i].value);
slouken@1895
   978
                break;
slouken@1895
   979
            case EV_ABS:
slouken@1895
   980
                switch (code) {
slouken@1895
   981
                case ABS_HAT0X:
slouken@1895
   982
                case ABS_HAT0Y:
slouken@1895
   983
                case ABS_HAT1X:
slouken@1895
   984
                case ABS_HAT1Y:
slouken@1895
   985
                case ABS_HAT2X:
slouken@1895
   986
                case ABS_HAT2Y:
slouken@1895
   987
                case ABS_HAT3X:
slouken@1895
   988
                case ABS_HAT3Y:
slouken@1895
   989
                    code -= ABS_HAT0X;
slouken@1895
   990
                    HandleHat(joystick, code / 2, code % 2, events[i].value);
slouken@1895
   991
                    break;
slouken@1895
   992
                default:
slouken@12410
   993
                    if (joystick->hwdata->abs_map[code] != 0xFF) {
slouken@12410
   994
                        events[i].value =
slouken@12410
   995
                            AxisCorrect(joystick, code, events[i].value);
slouken@12410
   996
                        SDL_PrivateJoystickAxis(joystick,
slouken@12410
   997
                                                joystick->hwdata->abs_map[code],
slouken@12410
   998
                                                events[i].value);
slouken@12410
   999
                    }
slouken@1895
  1000
                    break;
slouken@1895
  1001
                }
slouken@1895
  1002
                break;
slouken@1895
  1003
            case EV_REL:
slouken@1895
  1004
                switch (code) {
slouken@1895
  1005
                case REL_X:
slouken@1895
  1006
                case REL_Y:
slouken@1895
  1007
                    code -= REL_X;
slouken@1895
  1008
                    HandleBall(joystick, code / 2, code % 2, events[i].value);
slouken@1895
  1009
                    break;
slouken@1895
  1010
                default:
slouken@1895
  1011
                    break;
slouken@1895
  1012
                }
slouken@1895
  1013
                break;
slouken@6844
  1014
            case EV_SYN:
slouken@6844
  1015
                switch (code) {
slouken@6844
  1016
                case SYN_DROPPED :
slouken@6844
  1017
#ifdef DEBUG_INPUT_EVENTS
philipp@7133
  1018
                    printf("Event SYN_DROPPED detected\n");
slouken@6844
  1019
#endif
slouken@6844
  1020
                    PollAllValues(joystick);
slouken@6844
  1021
                    break;
slouken@6844
  1022
                default:
slouken@6844
  1023
                    break;
slouken@6844
  1024
                }
slouken@1895
  1025
            default:
slouken@1895
  1026
                break;
slouken@1895
  1027
            }
slouken@1895
  1028
        }
slouken@1895
  1029
    }
slouken@0
  1030
}
slouken@0
  1031
slouken@12088
  1032
static void
slouken@12088
  1033
LINUX_JoystickUpdate(SDL_Joystick * joystick)
slouken@0
  1034
{
slouken@1895
  1035
    int i;
slouken@1895
  1036
slouken@11532
  1037
    if (joystick->hwdata->m_bSteamController) {
slouken@11532
  1038
        SDL_UpdateSteamController(joystick);
slouken@11532
  1039
        return;
slouken@11532
  1040
    }
slouken@11532
  1041
icculus@6729
  1042
    HandleInputEvents(joystick);
slouken@0
  1043
slouken@1895
  1044
    /* Deliver ball motion updates */
slouken@1895
  1045
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
  1046
        int xrel, yrel;
slouken@0
  1047
slouken@1895
  1048
        xrel = joystick->hwdata->balls[i].axis[0];
slouken@1895
  1049
        yrel = joystick->hwdata->balls[i].axis[1];
slouken@1895
  1050
        if (xrel || yrel) {
slouken@1895
  1051
            joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
  1052
            joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
  1053
            SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
slouken@1895
  1054
        }
slouken@1895
  1055
    }
slouken@0
  1056
}
slouken@0
  1057
slouken@0
  1058
/* Function to close a joystick after use */
slouken@12088
  1059
static void
slouken@12088
  1060
LINUX_JoystickClose(SDL_Joystick * joystick)
slouken@0
  1061
{
slouken@1895
  1062
    if (joystick->hwdata) {
slouken@12088
  1063
        if (joystick->hwdata->effect.id >= 0) {
slouken@12088
  1064
            ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
slouken@12088
  1065
            joystick->hwdata->effect.id = -1;
slouken@12088
  1066
        }
slouken@11532
  1067
        if (joystick->hwdata->fd >= 0) {
slouken@11532
  1068
            close(joystick->hwdata->fd);
slouken@11532
  1069
        }
icculus@6752
  1070
        if (joystick->hwdata->item) {
icculus@6752
  1071
            joystick->hwdata->item->hwdata = NULL;
icculus@6752
  1072
        }
icculus@6734
  1073
        SDL_free(joystick->hwdata->hats);
icculus@6734
  1074
        SDL_free(joystick->hwdata->balls);
icculus@6734
  1075
        SDL_free(joystick->hwdata->fname);
slouken@1895
  1076
        SDL_free(joystick->hwdata);
slouken@1895
  1077
    }
slouken@0
  1078
}
slouken@0
  1079
slouken@0
  1080
/* Function to perform any system-specific joystick related cleanup */
slouken@12088
  1081
static void
slouken@12088
  1082
LINUX_JoystickQuit(void)
slouken@0
  1083
{
icculus@6734
  1084
    SDL_joylist_item *item = NULL;
icculus@6734
  1085
    SDL_joylist_item *next = NULL;
icculus@6734
  1086
icculus@6734
  1087
    for (item = SDL_joylist; item; item = next) {
icculus@6734
  1088
        next = item->next;
icculus@6734
  1089
        SDL_free(item->path);
icculus@6734
  1090
        SDL_free(item->name);
icculus@6734
  1091
        SDL_free(item);
icculus@6734
  1092
    }
icculus@6734
  1093
icculus@6734
  1094
    SDL_joylist = SDL_joylist_tail = NULL;
slouken@0
  1095
icculus@6734
  1096
    numjoysticks = 0;
icculus@6734
  1097
icculus@6734
  1098
#if SDL_USE_LIBUDEV
gabomdq@7772
  1099
    SDL_UDEV_DelCallback(joystick_udev_callback);
gabomdq@7772
  1100
    SDL_UDEV_Quit();
icculus@6734
  1101
#endif
slouken@11532
  1102
slouken@11532
  1103
    SDL_QuitSteamControllers();
slouken@0
  1104
}
slouken@0
  1105
slouken@12088
  1106
SDL_JoystickDriver SDL_LINUX_JoystickDriver =
slouken@6690
  1107
{
slouken@12088
  1108
    LINUX_JoystickInit,
slouken@12088
  1109
    LINUX_JoystickGetCount,
slouken@12088
  1110
    LINUX_JoystickDetect,
slouken@12088
  1111
    LINUX_JoystickGetDeviceName,
slouken@12359
  1112
    LINUX_JoystickGetDevicePlayerIndex,
slouken@12088
  1113
    LINUX_JoystickGetDeviceGUID,
slouken@12088
  1114
    LINUX_JoystickGetDeviceInstanceID,
slouken@12088
  1115
    LINUX_JoystickOpen,
slouken@12088
  1116
    LINUX_JoystickRumble,
slouken@12088
  1117
    LINUX_JoystickUpdate,
slouken@12088
  1118
    LINUX_JoystickClose,
slouken@12088
  1119
    LINUX_JoystickQuit,
slouken@12088
  1120
};
slouken@6690
  1121
slouken@1635
  1122
#endif /* SDL_JOYSTICK_LINUX */
slouken@6693
  1123
slouken@1895
  1124
/* vi: set ts=4 sw=4 expandtab: */