src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 16 Oct 2018 14:58:07 -0700
changeset 12333 898f03b00670
parent 12115 0d9277d27e2d
child 12359 691c32a30fb9
permissions -rw-r--r--
Fixed updating the rumble parameters on Linux
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@12088
   585
static SDL_JoystickGUID
slouken@12088
   586
LINUX_JoystickGetDeviceGUID( int device_index )
slouken@12088
   587
{
slouken@12088
   588
    return JoystickByDevIndex(device_index)->guid;
slouken@12088
   589
}
slouken@12088
   590
slouken@6707
   591
/* Function to perform the mapping from device index to the instance id for this index */
slouken@12088
   592
static SDL_JoystickID
slouken@12088
   593
LINUX_JoystickGetDeviceInstanceID(int device_index)
slouken@6707
   594
{
icculus@6734
   595
    return JoystickByDevIndex(device_index)->device_instance;
slouken@6707
   596
}
slouken@6707
   597
slouken@1895
   598
static int
slouken@1895
   599
allocate_hatdata(SDL_Joystick * joystick)
slouken@0
   600
{
slouken@1895
   601
    int i;
slouken@0
   602
slouken@1895
   603
    joystick->hwdata->hats =
slouken@1895
   604
        (struct hwdata_hat *) SDL_malloc(joystick->nhats *
slouken@1895
   605
                                         sizeof(struct hwdata_hat));
slouken@1895
   606
    if (joystick->hwdata->hats == NULL) {
slouken@1895
   607
        return (-1);
slouken@1895
   608
    }
slouken@1895
   609
    for (i = 0; i < joystick->nhats; ++i) {
slouken@1895
   610
        joystick->hwdata->hats[i].axis[0] = 1;
slouken@1895
   611
        joystick->hwdata->hats[i].axis[1] = 1;
slouken@1895
   612
    }
slouken@1895
   613
    return (0);
slouken@0
   614
}
slouken@0
   615
slouken@1895
   616
static int
slouken@1895
   617
allocate_balldata(SDL_Joystick * joystick)
slouken@0
   618
{
slouken@1895
   619
    int i;
slouken@0
   620
slouken@1895
   621
    joystick->hwdata->balls =
slouken@1895
   622
        (struct hwdata_ball *) SDL_malloc(joystick->nballs *
slouken@1895
   623
                                          sizeof(struct hwdata_ball));
slouken@1895
   624
    if (joystick->hwdata->balls == NULL) {
slouken@1895
   625
        return (-1);
slouken@1895
   626
    }
slouken@1895
   627
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
   628
        joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
   629
        joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
   630
    }
slouken@1895
   631
    return (0);
slouken@0
   632
}
slouken@0
   633
icculus@6729
   634
static void
icculus@6729
   635
