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