cscg22-gearboy

CSCG 2022 Challenge 'Gearboy'
git clone https://git.sinitax.com/sinitax/cscg22-gearboy
Log | Files | Refs | sfeed.txt

SDL_sysjoystick.c (25195B)


      1/*
      2  Simple DirectMedia Layer
      3  Copyright (C) 1997-2014 Sam Lantinga <slouken@libsdl.org>
      4
      5  This software is provided 'as-is', without any express or implied
      6  warranty.  In no event will the authors be held liable for any damages
      7  arising from the use of this software.
      8
      9  Permission is granted to anyone to use this software for any purpose,
     10  including commercial applications, and to alter it and redistribute it
     11  freely, subject to the following restrictions:
     12
     13  1. The origin of this software must not be misrepresented; you must not
     14     claim that you wrote the original software. If you use this software
     15     in a product, an acknowledgment in the product documentation would be
     16     appreciated but is not required.
     17  2. Altered source versions must be plainly marked as such, and must not be
     18     misrepresented as being the original software.
     19  3. This notice may not be removed or altered from any source distribution.
     20*/
     21#include "../../SDL_internal.h"
     22
     23#ifdef SDL_JOYSTICK_LINUX
     24
     25#ifndef SDL_INPUT_LINUXEV
     26#error SDL now requires a Linux 2.4+ kernel with /dev/input/event support.
     27#endif
     28
     29/* This is the Linux implementation of the SDL joystick API */
     30
     31#include <sys/stat.h>
     32#include <unistd.h>
     33#include <fcntl.h>
     34#include <sys/ioctl.h>
     35#include <limits.h>             /* For the definition of PATH_MAX */
     36#include <linux/joystick.h>
     37
     38#include "SDL_assert.h"
     39#include "SDL_joystick.h"
     40#include "SDL_endian.h"
     41#include "../SDL_sysjoystick.h"
     42#include "../SDL_joystick_c.h"
     43#include "SDL_sysjoystick_c.h"
     44
     45/* !!! FIXME: move this somewhere else. */
     46#if !SDL_EVENTS_DISABLED
     47#include "../../events/SDL_events_c.h"
     48#endif
     49
     50/* This isn't defined in older Linux kernel headers */
     51#ifndef SYN_DROPPED
     52#define SYN_DROPPED 3
     53#endif
     54
     55#include "../../core/linux/SDL_udev.h"
     56
     57static int MaybeAddDevice(const char *path);
     58#if SDL_USE_LIBUDEV
     59static int MaybeRemoveDevice(const char *path);
     60void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath);
     61#endif /* SDL_USE_LIBUDEV */
     62
     63
     64/* A linked list of available joysticks */
     65typedef struct SDL_joylist_item
     66{
     67    int device_instance;
     68    char *path;   /* "/dev/input/event2" or whatever */
     69    char *name;   /* "SideWinder 3D Pro" or whatever */
     70    SDL_JoystickGUID guid;
     71    dev_t devnum;
     72    struct joystick_hwdata *hwdata;
     73    struct SDL_joylist_item *next;
     74} SDL_joylist_item;
     75
     76static SDL_joylist_item *SDL_joylist = NULL;
     77static SDL_joylist_item *SDL_joylist_tail = NULL;
     78static int numjoysticks = 0;
     79static int instance_counter = 0;
     80
     81#define test_bit(nr, addr) \
     82    (((1UL << ((nr) % (sizeof(long) * 8))) & ((addr)[(nr) / (sizeof(long) * 8)])) != 0)
     83#define NBITS(x) ((((x)-1)/(sizeof(long) * 8))+1)
     84
     85static int
     86IsJoystick(int fd, char *namebuf, const size_t namebuflen, SDL_JoystickGUID *guid)
     87{
     88    struct input_id inpid;
     89    Uint16 *guid16 = (Uint16 *) ((char *) &guid->data);
     90
     91#if !SDL_USE_LIBUDEV
     92    /* When udev is enabled we only get joystick devices here, so there's no need to test them */
     93    unsigned long evbit[NBITS(EV_MAX)] = { 0 };
     94    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
     95    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
     96
     97    if ((ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
     98        (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
     99        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0)) {
    100        return (0);
    101    }
    102
    103    if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
    104          test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit))) {
    105        return 0;
    106    }
    107#endif
    108
    109    if (ioctl(fd, EVIOCGNAME(namebuflen), namebuf) < 0) {
    110        return 0;
    111    }
    112
    113    if (ioctl(fd, EVIOCGID, &inpid) < 0) {
    114        return 0;
    115    }
    116
    117#ifdef DEBUG_JOYSTICK
    118    printf("Joystick: %s, bustype = %d, vendor = 0x%x, product = 0x%x, version = %d\n", namebuf, inpid.bustype, inpid.vendor, inpid.product, inpid.version);
    119#endif
    120
    121    SDL_memset(guid->data, 0, sizeof(guid->data));
    122
    123    /* We only need 16 bits for each of these; space them out to fill 128. */
    124    /* Byteswap so devices get same GUID on little/big endian platforms. */
    125    *(guid16++) = SDL_SwapLE16(inpid.bustype);
    126    *(guid16++) = 0;
    127
    128    if (inpid.vendor && inpid.product && inpid.version) {
    129        *(guid16++) = SDL_SwapLE16(inpid.vendor);
    130        *(guid16++) = 0;
    131        *(guid16++) = SDL_SwapLE16(inpid.product);
    132        *(guid16++) = 0;
    133        *(guid16++) = SDL_SwapLE16(inpid.version);
    134        *(guid16++) = 0;
    135    } else {
    136        SDL_strlcpy((char*)guid16, namebuf, sizeof(guid->data) - 4);
    137    }
    138
    139    return 1;
    140}
    141
    142#if SDL_USE_LIBUDEV
    143void joystick_udev_callback(SDL_UDEV_deviceevent udev_type, int udev_class, const char *devpath)
    144{
    145    if (devpath == NULL || !(udev_class & SDL_UDEV_DEVICE_JOYSTICK)) {
    146        return;
    147    }
    148    
    149    switch( udev_type )
    150    {
    151        case SDL_UDEV_DEVICEADDED:
    152            MaybeAddDevice(devpath);
    153            break;
    154            
    155        case SDL_UDEV_DEVICEREMOVED:
    156            MaybeRemoveDevice(devpath);
    157            break;
    158            
    159        default:
    160            break;
    161    }
    162    
    163}
    164#endif /* SDL_USE_LIBUDEV */
    165
    166
    167/* !!! FIXME: I would love to dump this code and use libudev instead. */
    168static int
    169MaybeAddDevice(const char *path)
    170{
    171    struct stat sb;
    172    int fd = -1;
    173    int isstick = 0;
    174    char namebuf[128];
    175    SDL_JoystickGUID guid;
    176    SDL_joylist_item *item;
    177#if !SDL_EVENTS_DISABLED
    178    SDL_Event event;
    179#endif
    180
    181    if (path == NULL) {
    182        return -1;
    183    }
    184
    185    if (stat(path, &sb) == -1) {
    186        return -1;
    187    }
    188
    189    /* Check to make sure it's not already in list. */
    190    for (item = SDL_joylist; item != NULL; item = item->next) {
    191        if (sb.st_rdev == item->devnum) {
    192            return -1;  /* already have this one */
    193        }
    194    }
    195
    196    fd = open(path, O_RDONLY, 0);
    197    if (fd < 0) {
    198        return -1;
    199    }
    200
    201#ifdef DEBUG_INPUT_EVENTS
    202    printf("Checking %s\n", path);
    203#endif
    204
    205    isstick = IsJoystick(fd, namebuf, sizeof (namebuf), &guid);
    206    close(fd);
    207    if (!isstick) {
    208        return -1;
    209    }
    210
    211    item = (SDL_joylist_item *) SDL_malloc(sizeof (SDL_joylist_item));
    212    if (item == NULL) {
    213        return -1;
    214    }
    215
    216    SDL_zerop(item);
    217    item->devnum = sb.st_rdev;
    218    item->path = SDL_strdup(path);
    219    item->name = SDL_strdup(namebuf);
    220    item->guid = guid;
    221
    222    if ( (item->path == NULL) || (item->name == NULL) ) {
    223         SDL_free(item->path);
    224         SDL_free(item->name);
    225         SDL_free(item);
    226         return -1;
    227    }
    228
    229    item->device_instance = instance_counter++;
    230    if (SDL_joylist_tail == NULL) {
    231        SDL_joylist = SDL_joylist_tail = item;
    232    } else {
    233        SDL_joylist_tail->next = item;
    234        SDL_joylist_tail = item;
    235    }
    236
    237    /* Need to increment the joystick count before we post the event */
    238    ++numjoysticks;
    239
    240    /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceAdded() function? */
    241#if !SDL_EVENTS_DISABLED
    242    event.type = SDL_JOYDEVICEADDED;
    243
    244    if (SDL_GetEventState(event.type) == SDL_ENABLE) {
    245        event.jdevice.which = (numjoysticks - 1);
    246        if ( (SDL_EventOK == NULL) ||
    247             (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
    248            SDL_PushEvent(&event);
    249        }
    250    }
    251#endif /* !SDL_EVENTS_DISABLED */
    252
    253    return numjoysticks;
    254}
    255
    256#if SDL_USE_LIBUDEV
    257/* !!! FIXME: I would love to dump this code and use libudev instead. */
    258static int
    259MaybeRemoveDevice(const char *path)
    260{
    261    SDL_joylist_item *item;
    262    SDL_joylist_item *prev = NULL;
    263#if !SDL_EVENTS_DISABLED
    264    SDL_Event event;
    265#endif
    266
    267    if (path == NULL) {
    268        return -1;
    269    }
    270
    271    for (item = SDL_joylist; item != NULL; item = item->next) {
    272        /* found it, remove it. */
    273        if (SDL_strcmp(path, item->path) == 0) {
    274            const int retval = item->device_instance;
    275            if (item->hwdata) {
    276                item->hwdata->item = NULL;
    277            }
    278            if (prev != NULL) {
    279                prev->next = item->next;
    280            } else {
    281                SDL_assert(SDL_joylist == item);
    282                SDL_joylist = item->next;
    283            }
    284            if (item == SDL_joylist_tail) {
    285                SDL_joylist_tail = prev;
    286            }
    287
    288            /* Need to decrement the joystick count before we post the event */
    289            --numjoysticks;
    290
    291            /* !!! FIXME: Move this to an SDL_PrivateJoyDeviceRemoved() function? */
    292#if !SDL_EVENTS_DISABLED
    293            event.type = SDL_JOYDEVICEREMOVED;
    294
    295            if (SDL_GetEventState(event.type) == SDL_ENABLE) {
    296                event.jdevice.which = item->device_instance;
    297                if ( (SDL_EventOK == NULL) ||
    298                     (*SDL_EventOK) (SDL_EventOKParam, &event) ) {
    299                    SDL_PushEvent(&event);
    300                }
    301            }
    302#endif /* !SDL_EVENTS_DISABLED */
    303
    304            SDL_free(item->path);
    305            SDL_free(item->name);
    306            SDL_free(item);
    307            return retval;
    308        }
    309        prev = item;
    310    }
    311
    312    return -1;
    313}
    314#endif
    315
    316static int
    317JoystickInitWithoutUdev(void)
    318{
    319    int i;
    320    char path[PATH_MAX];
    321
    322    /* !!! FIXME: only finds sticks if they're called /dev/input/event[0..31] */
    323    /* !!! FIXME:  we could at least readdir() through /dev/input...? */
    324    /* !!! FIXME:  (or delete this and rely on libudev?) */
    325    for (i = 0; i < 32; i++) {
    326        SDL_snprintf(path, SDL_arraysize(path), "/dev/input/event%d", i);
    327        MaybeAddDevice(path);
    328    }
    329
    330    return numjoysticks;
    331}
    332
    333
    334#if SDL_USE_LIBUDEV
    335static int
    336JoystickInitWithUdev(void)
    337{
    338
    339    if (SDL_UDEV_Init() < 0) {
    340        return SDL_SetError("Could not initialize UDEV");
    341    }
    342
    343    /* Set up the udev callback */
    344    if ( SDL_UDEV_AddCallback(joystick_udev_callback) < 0) {
    345        SDL_UDEV_Quit();
    346        return SDL_SetError("Could not set up joystick <-> udev callback");
    347    }
    348    
    349    /* Force a scan to build the initial device list */
    350    SDL_UDEV_Scan();
    351
    352    return numjoysticks;
    353}
    354#endif
    355
    356int
    357SDL_SYS_JoystickInit(void)
    358{
    359    /* First see if the user specified one or more joysticks to use */
    360    if (SDL_getenv("SDL_JOYSTICK_DEVICE") != NULL) {
    361        char *envcopy, *envpath, *delim;
    362        envcopy = SDL_strdup(SDL_getenv("SDL_JOYSTICK_DEVICE"));
    363        envpath = envcopy;
    364        while (envpath != NULL) {
    365            delim = SDL_strchr(envpath, ':');
    366            if (delim != NULL) {
    367                *delim++ = '\0';
    368            }
    369            MaybeAddDevice(envpath);
    370            envpath = delim;
    371        }
    372        SDL_free(envcopy);
    373    }
    374
    375#if SDL_USE_LIBUDEV
    376    return JoystickInitWithUdev();
    377#endif
    378
    379    return JoystickInitWithoutUdev();
    380}
    381
    382int SDL_SYS_NumJoysticks()
    383{
    384    return numjoysticks;
    385}
    386
    387void SDL_SYS_JoystickDetect()
    388{
    389#if SDL_USE_LIBUDEV
    390    SDL_UDEV_Poll();
    391#endif
    392    
    393}
    394
    395static SDL_joylist_item *
    396JoystickByDevIndex(int device_index)
    397{
    398    SDL_joylist_item *item = SDL_joylist;
    399
    400    if ((device_index < 0) || (device_index >= numjoysticks)) {
    401        return NULL;
    402    }
    403
    404    while (device_index > 0) {
    405        SDL_assert(item != NULL);
    406        device_index--;
    407        item = item->next;
    408    }
    409
    410    return item;
    411}
    412
    413/* Function to get the device-dependent name of a joystick */
    414const char *
    415SDL_SYS_JoystickNameForDeviceIndex(int device_index)
    416{
    417    return JoystickByDevIndex(device_index)->name;
    418}
    419
    420/* Function to perform the mapping from device index to the instance id for this index */
    421SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
    422{
    423    return JoystickByDevIndex(device_index)->device_instance;
    424}
    425
    426static int
    427allocate_hatdata(SDL_Joystick * joystick)
    428{
    429    int i;
    430
    431    joystick->hwdata->hats =
    432        (struct hwdata_hat *) SDL_malloc(joystick->nhats *
    433                                         sizeof(struct hwdata_hat));
    434    if (joystick->hwdata->hats == NULL) {
    435        return (-1);
    436    }
    437    for (i = 0; i < joystick->nhats; ++i) {
    438        joystick->hwdata->hats[i].axis[0] = 1;
    439        joystick->hwdata->hats[i].axis[1] = 1;
    440    }
    441    return (0);
    442}
    443
    444static int
    445allocate_balldata(SDL_Joystick * joystick)
    446{
    447    int i;
    448
    449    joystick->hwdata->balls =
    450        (struct hwdata_ball *) SDL_malloc(joystick->nballs *
    451                                          sizeof(struct hwdata_ball));
    452    if (joystick->hwdata->balls == NULL) {
    453        return (-1);
    454    }
    455    for (i = 0; i < joystick->nballs; ++i) {
    456        joystick->hwdata->balls[i].axis[0] = 0;
    457        joystick->hwdata->balls[i].axis[1] = 0;
    458    }
    459    return (0);
    460}
    461
    462static void
    463ConfigJoystick(SDL_Joystick * joystick, int fd)
    464{
    465    int i, t;
    466    unsigned long keybit[NBITS(KEY_MAX)] = { 0 };
    467    unsigned long absbit[NBITS(ABS_MAX)] = { 0 };
    468    unsigned long relbit[NBITS(REL_MAX)] = { 0 };
    469
    470    /* See if this device uses the new unified event API */
    471    if ((ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
    472        (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
    473        (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0)) {
    474
    475        /* Get the number of buttons, axes, and other thingamajigs */
    476        for (i = BTN_JOYSTICK; i < KEY_MAX; ++i) {
    477            if (test_bit(i, keybit)) {
    478#ifdef DEBUG_INPUT_EVENTS
    479                printf("Joystick has button: 0x%x\n", i);
    480#endif
    481                joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
    482                ++joystick->nbuttons;
    483            }
    484        }
    485        for (i = BTN_MISC; i < BTN_JOYSTICK; ++i) {
    486            if (test_bit(i, keybit)) {
    487#ifdef DEBUG_INPUT_EVENTS
    488                printf("Joystick has button: 0x%x\n", i);
    489#endif
    490                joystick->hwdata->key_map[i - BTN_MISC] = joystick->nbuttons;
    491                ++joystick->nbuttons;
    492            }
    493        }
    494        for (i = 0; i < ABS_MISC; ++i) {
    495            /* Skip hats */
    496            if (i == ABS_HAT0X) {
    497                i = ABS_HAT3Y;
    498                continue;
    499            }
    500            if (test_bit(i, absbit)) {
    501                struct input_absinfo absinfo;
    502
    503                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
    504                    continue;
    505                }
    506#ifdef DEBUG_INPUT_EVENTS
    507                printf("Joystick has absolute axis: 0x%.2x\n", i);
    508                printf("Values = { %d, %d, %d, %d, %d }\n",
    509                       absinfo.value, absinfo.minimum, absinfo.maximum,
    510                       absinfo.fuzz, absinfo.flat);
    511#endif /* DEBUG_INPUT_EVENTS */
    512                joystick->hwdata->abs_map[i] = joystick->naxes;
    513                if (absinfo.minimum == absinfo.maximum) {
    514                    joystick->hwdata->abs_correct[i].used = 0;
    515                } else {
    516                    joystick->hwdata->abs_correct[i].used = 1;
    517                    joystick->hwdata->abs_correct[i].coef[0] =
    518                        (absinfo.maximum + absinfo.minimum) - 2 * absinfo.flat;
    519                    joystick->hwdata->abs_correct[i].coef[1] =
    520                        (absinfo.maximum + absinfo.minimum) + 2 * absinfo.flat;
    521                    t = ((absinfo.maximum - absinfo.minimum) - 4 * absinfo.flat);
    522                    if (t != 0) {
    523                        joystick->hwdata->abs_correct[i].coef[2] =
    524                            (1 << 28) / t;
    525                    } else {
    526                        joystick->hwdata->abs_correct[i].coef[2] = 0;
    527                    }
    528                }
    529                ++joystick->naxes;
    530            }
    531        }
    532        for (i = ABS_HAT0X; i <= ABS_HAT3Y; i += 2) {
    533            if (test_bit(i, absbit) || test_bit(i + 1, absbit)) {
    534                struct input_absinfo absinfo;
    535
    536                if (ioctl(fd, EVIOCGABS(i), &absinfo) < 0) {
    537                    continue;
    538                }
    539#ifdef DEBUG_INPUT_EVENTS
    540                printf("Joystick has hat %d\n", (i - ABS_HAT0X) / 2);
    541                printf("Values = { %d, %d, %d, %d, %d }\n",
    542                       absinfo.value, absinfo.minimum, absinfo.maximum,
    543                       absinfo.fuzz, absinfo.flat);
    544#endif /* DEBUG_INPUT_EVENTS */
    545                ++joystick->nhats;
    546            }
    547        }
    548        if (test_bit(REL_X, relbit) || test_bit(REL_Y, relbit)) {
    549            ++joystick->nballs;
    550        }
    551
    552        /* Allocate data to keep track of these thingamajigs */
    553        if (joystick->nhats > 0) {
    554            if (allocate_hatdata(joystick) < 0) {
    555                joystick->nhats = 0;
    556            }
    557        }
    558        if (joystick->nballs > 0) {
    559            if (allocate_balldata(joystick) < 0) {
    560                joystick->nballs = 0;
    561            }
    562        }
    563    }
    564}
    565
    566
    567/* Function to open a joystick for use.
    568   The joystick to open is specified by the index field of the joystick.
    569   This should fill the nbuttons and naxes fields of the joystick structure.
    570   It returns 0, or -1 if there is an error.
    571 */
    572int
    573SDL_SYS_JoystickOpen(SDL_Joystick * joystick, int device_index)
    574{
    575    SDL_joylist_item *item = JoystickByDevIndex(device_index);
    576    char *fname = NULL;
    577    int fd = -1;
    578
    579    if (item == NULL) {
    580        return SDL_SetError("No such device");
    581    }
    582
    583    fname = item->path;
    584    fd = open(fname, O_RDONLY, 0);
    585    if (fd < 0) {
    586        return SDL_SetError("Unable to open %s", fname);
    587    }
    588
    589    joystick->instance_id = item->device_instance;
    590    joystick->hwdata = (struct joystick_hwdata *)
    591        SDL_malloc(sizeof(*joystick->hwdata));
    592    if (joystick->hwdata == NULL) {
    593        close(fd);
    594        return SDL_OutOfMemory();
    595    }
    596    SDL_memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
    597    joystick->hwdata->item = item;
    598    joystick->hwdata->guid = item->guid;
    599    joystick->hwdata->fd = fd;
    600    joystick->hwdata->fname = SDL_strdup(item->path);
    601    if (joystick->hwdata->fname == NULL) {
    602        SDL_free(joystick->hwdata);
    603        joystick->hwdata = NULL;
    604        close(fd);
    605        return SDL_OutOfMemory();
    606    }
    607
    608    SDL_assert(item->hwdata == NULL);
    609    item->hwdata = joystick->hwdata;
    610
    611    /* Set the joystick to non-blocking read mode */
    612    fcntl(fd, F_SETFL, O_NONBLOCK);
    613
    614    /* Get the number of buttons and axes on the joystick */
    615    ConfigJoystick(joystick, fd);
    616
    617    /* mark joystick as fresh and ready */
    618    joystick->hwdata->fresh = 1;
    619
    620    return (0);
    621}
    622
    623/* Function to determine is this joystick is attached to the system right now */
    624SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
    625{
    626    return !joystick->closed && (joystick->hwdata->item != NULL);
    627}
    628
    629static SDL_INLINE void
    630HandleHat(SDL_Joystick * stick, Uint8 hat, int axis, int value)
    631{
    632    struct hwdata_hat *the_hat;
    633    const Uint8 position_map[3][3] = {
    634        {SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP},
    635        {SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT},
    636        {SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN}
    637    };
    638
    639    the_hat = &stick->hwdata->hats[hat];
    640    if (value < 0) {
    641        value = 0;
    642    } else if (value == 0) {
    643        value = 1;
    644    } else if (value > 0) {
    645        value = 2;
    646    }
    647    if (value != the_hat->axis[axis]) {
    648        the_hat->axis[axis] = value;
    649        SDL_PrivateJoystickHat(stick, hat,
    650                               position_map[the_hat->
    651                                            axis[1]][the_hat->axis[0]]);
    652    }
    653}
    654
    655static SDL_INLINE void
    656HandleBall(SDL_Joystick * stick, Uint8 ball, int axis, int value)
    657{
    658    stick->hwdata->balls[ball].axis[axis] += value;
    659}
    660
    661
    662static SDL_INLINE int
    663AxisCorrect(SDL_Joystick * joystick, int which, int value)
    664{
    665    struct axis_correct *correct;
    666
    667    correct = &joystick->hwdata->abs_correct[which];
    668    if (correct->used) {
    669        value *= 2;
    670        if (value > correct->coef[0]) {
    671            if (value < correct->coef[1]) {
    672                return 0;
    673            }
    674            value -= correct->coef[1];
    675        } else {
    676            value -= correct->coef[0];
    677        }
    678        value *= correct->coef[2];
    679        value >>= 13;
    680    }
    681
    682    /* Clamp and return */
    683    if (value < -32768)
    684        return -32768;
    685    if (value > 32767)
    686        return 32767;
    687
    688    return value;
    689}
    690
    691static SDL_INLINE void
    692PollAllValues(SDL_Joystick * joystick)
    693{
    694    struct input_absinfo absinfo;
    695    int a, b = 0;
    696
    697    /* Poll all axis */
    698    for (a = ABS_X; b < ABS_MAX; a++) {
    699        switch (a) {
    700        case ABS_HAT0X:
    701        case ABS_HAT0Y:
    702        case ABS_HAT1X:
    703        case ABS_HAT1Y:
    704        case ABS_HAT2X:
    705        case ABS_HAT2Y:
    706        case ABS_HAT3X:
    707        case ABS_HAT3Y:
    708            /* ingore hats */
    709            break;
    710        default:
    711            if (joystick->hwdata->abs_correct[b].used) {
    712                if (ioctl(joystick->hwdata->fd, EVIOCGABS(a), &absinfo) >= 0) {
    713                    absinfo.value = AxisCorrect(joystick, b, absinfo.value);
    714
    715#ifdef DEBUG_INPUT_EVENTS
    716                    printf("Joystick : Re-read Axis %d (%d) val= %d\n",
    717                        joystick->hwdata->abs_map[b], a, absinfo.value);
    718#endif
    719                    SDL_PrivateJoystickAxis(joystick,
    720                            joystick->hwdata->abs_map[b],
    721                            absinfo.value);
    722                }
    723            }
    724            b++;
    725        }
    726    }
    727}
    728
    729static SDL_INLINE void
    730HandleInputEvents(SDL_Joystick * joystick)
    731{
    732    struct input_event events[32];
    733    int i, len;
    734    int code;
    735
    736    if (joystick->hwdata->fresh) {
    737        PollAllValues(joystick);
    738        joystick->hwdata->fresh = 0;
    739    }
    740
    741    while ((len = read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
    742        len /= sizeof(events[0]);
    743        for (i = 0; i < len; ++i) {
    744            code = events[i].code;
    745            switch (events[i].type) {
    746            case EV_KEY:
    747                if (code >= BTN_MISC) {
    748                    code -= BTN_MISC;
    749                    SDL_PrivateJoystickButton(joystick,
    750                                              joystick->hwdata->key_map[code],
    751                                              events[i].value);
    752                }
    753                break;
    754            case EV_ABS:
    755                if (code >= ABS_MISC) {
    756                    break;
    757                }
    758
    759                switch (code) {
    760                case ABS_HAT0X:
    761                case ABS_HAT0Y:
    762                case ABS_HAT1X:
    763                case ABS_HAT1Y:
    764                case ABS_HAT2X:
    765                case ABS_HAT2Y:
    766                case ABS_HAT3X:
    767                case ABS_HAT3Y:
    768                    code -= ABS_HAT0X;
    769                    HandleHat(joystick, code / 2, code % 2, events[i].value);
    770                    break;
    771                default:
    772                    events[i].value =
    773                        AxisCorrect(joystick, code, events[i].value);
    774                    SDL_PrivateJoystickAxis(joystick,
    775                                            joystick->hwdata->abs_map[code],
    776                                            events[i].value);
    777                    break;
    778                }
    779                break;
    780            case EV_REL:
    781                switch (code) {
    782                case REL_X:
    783                case REL_Y:
    784                    code -= REL_X;
    785                    HandleBall(joystick, code / 2, code % 2, events[i].value);
    786                    break;
    787                default:
    788                    break;
    789                }
    790                break;
    791            case EV_SYN:
    792                switch (code) {
    793                case SYN_DROPPED :
    794#ifdef DEBUG_INPUT_EVENTS
    795                    printf("Event SYN_DROPPED detected\n");
    796#endif
    797                    PollAllValues(joystick);
    798                    break;
    799                default:
    800                    break;
    801                }
    802            default:
    803                break;
    804            }
    805        }
    806    }
    807}
    808
    809void
    810SDL_SYS_JoystickUpdate(SDL_Joystick * joystick)
    811{
    812    int i;
    813
    814    HandleInputEvents(joystick);
    815
    816    /* Deliver ball motion updates */
    817    for (i = 0; i < joystick->nballs; ++i) {
    818        int xrel, yrel;
    819
    820        xrel = joystick->hwdata->balls[i].axis[0];
    821        yrel = joystick->hwdata->balls[i].axis[1];
    822        if (xrel || yrel) {
    823            joystick->hwdata->balls[i].axis[0] = 0;
    824            joystick->hwdata->balls[i].axis[1] = 0;
    825            SDL_PrivateJoystickBall(joystick, (Uint8) i, xrel, yrel);
    826        }
    827    }
    828}
    829
    830/* Function to close a joystick after use */
    831void
    832SDL_SYS_JoystickClose(SDL_Joystick * joystick)
    833{
    834    if (joystick->hwdata) {
    835        close(joystick->hwdata->fd);
    836        if (joystick->hwdata->item) {
    837            joystick->hwdata->item->hwdata = NULL;
    838        }
    839        SDL_free(joystick->hwdata->hats);
    840        SDL_free(joystick->hwdata->balls);
    841        SDL_free(joystick->hwdata->fname);
    842        SDL_free(joystick->hwdata);
    843        joystick->hwdata = NULL;
    844    }
    845    joystick->closed = 1;
    846}
    847
    848/* Function to perform any system-specific joystick related cleanup */
    849void
    850SDL_SYS_JoystickQuit(void)
    851{
    852    SDL_joylist_item *item = NULL;
    853    SDL_joylist_item *next = NULL;
    854
    855    for (item = SDL_joylist; item; item = next) {
    856        next = item->next;
    857        SDL_free(item->path);
    858        SDL_free(item->name);
    859        SDL_free(item);
    860    }
    861
    862    SDL_joylist = SDL_joylist_tail = NULL;
    863
    864    numjoysticks = 0;
    865    instance_counter = 0;
    866
    867#if SDL_USE_LIBUDEV
    868    SDL_UDEV_DelCallback(joystick_udev_callback);
    869    SDL_UDEV_Quit();
    870#endif
    871}
    872
    873SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
    874{
    875    return JoystickByDevIndex(device_index)->guid;
    876}
    877
    878SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
    879{
    880    return joystick->hwdata->guid;
    881}
    882
    883#endif /* SDL_JOYSTICK_LINUX */
    884
    885/* vi: set ts=4 sw=4 expandtab: */