ConfigJoystick(SDL_Joystick * joystick, int fd)
slouken@0
   636
{
slouken@1895
   637
    int i, t;
slouken@3404
   638
    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
slouken@3404
   639
    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
slouken@3404
   640
    unsigned long relbit[NBITS(REL_MAX)] = { 0 };
slouken@12088
   641
    unsigned long ffbit[NBITS(FF_MAX)] = { 0 };
slouken@0
   642
slouken@1895
   643
    /* See if this device uses the new unified event API */
slouken@1895
   644
    if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
slouken@1895
   645
        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
slouken@1895
   646
        (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
slouken@0
   647
slouken@1895
   648
        /* Get the number of buttons, axes, and other thingamajigs */
slouken@1895
   649
        for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
slouken@1895
   650
            if (test_bit(i, keybit)) {
slouken@0
   651
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   652
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   653
#endif
slouken@10641
   654
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   655
                ++joystick->nbuttons;
slouken@1895
   656
            }
slouken@1895
   657
        }
slouken@10641
   658
        for (i = 0; i < BTN_JOYSTICK; ++i) {
slouken@1895
   659
            if (test_bit(i, keybit)) {
slouken@0
   660
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   661
                printf("Joystick has button: 0x%x\n", i);
slouken@0
   662
#endif
slouken@10641
   663
                joystick->hwdata->key_map[i] = joystick->nbuttons;
slouken@1895
   664
                ++joystick->nbuttons;
slouken@1895
   665
            }
slouken@1895
   666
        }
icculus@9630
   667
        for (i = 0; i < ABS_MAX; ++i) {
slouken@1895
   668
            /* Skip hats */
slouken@1895
   669
            if (i == ABS_HAT0X) {
slouken@1895
   670
                i = ABS_HAT3Y;
slouken@1895
   671
                continue;
slouken@1895
   672
            }
slouken@1895
   673
            if (test_bit(i, absbit)) {
slouken@5084
   674
                struct input_absinfo absinfo;
slouken@0
   675
slouken@8053
   676
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@1895
   677
                    continue;
slouken@8053
   678
                }
slouken@0
   679
#ifdef DEBUG_INPUT_EVENTS
slouken@8053
   680
                printf("Joystick has absolute axis: 0x%.2x\n", i);
slouken@1895
   681
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@5084
   682
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@5084
   683
                       absinfo.fuzz, absinfo.flat);
slouken@0
   684
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   685
                joystick->hwdata->abs_map[i] = joystick->naxes;
slouken@5084
   686
                if (absinfo.minimum == absinfo.maximum) {
slouken@1895
   687
                    joystick->hwdata->abs_correct[i].used = 0;
slouken@1895
   688
                } else {
slouken@1895
   689
                    joystick->hwdata->abs_correct[i].used = 1;
slouken@1895
   690
                    joystick->hwdata->abs_correct[i].coef[0] =
slouken@6845
   691
                        (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
slouken@1895
   692
                    joystick->hwdata->abs_correct[i].coef[1] =
slouken@6845
   693
                        (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
slouken@6845
   694
                    t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
slouken@1895
   695
                    if (t != 0) {
slouken@1895
   696
                        joystick->hwdata->abs_correct[i].coef[2] =
slouken@6845
   697
                            (1 << 28) / t;
slouken@1895
   698
                    } else {
slouken@1895
   699
                        joystick->hwdata->abs_correct[i].coef[2] = 0;
slouken@1895
   700
                    }
slouken@1895
   701
                }
slouken@1895
   702
                ++joystick->naxes;
slouken@1895
   703
            }
slouken@1895
   704
        }
slouken@1895
   705
        for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
slouken@1895
   706
            if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
slouken@8053
   707
                struct input_absinfo absinfo;
slouken@8053
   708
slouken@8053
   709
                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
slouken@8053
   710
                    continue;
slouken@8053
   711
                }
slouken@0
   712
#ifdef DEBUG_INPUT_EVENTS
slouken@1895
   713
                printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
slouken@8053
   714
                printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@8053
   715
                       absinfo.value, absinfo.minimum, absinfo.maximum,
slouken@8053
   716
                       absinfo.fuzz, absinfo.flat);
slouken@8053
   717
#endif /* DEBUG_INPUT_EVENTS */
slouken@1895
   718
                ++joystick->nhats;
slouken@1895
   719
            }
slouken@1895
   720
        }
slouken@1895
   721
        if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
slouken@1895
   722
            ++joystick->nballs;
slouken@1895
   723
        }
slouken@0
   724
slouken@1895
   725
        /* Allocate data to keep track of these thingamajigs */
slouken@1895
   726
        if (joystick->nhats > 0) {
slouken@1895
   727
            if (allocate_hatdata(joystick) < 0) {
slouken@1895
   728
                joystick->nhats = 0;
slouken@1895
   729
            }
slouken@1895
   730
        }
slouken@1895
   731
        if (joystick->nballs > 0) {
slouken@1895
   732
            if (allocate_balldata(joystick) < 0) {
slouken@1895
   733
                joystick->nballs = 0;
slouken@1895
   734
            }
slouken@1895
   735
        }
slouken@1895
   736
    }
slouken@12088
   737
slouken@12088
   738
    if (ioctl(fd, EVIOCGBIT(EV_FF, sizeof(ffbit)), ffbit) >= 0) {
slouken@12088
   739
        if (test_bit(FF_RUMBLE, ffbit)) {
slouken@12088
   740
            joystick->hwdata->ff_rumble = SDL_TRUE;
slouken@12088
   741
        }
slouken@12088
   742
        if (test_bit(FF_SINE, ffbit)) {
slouken@12088
   743
            joystick->hwdata->ff_sine = SDL_TRUE;
slouken@12088
   744
        }
slouken@12088
   745
    }
slouken@0
   746
}
slouken@0
   747
slouken@892
   748
slouken@0
   749
/* Function to open a joystick for use.
philipp@9380
   750
   The joystick to open is specified by the device index.
slouken@0
   751
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@0
   752
   It returns 0, or -1 if there is an error.
slouken@0
   753
 */
slouken@12088
   754
static int
slouken@12088
   755
LINUX_JoystickOpen(SDL_Joystick * joystick, int device_index)
slouken@0
   756
{
icculus@6734
   757
    SDL_joylist_item *item = JoystickByDevIndex(device_index);
slouken@892
   758
icculus@6734
   759
    if (item == NULL) {
icculus@7037
   760
        return SDL_SetError("No such device");
icculus@6734
   761
    }
slouken@892
   762
icculus@6751
   763
    joystick->instance_id = item->device_instance;
slouken@1895
   764
    joystick->hwdata = (struct joystick_hwdata *)
slouken@11532
   765
        SDL_calloc(1, sizeof(*joystick->hwdata));
slouken@1895
   766
    if (joystick->hwdata == NULL) {
icculus@7037
   767
        return SDL_OutOfMemory();
slouken@1895
   768
    }
icculus@6752
   769
    joystick->hwdata->item = item;
icculus@6734
   770
    joystick->hwdata->guid = item->guid;
slouken@12088
   771
    joystick->hwdata->effect.id = -1;
slouken@11532
   772
    joystick->hwdata->m_bSteamController = item->m_bSteamController;
slouken@11532
   773
slouken@11532
   774
    if (item->m_bSteamController) {
slouken@11532
   775
        joystick->hwdata->fd = -1;
slouken@11532
   776
        SDL_GetSteamControllerInputs(&joystick->nbuttons,
slouken@11532
   777
                                     &joystick->naxes,
slouken@11532
   778
                                     &joystick->nhats);
slouken@11532
   779
    } else {
slouken@12088
   780
        int fd = open(item->path, O_RDWR, 0);
slouken@11532
   781
        if (fd < 0) {
slouken@11532
   782
            SDL_free(joystick->hwdata);
slouken@11532
   783
            joystick->hwdata = NULL;
slouken@11532
   784
            return SDL_SetError("Unable to open %s", item->path);
slouken@11532
   785
        }
slouken@11532
   786
slouken@11532
   787
        joystick->hwdata->fd = fd;
slouken@11532
   788
        joystick->hwdata->fname = SDL_strdup(item->path);
slouken@11532
   789
        if (joystick->hwdata->fname == NULL) {
slouken@11532
   790
            SDL_free(joystick->hwdata);
slouken@11532
   791
            joystick->hwdata = NULL;
slouken@11532
   792
            close(fd);
slouken@11532
   793
            return SDL_OutOfMemory();
slouken@11532
   794
        }
slouken@11532
   795
slouken@11532
   796
        /* Set the joystick to non-blocking read mode */
slouken@11532
   797
        fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@11532
   798
slouken@11532
   799
        /* Get the number of buttons and axes on the joystick */
slouken@11532
   800
        ConfigJoystick(joystick, fd);
icculus@6734
   801
    }
icculus@6734
   802
icculus@6734
   803
    SDL_assert(item->hwdata == NULL);
icculus@6734
   804
    item->hwdata = joystick->hwdata;
slouken@0
   805
slouken@7191
   806
    /* mark joystick as fresh and ready */
slouken@6844
   807
    joystick->hwdata->fresh = 1;
slouken@6844
   808
slouken@1895
   809
    return (0);
slouken@0
   810
}
slouken@0
   811
slouken@12088
   812
static int
slouken@12088
   813
LINUX_JoystickRumble(SDL_Joystick * joystick, Uint16 low_frequency_rumble, Uint16 high_frequency_rumble, Uint32 duration_ms)
slouken@12088
   814
{
slouken@12088
   815
    struct input_event event;
slouken@12088
   816
slouken@12333
   817
    if (joystick->hwdata->ff_rumble) {
slouken@12333
   818
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   819
slouken@12333
   820
        effect->type = FF_RUMBLE;
slouken@12333
   821
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   822
        effect->u.rumble.strong_magnitude = low_frequency_rumble;
slouken@12333
   823
        effect->u.rumble.weak_magnitude = high_frequency_rumble;
slouken@12333
   824
    } else if (joystick->hwdata->ff_sine) {
slouken@12333
   825
        /* Scale and average the two rumble strengths */
slouken@12333
   826
        Sint16 magnitude = (Sint16)(((low_frequency_rumble / 2) + (high_frequency_rumble / 2)) / 2);
slouken@12333
   827
        struct ff_effect *effect = &joystick->hwdata->effect;
slouken@12088
   828
slouken@12333
   829
        effect->type = FF_PERIODIC;
slouken@12333
   830
        effect->replay.length = SDL_min(duration_ms, 32767);
slouken@12333
   831
        effect->u.periodic.waveform = FF_SINE;
slouken@12333
   832
        effect->u.periodic.magnitude = magnitude;
slouken@12333
   833
    } else {
slouken@12333
   834
        return SDL_Unsupported();
slouken@12088
   835
    }
slouken@12088
   836
slouken@12088
   837
    if (ioctl(joystick->hwdata->fd, EVIOCSFF, &joystick->hwdata->effect) < 0) {
slouken@12088
   838
        return SDL_SetError("Couldn't update rumble effect: %s", strerror(errno));
slouken@12088
   839
    }
slouken@12088
   840
slouken@12088
   841
    event.type = EV_FF;
slouken@12088
   842
    event.code = joystick->hwdata->effect.id;
slouken@12088
   843
    event.value = 1;
slouken@12088
   844
    if (write(joystick->hwdata->fd, &event, sizeof(event)) < 0) {
slouken@12088
   845
        return SDL_SetError("Couldn't start rumble effect: %s", strerror(errno));
slouken@12088
   846
    }
slouken@12088
   847
    return 0;
slouken@12088
   848
}
slouken@12088
   849
slouken@7860
   850
static SDL_INLINE void
slouken@1895
   851
HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
slouken@0
   852
{
slouken@1895
   853
    struct hwdata_hat *the_hat;
slouken@1895
   854
    const Uint8 position_map[3][3] = {
slouken@1895
   855
        {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
slouken@1895
   856
        {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
slouken@1895
   857
        {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
slouken@1895
   858
    };
slouken@0
   859
slouken@1895
   860
    the_hat = &stick->hwdata->hats[hat];
slouken@1895
   861
    if (value < 0) {
slouken@1895
   862
        value = 0;
slouken@1895
   863
    } else if (value == 0) {
slouken@1895
   864
        value = 1;
slouken@1895
   865
    } else if (value > 0) {
slouken@1895
   866
        value = 2;
slouken@1895
   867
    }
slouken@1895
   868
    if (value != the_hat->axis[axis]) {
slouken@1895
   869
        the_hat->axis[axis] = value;
slouken@1895
   870
        SDL_PrivateJoystickHat(stick, hat,
slouken@3013
   871
                               position_map[the_hat->
slouken@3013
   872
                                            axis[1]][the_hat->axis[0]]);
slouken@1895
   873
    }
slouken@0
   874
}
slouken@0
   875
slouken@7860
   876
static SDL_INLINE void
slouken@1895
   877
HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
slouken@0
   878
{
slouken@1895
   879
    stick->hwdata->balls[ball].axis[axis] += value;
slouken@0
   880
}
slouken@0
   881
slouken@0
   882
slouken@7860
   883
static SDL_INLINE int
icculus@6729
   884
AxisCorrect(SDL_Joystick * joystick, int which, int value)
slouken@0
   885
{
slouken@1895
   886
    struct axis_correct *correct;
slouken@0
   887
slouken@1895
   888
    correct = &joystick->hwdata->abs_correct[which];
slouken@1895
   889
    if (correct->used) {
slouken@6845
   890
        value *= 2;
slouken@1895
   891
        if (value > correct->coef[0]) {
slouken@1895
   892
            if (value < correct->coef[1]) {
slouken@1895
   893
                return 0;
slouken@1895
   894
            }
slouken@1895
   895
            value -= correct->coef[1];
slouken@1895
   896
        } else {
slouken@1895
   897
            value -= correct->coef[0];
slouken@1895
   898
        }
slouken@1895
   899
        value *= correct->coef[2];
slouken@6845
   900
        value >>= 13;
slouken@1895
   901
    }
slouken@554
   902
slouken@1895
   903
    /* Clamp and return */
slouken@1895
   904
    if (value < -32768)
slouken@1895
   905
        return -32768;
slouken@1895
   906
    if (value > 32767)
slouken@1895
   907
        return 32767;
slouken@554
   908
slouken@1895
   909
    return value;
slouken@0
   910
}
slouken@0
   911
slouken@7860
   912
static SDL_INLINE void
slouken@6844
   913
PollAllValues(SDL_Joystick * joystick)
slouken@6844
   914
{
slouken@6844
   915
    struct input_absinfo absinfo;
slouken@6844
   916
    int a, b = 0;
slouken@6844
   917
slouken@7191
   918
    /* Poll all axis */
slouken@6844
   919
    for (a = ABS_X; b < ABS_MAX; a++) {
slouken@6844
   920
        switch (a) {
slouken@6844
   921
        case ABS_HAT0X:
slouken@6844
   922
        case ABS_HAT0Y:
slouken@6844
   923
        case ABS_HAT1X:
slouken@6844
   924
        case ABS_HAT1Y:
slouken@6844
   925
        case ABS_HAT2X:
slouken@6844
   926
        case ABS_HAT2Y:
slouken@6844
   927
        case ABS_HAT3X:
slouken@6844
   928
        case ABS_HAT3Y:
slouken@7191
   929
            /* ingore hats */
slouken@6844
   930
            break;
slouken@6844
   931
        default:
slouken@6844
   932
            if (joystick->hwdata->abs_correct[b].used) {
slouken@6844
   933
                if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
slouken@6844
   934
                    absinfo.value = AxisCorrect(joystick, b, absinfo.value);
slouken@6844
   935
slouken@6844
   936
#ifdef DEBUG_INPUT_EVENTS
slouken@6844
   937
                    printf("Joystick : Re-read Axis %d (%d) val= %d\n",
slouken@6844
   938
                        joystick->hwdata->abs_map[b], a, absinfo.value);
slouken@6844
   939
#endif
slouken@6844
   940
                    SDL_PrivateJoystickAxis(joystick,
slouken@6844
   941
                            joystick->hwdata->abs_map[b],
slouken@6844
   942
                            absinfo.value);
slouken@6844
   943
                }
slouken@6844
   944
            }
slouken@6844
   945
            b++;
slouken@6844
   946
        }
slouken@6844
   947
    }
slouken@6844
   948
}
slouken@6844
   949
slouken@7860
   950
static SDL_INLINE void
icculus@6729
   951
HandleInputEvents(SDL_Joystick * joystick)
slouken@0
   952
{
slouken@1895
   953
    struct input_event events[32];
slouken@1895
   954
    int i, len;
slouken@1895
   955
    int code;
slouken@0
   956
slouken@6844
   957
    if (joystick->hwdata->fresh) {
slouken@6844
   958
        PollAllValues(joystick);
slouken@6844
   959
        joystick->hwdata->fresh = 0;
slouken@6844
   960
    }
slouken@6844
   961
slouken@1895
   962
    while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
slouken@1895
   963
        len /= sizeof(events[0]);
slouken@1895
   964
        for (i = 0; i < len; ++i) {
slouken@1895
   965
            code = events[i].code;
slouken@1895
   966
            switch (events[i].type) {
slouken@1895
   967
            case EV_KEY:
slouken@10641
   968
                SDL_PrivateJoystickButton(joystick,
slouken@10641
   969
                                          joystick->hwdata->key_map[code],
slouken@10641
   970
                                          events[i].value);
slouken@1895
   971
                break;
slouken@1895
   972
            case EV_ABS:
slouken@1895
   973
                switch (code) {
slouken@1895
   974
                case ABS_HAT0X:
slouken@1895
   975
                case ABS_HAT0Y:
slouken@1895
   976
                case ABS_HAT1X:
slouken@1895
   977
                case ABS_HAT1Y:
slouken@1895
   978
                case ABS_HAT2X:
slouken@1895
   979
                case ABS_HAT2Y:
slouken@1895
   980
                case ABS_HAT3X:
slouken@1895
   981
                case ABS_HAT3Y:
slouken@1895
   982
                    code -= ABS_HAT0X;
slouken@1895
   983
                    HandleHat(joystick, code / 2, code % 2, events[i].value);
slouken@1895
   984
                    break;
slouken@1895
   985
                default:
slouken@1895
   986
                    events[i].value =
icculus@6729
   987
                        AxisCorrect(joystick, code, events[i].value);
icculus@6728
   988
                    SDL_PrivateJoystickAxis(joystick,
icculus@6728
   989
                                            joystick->hwdata->abs_map[code],
icculus@6728
   990
                                            events[i].value);
slouken@1895
   991
                    break;
slouken@1895
   992
                }
slouken@1895
   993
                break;
slouken@1895
   994
            case EV_REL:
slouken@1895
   995
                switch (code) {
slouken@1895
   996
                case REL_X:
slouken@1895
   997
                case REL_Y:
slouken@1895
   998
                    code -= REL_X;
slouken@1895
   999
                    HandleBall(joystick, code / 2, code % 2, events[i].value);
slouken@1895
  1000
                    break;
slouken@1895
  1001
                default:
slouken@1895
  1002
                    break;
slouken@1895
  1003
                }
slouken@1895
  1004
                break;
slouken@6844
  1005
            case EV_SYN:
slouken@6844
  1006
                switch (code) {
slouken@6844
  1007
                case SYN_DROPPED :
slouken@6844
  1008
#ifdef DEBUG_INPUT_EVENTS
philipp@7133
  1009
                    printf("Event SYN_DROPPED detected\n");
slouken@6844
  1010
#endif
slouken@6844
  1011
                    PollAllValues(joystick);
slouken@6844
  1012
                    break;
slouken@6844
  1013
                default:
slouken@6844
  1014
                    break;
slouken@6844
  1015
                }
slouken@1895
  1016
            default:
slouken@1895
  1017
                break;
slouken@1895
  1018
            }
slouken@1895
  1019
        }
slouken@1895
  1020
    }
slouken@0
  1021
}
slouken@0
  1022
slouken@12088
  1023
static void
slouken@12088
  1024
LINUX_JoystickUpdate(SDL_Joystick * joystick)
slouken@0
  1025
{
slouken@1895
  1026
    int i;
slouken@1895
  1027
slouken@11532
  1028
    if (joystick->hwdata->m_bSteamController) {
slouken@11532
  1029
        SDL_UpdateSteamController(joystick);
slouken@11532
  1030
        return;
slouken@11532
  1031
    }
slouken@11532
  1032
icculus@6729
  1033
    HandleInputEvents(joystick);
slouken@0
  1034
slouken@1895
  1035
    /* Deliver ball motion updates */
slouken@1895
  1036
    for (i = 0; i < joystick->nballs; ++i) {
slouken@1895
  1037
        int xrel, yrel;
slouken@0
  1038
slouken@1895
  1039
        xrel = joystick->hwdata->balls[i].axis[0];
slouken@1895
  1040
        yrel = joystick->hwdata->balls[i].axis[1];
slouken@1895
  1041
        if (xrel || yrel) {
slouken@1895
  1042
            joystick->hwdata->balls[i].axis[0] = 0;
slouken@1895
  1043
            joystick->hwdata->balls[i].axis[1] = 0;
slouken@1895
  1044
            SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
slouken@1895
  1045
        }
slouken@1895
  1046
    }
slouken@0
  1047
}
slouken@0
  1048
slouken@0
  1049
/* Function to close a joystick after use */
slouken@12088
  1050
static void
slouken@12088
  1051
LINUX_JoystickClose(SDL_Joystick * joystick)
slouken@0
  1052
{
slouken@1895
  1053
    if (joystick->hwdata) {
slouken@12088
  1054
        if (joystick->hwdata->effect.id >= 0) {
slouken@12088
  1055
            ioctl(joystick->hwdata->fd, EVIOCRMFF, joystick->hwdata->effect.id);
slouken@12088
  1056
            joystick->hwdata->effect.id = -1;
slouken@12088
  1057
        }
slouken@11532
  1058
        if (joystick->hwdata->fd >= 0) {
slouken@11532
  1059
            close(joystick->hwdata->fd);
slouken@11532
  1060
        }
icculus@6752
  1061
        if (joystick->hwdata->item) {
icculus@6752
  1062
            joystick->hwdata->item->hwdata = NULL;
icculus@6752
  1063
        }
icculus@6734
  1064
        SDL_free(joystick->hwdata->hats);
icculus@6734
  1065
        SDL_free(joystick->hwdata->balls);
icculus@6734
  1066
        SDL_free(joystick->hwdata->fname);
slouken@1895
  1067
        SDL_free(joystick->hwdata);
slouken@1895
  1068
    }
slouken@0
  1069
}
slouken@0
  1070
slouken@0
  1071
/* Function to perform any system-specific joystick related cleanup */
slouken@12088
  1072
static void
slouken@12088
  1073
LINUX_JoystickQuit(void)
slouken@0
  1074
{
icculus@6734
  1075
    SDL_joylist_item *item = NULL;
icculus@6734
  1076
    SDL_joylist_item *next = NULL;
icculus@6734
  1077
icculus@6734
  1078
    for (item = SDL_joylist; item; item = next) {
icculus@6734
  1079
        next = item->next;
icculus@6734
  1080
        SDL_free(item->path);
icculus@6734
  1081
        SDL_free(item->name);
icculus@6734
  1082
        SDL_free(item);
icculus@6734
  1083
    }
icculus@6734
  1084
icculus@6734
  1085
    SDL_joylist = SDL_joylist_tail = NULL;
slouken@0
  1086
icculus@6734
  1087
    numjoysticks = 0;
icculus@6734
  1088
icculus@6734
  1089
#if SDL_USE_LIBUDEV
gabomdq@7772
  1090
    SDL_UDEV_DelCallback(joystick_udev_callback);
gabomdq@7772
  1091
    SDL_UDEV_Quit();
icculus@6734
  1092
#endif
slouken@11532
  1093
slouken@11532
  1094
    SDL_QuitSteamControllers();
slouken@0
  1095
}
slouken@0
  1096
slouken@12088
  1097
SDL_JoystickDriver SDL_LINUX_JoystickDriver =
slouken@6690
  1098
{
slouken@12088
  1099
    LINUX_JoystickInit,
slouken@12088
  1100
    LINUX_JoystickGetCount,
slouken@12088
  1101
    LINUX_JoystickDetect,
slouken@12088
  1102
    LINUX_JoystickGetDeviceName,
slouken@12088
  1103
    LINUX_JoystickGetDeviceGUID,
slouken@12088
  1104
    LINUX_JoystickGetDeviceInstanceID,
slouken@12088
  1105
    LINUX_JoystickOpen,
slouken@12088
  1106
    LINUX_JoystickRumble,
slouken@12088
  1107
    LINUX_JoystickUpdate,
slouken@12088
  1108
    LINUX_JoystickClose,
slouken@12088
  1109
    LINUX_JoystickQuit,
slouken@12088
  1110
};
slouken@6690
  1111
slouken@1635
  1112
#endif /* SDL_JOYSTICK_LINUX */
slouken@6693
  1113
slouken@1895
  1114
/* vi: set ts=4 sw=4 expandtab: */