src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Tue, 03 Jan 2017 23:39:28 -0800
changeset 10745 7461fcef6ae2
parent 10737 3406a0f8b041
child 11811 5d94cb6b24d3
permissions -rw-r--r--
Fixed binding the D-pad on some Super NES style controllers
Fixed a case where partial trigger pull could be bound to another button

There is a fundamental problem not resolved by this commit:

Some controllers have axes (triggers, pedals, etc.) that don't start at zero, but we're guaranteed that if we get a value that it's correct. For these controllers, the current code works, where we take the first value we get and use that as the zero point and generate axis motion starting from that point on.

Other controllers have digital axes (D-pad) that assume a zero starting point, and the first value we get is the min or max axis value when the D-pad is moved. For these controllers, the current code thinks that the zero point is the axis value after the D-pad motion and this doesn't work.

My hypothesis is that the first class of devices is more common and that we should solve for that, and add an exception to SDL_JoystickAxesCenteredAtZero() as needed for the second class of devices.
slouken@278
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@10737
     3
  Copyright (C) 1997-2017 Sam Lantinga <slouken@libsdl.org>
slouken@278
     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@278
     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@278
    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@278
    20
*/
icculus@8093
    21
#include "../../SDL_internal.h"
slouken@278
    22
slouken@1635
    23
#ifdef SDL_JOYSTICK_USBHID
slouken@1635
    24
slouken@278
    25
/*
slouken@278
    26
 * Joystick driver for the uhid(4) interface found in OpenBSD,
slouken@278
    27
 * NetBSD and FreeBSD.
slouken@278
    28
 *
slouken@278
    29
 * Maintainer: <vedge at csoft.org>
slouken@278
    30
 */
slouken@278
    31
slouken@552
    32
#include <sys/param.h>
slouken@552
    33
slouken@278
    34
#include <unistd.h>
slouken@278
    35
#include <fcntl.h>
slouken@278
    36
#include <errno.h>
slouken@278
    37
slouken@3367
    38
#ifndef __FreeBSD_kernel_version
slouken@3367
    39
#define __FreeBSD_kernel_version __FreeBSD_version
slouken@3367
    40
#endif
slouken@3367
    41
slouken@403
    42
#if defined(HAVE_USB_H)
slouken@403
    43
#include <usb.h>
slouken@403
    44
#endif
slouken@1565
    45
#ifdef __DragonFly__
slouken@1565
    46
#include <bus/usb/usb.h>
slouken@1565
    47
#include <bus/usb/usbhid.h>
slouken@1565
    48
#else
slouken@278
    49
#include <dev/usb/usb.h>
slouken@278
    50
#include <dev/usb/usbhid.h>
slouken@1565
    51
#endif
slouken@358
    52
slouken@381
    53
#if defined(HAVE_USBHID_H)
slouken@381
    54
#include <usbhid.h>
slouken@381
    55
#elif defined(HAVE_LIBUSB_H)
slouken@381
    56
#include <libusb.h>
slouken@381
    57
#elif defined(HAVE_LIBUSBHID_H)
slouken@381
    58
#include <libusbhid.h>
slouken@358
    59
#endif
slouken@278
    60
slouken@4944
    61
#if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
slouken@1565
    62
#ifndef __DragonFly__
slouken@611
    63
#include <osreldate.h>
slouken@1565
    64
#endif
icculus@6080
    65
#if __FreeBSD_kernel_version > 800063
icculus@6080
    66
#include <dev/usb/usb_ioctl.h>
icculus@6080
    67
#endif
slouken@776
    68
#include <sys/joystick.h>
slouken@776
    69
#endif
slouken@776
    70
slouken@1565
    71
#if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
slouken@776
    72
#include <machine/joystick.h>
slouken@611
    73
#endif
slouken@611
    74
slouken@278
    75
#include "SDL_joystick.h"
slouken@1361
    76
#include "../SDL_sysjoystick.h"
slouken@1361
    77
#include "../SDL_joystick_c.h"
slouken@278
    78
icculus@9986
    79
#define MAX_UHID_JOYS   64
slouken@7191
    80
#define MAX_JOY_JOYS    2
slouken@7191
    81
#define MAX_JOYS    (MAX_UHID_JOYS + MAX_JOY_JOYS)
slouken@278
    82
slouken@3385
    83
slouken@1895
    84
struct report
slouken@1895
    85
{
slouken@6963
    86
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
slouken@6963
    87
    void *buf; /* Buffer */
slouken@6963
    88
#elif defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
icculus@6080
    89
    struct usb_gen_descriptor *buf; /* Buffer */
icculus@6080
    90
#else
slouken@1895
    91
    struct usb_ctl_report *buf; /* Buffer */
icculus@6080
    92
#endif
slouken@1895
    93
    size_t size;                /* Buffer size */
slouken@1895
    94
    int rid;                    /* Report ID */
slouken@1895
    95
    enum
slouken@1895
    96
    {
slouken@1895
    97
        SREPORT_UNINIT,
slouken@1895
    98
        SREPORT_CLEAN,
slouken@1895
    99
        SREPORT_DIRTY
slouken@1895
   100
    } status;
slouken@278
   101
};
slouken@278
   102
slouken@1895
   103
static struct
slouken@1895
   104
{
slouken@1895
   105
    int uhid_report;
slouken@1895
   106
    hid_kind_t kind;
slouken@1895
   107
    const char *name;
slouken@278
   108
} const repinfo[] = {
slouken@1895
   109
    {UHID_INPUT_REPORT, hid_input, "input"},
slouken@1895
   110
    {UHID_OUTPUT_REPORT, hid_output, "output"},
slouken@1895
   111
    {UHID_FEATURE_REPORT, hid_feature, "feature"}
slouken@278
   112
};
slouken@307
   113
slouken@1895
   114
enum
slouken@1895
   115
{
slouken@1895
   116
    REPORT_INPUT = 0,
slouken@1895
   117
    REPORT_OUTPUT = 1,
slouken@1895
   118
    REPORT_FEATURE = 2
slouken@307
   119
};
slouken@307
   120
slouken@1895
   121
enum
slouken@1895
   122
{
slouken@1895
   123
    JOYAXE_X,
slouken@1895
   124
    JOYAXE_Y,
slouken@1895
   125
    JOYAXE_Z,
slouken@1895
   126
    JOYAXE_SLIDER,
slouken@1895
   127
    JOYAXE_WHEEL,
slouken@1895
   128
    JOYAXE_RX,
slouken@1895
   129
    JOYAXE_RY,
slouken@1895
   130
    JOYAXE_RZ,
slouken@1895
   131
    JOYAXE_count
slouken@307
   132
};
slouken@278
   133
slouken@1895
   134
struct joystick_hwdata
slouken@1895
   135
{
slouken@1895
   136
    int fd;
slouken@1895
   137
    char *path;
slouken@1895
   138
    enum
slouken@1895
   139
    {
slouken@1895
   140
        BSDJOY_UHID,            /* uhid(4) */
slouken@1895
   141
        BSDJOY_JOY              /* joy(4) */
slouken@1895
   142
    } type;
slouken@1895
   143
    struct report_desc *repdesc;
slouken@1895
   144
    struct report inreport;
slouken@1895
   145
    int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
slouken@278
   146
};
slouken@278
   147
slouken@278
   148
static char *joynames[MAX_JOYS];
slouken@278
   149
static char *joydevnames[MAX_JOYS];
slouken@278
   150
slouken@1895
   151
static int report_alloc(struct report *, struct report_desc *, int);
slouken@1895
   152
static void report_free(struct report *);
slouken@278
   153
slouken@6963
   154
#if defined(USBHID_UCR_DATA) || (defined(__FreeBSD_kernel__) && __FreeBSD_kernel_version <= 800063)
slouken@381
   155
#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
slouken@6963
   156
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000))
slouken@6963
   157
#define REP_BUF_DATA(rep) ((rep)->buf)
icculus@6080
   158
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
icculus@6080
   159
#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
slouken@381
   160
#else
slouken@381
   161
#define REP_BUF_DATA(rep) ((rep)->buf->data)
slouken@381
   162
#endif
slouken@381
   163
slouken@6707
   164
static int SDL_SYS_numjoysticks = 0;
slouken@6697
   165
slouken@278
   166
int
slouken@278
   167
SDL_SYS_JoystickInit(void)
slouken@278
   168
{
slouken@1895
   169
    char s[16];
slouken@1895
   170
    int i, fd;
slouken@278
   171
slouken@6697
   172
    SDL_SYS_numjoysticks = 0;
slouken@278
   173
slouken@1895
   174
    SDL_memset(joynames, 0, sizeof(joynames));
slouken@1895
   175
    SDL_memset(joydevnames, 0, sizeof(joydevnames));
slouken@278
   176
slouken@1895
   177
    for (i = 0; i < MAX_UHID_JOYS; i++) {
slouken@1895
   178
        SDL_Joystick nj;
slouken@544
   179
slouken@1895
   180
        SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
slouken@544
   181
philipp@10187
   182
        joynames[SDL_SYS_numjoysticks] = SDL_strdup(s);
slouken@544
   183
slouken@6700
   184
        if (SDL_SYS_JoystickOpen(&nj, SDL_SYS_numjoysticks) == 0) {
slouken@1895
   185
            SDL_SYS_JoystickClose(&nj);
slouken@6697
   186
            SDL_SYS_numjoysticks++;
slouken@1895
   187
        } else {
slouken@6700
   188
            SDL_free(joynames[SDL_SYS_numjoysticks]);
slouken@6700
   189
            joynames[SDL_SYS_numjoysticks] = NULL;
slouken@1895
   190
        }
slouken@1895
   191
    }
slouken@1895
   192
    for (i = 0; i < MAX_JOY_JOYS; i++) {
slouken@1895
   193
        SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
slouken@1895
   194
        fd = open(s, O_RDONLY);
slouken@1895
   195
        if (fd != -1) {
philipp@10187
   196
            joynames[SDL_SYS_numjoysticks++] = SDL_strdup(s);
slouken@1895
   197
            close(fd);
slouken@1895
   198
        }
slouken@1895
   199
    }
slouken@278
   200
slouken@1895
   201
    /* Read the default USB HID usage table. */
slouken@1895
   202
    hid_init(NULL);
slouken@278
   203
slouken@6697
   204
    return (SDL_SYS_numjoysticks);
slouken@278
   205
}
slouken@278
   206
philipp@10617
   207
int
philipp@10617
   208
SDL_SYS_NumJoysticks(void)
slouken@6707
   209
{
slouken@6707
   210
    return SDL_SYS_numjoysticks;
slouken@6707
   211
}
slouken@6707
   212
philipp@10617
   213
void
philipp@10617
   214
SDL_SYS_JoystickDetect(void)
slouken@6707
   215
{
slouken@6707
   216
}
slouken@6707
   217
slouken@278
   218
const char *
slouken@6707
   219
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@278
   220
{
slouken@6707
   221
    if (joydevnames[device_index] != NULL) {
slouken@6707
   222
        return (joydevnames[device_index]);
slouken@1895
   223
    }
slouken@6707
   224
    return (joynames[device_index]);
slouken@6707
   225
}
slouken@6707
   226
slouken@6707
   227
/* Function to perform the mapping from device index to the instance id for this index */
slouken@6707
   228
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   229
{
slouken@6707
   230
    return device_index;
slouken@278
   231
}
slouken@278
   232
slouken@632
   233
static int
slouken@632
   234
usage_to_joyaxe(unsigned usage)
slouken@632
   235
{
slouken@632
   236
    int joyaxe;
slouken@632
   237
    switch (usage) {
slouken@632
   238
    case HUG_X:
slouken@1895
   239
        joyaxe = JOYAXE_X;
slouken@1895
   240
        break;
slouken@632
   241
    case HUG_Y:
slouken@1895
   242
        joyaxe = JOYAXE_Y;
slouken@1895
   243
        break;
slouken@632
   244
    case HUG_Z:
slouken@1895
   245
        joyaxe = JOYAXE_Z;
slouken@1895
   246
        break;
slouken@632
   247
    case HUG_SLIDER:
slouken@1895
   248
        joyaxe = JOYAXE_SLIDER;
slouken@1895
   249
        break;
slouken@632
   250
    case HUG_WHEEL:
slouken@1895
   251
        joyaxe = JOYAXE_WHEEL;
slouken@1895
   252
        break;
slouken@632
   253
    case HUG_RX:
slouken@1895
   254
        joyaxe = JOYAXE_RX;
slouken@1895
   255
        break;
slouken@632
   256
    case HUG_RY:
slouken@1895
   257
        joyaxe = JOYAXE_RY;
slouken@1895
   258
        break;
slouken@632
   259
    case HUG_RZ:
slouken@1895
   260
        joyaxe = JOYAXE_RZ;
slouken@1895
   261
        break;
slouken@632
   262
    default:
slouken@1895
   263
        joyaxe = -1;
slouken@632
   264
    }
slouken@1895
   265
    return joyaxe;
slouken@632
   266
}
slouken@632
   267
slouken@632
   268
static unsigned
slouken@632
   269
hatval_to_sdl(Sint32 hatval)
slouken@632
   270
{
slouken@632
   271
    static const unsigned hat_dir_map[8] = {
slouken@1895
   272
        SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
slouken@1895
   273
        SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
slouken@632
   274
    };
slouken@632
   275
    unsigned result;
slouken@1895
   276
    if ((hatval & 7) == hatval)
slouken@1895
   277
        result = hat_dir_map[hatval];
slouken@1895
   278
    else
slouken@1895
   279
        result = SDL_HAT_CENTERED;
slouken@632
   280
    return result;
slouken@632
   281
}
slouken@632
   282
slouken@632
   283
slouken@278
   284
int
slouken@6697
   285
SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
slouken@278
   286
{
slouken@6697
   287
    char *path = joynames[device_index];
slouken@1895
   288
    struct joystick_hwdata *hw;
slouken@1895
   289
    struct hid_item hitem;
slouken@1895
   290
    struct hid_data *hdata;
icculus@9986
   291
    struct report *rep = NULL;
slouken@1895
   292
    int fd;
slouken@1895
   293
    int i;
slouken@278
   294
slouken@1895
   295
    fd = open(path, O_RDONLY);
slouken@1895
   296
    if (fd == -1) {
icculus@7037
   297
        return SDL_SetError("%s: %s", path, strerror(errno));
slouken@1895
   298
    }
slouken@278
   299
slouken@6698
   300
    joy->instance_id = device_index;
slouken@1895
   301
    hw = (struct joystick_hwdata *)
slouken@1895
   302
        SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   303
    if (hw == NULL) {
slouken@1895
   304
        close(fd);
icculus@7037
   305
        return SDL_OutOfMemory();
slouken@1895
   306
    }
slouken@1895
   307
    joy->hwdata = hw;
slouken@1895
   308
    hw->fd = fd;
philipp@10187
   309
    hw->path = SDL_strdup(path);
slouken@1895
   310
    if (!SDL_strncmp(path, "/dev/joy", 8)) {
slouken@1895
   311
        hw->type = BSDJOY_JOY;
slouken@1895
   312
        joy->naxes = 2;
slouken@1895
   313
        joy->nbuttons = 2;
slouken@1895
   314
        joy->nhats = 0;
slouken@1895
   315
        joy->nballs = 0;
philipp@10187
   316
        joydevnames[device_index] = SDL_strdup("Gameport joystick");
slouken@1895
   317
        goto usbend;
slouken@1895
   318
    } else {
slouken@1895
   319
        hw->type = BSDJOY_UHID;
slouken@1895
   320
    }
slouken@776
   321
slouken@1895
   322
    {
slouken@1895
   323
        int ax;
slouken@1895
   324
        for (ax = 0; ax < JOYAXE_count; ax++)
slouken@1895
   325
            hw->axis_map[ax] = -1;
slouken@1895
   326
    }
slouken@1895
   327
    hw->repdesc = hid_get_report_desc(fd);
slouken@1895
   328
    if (hw->repdesc == NULL) {
slouken@1895
   329
        SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
slouken@1895
   330
                     strerror(errno));
slouken@1895
   331
        goto usberr;
slouken@1895
   332
    }
icculus@3703
   333
    rep = &hw->inreport;
slouken@4537
   334
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
slouken@3385
   335
    rep->rid = hid_get_report_id(fd);
slouken@3385
   336
    if (rep->rid < 0) {
slouken@3385
   337
#else
slouken@1895
   338
    if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
slouken@3385
   339
#endif
slouken@1895
   340
        rep->rid = -1;          /* XXX */
slouken@1895
   341
    }
icculus@9986
   342
#if defined(__NetBSD__)
icculus@9986
   343
    usb_device_descriptor_t udd;
icculus@9986
   344
    struct usb_string_desc usd;
icculus@9986
   345
    if (ioctl(fd, USB_GET_DEVICE_DESC, &udd) == -1)
icculus@9986
   346
        goto desc_failed;
icculus@9986
   347
icculus@9986
   348
    /* Get default language */
icculus@9986
   349
    usd.usd_string_index = USB_LANGUAGE_TABLE;
icculus@9986
   350
    usd.usd_language_id = 0;
icculus@9986
   351
    if (ioctl(fd, USB_GET_STRING_DESC, &usd) == -1 || usd.usd_desc.bLength < 4) {
icculus@9986
   352
        usd.usd_language_id = 0;
icculus@9986
   353
    } else {
icculus@9986
   354
        usd.usd_language_id = UGETW(usd.usd_desc.bString[0]);
icculus@9986
   355
    }
icculus@9986
   356
icculus@9986
   357
    usd.usd_string_index = udd.iProduct;
icculus@9986
   358
    if (ioctl(fd, USB_GET_STRING_DESC, &usd) == 0) {
icculus@9986
   359
        char str[128];
icculus@9986
   360
        char *new_name = NULL;
icculus@9986
   361
        int i;
icculus@9986
   362
        for (i = 0; i < (usd.usd_desc.bLength >> 1) - 1 && i < sizeof(str) - 1; i++) {
icculus@9986
   363
            str[i] = UGETW(usd.usd_desc.bString[i]);
icculus@9986
   364
        }
icculus@9986
   365
        str[i] = '\0';
icculus@9986
   366
        asprintf(&new_name, "%s @ %s", str, path);
icculus@9986
   367
        if (new_name != NULL) {
philipp@10187
   368
            SDL_free(joydevnames[SDL_SYS_numjoysticks]);
icculus@9986
   369
            joydevnames[SDL_SYS_numjoysticks] = new_name;
icculus@9986
   370
        }
icculus@9986
   371
    }
icculus@9986
   372
desc_failed:
icculus@9986
   373
#endif
slouken@1895
   374
    if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
slouken@1895
   375
        goto usberr;
slouken@1895
   376
    }
slouken@1895
   377
    if (rep->size <= 0) {
slouken@1895
   378
        SDL_SetError("%s: Input report descriptor has invalid length",
slouken@1895
   379
                     hw->path);
slouken@1895
   380
        goto usberr;
slouken@1895
   381
    }
slouken@4537
   382
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@1895
   383
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
slouken@1895
   384
#else
slouken@1895
   385
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
slouken@1895
   386
#endif
slouken@1895
   387
    if (hdata == NULL) {
slouken@1895
   388
        SDL_SetError("%s: Cannot start HID parser", hw->path);
slouken@1895
   389
        goto usberr;
slouken@1895
   390
    }
slouken@1895
   391
    joy->naxes = 0;
slouken@1895
   392
    joy->nbuttons = 0;
slouken@1895
   393
    joy->nhats = 0;
slouken@1895
   394
    joy->nballs = 0;
slouken@1895
   395
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   396
        hw->axis_map[i] = -1;
slouken@278
   397
slouken@1895
   398
    while (hid_get_item(hdata, &hitem) > 0) {
slouken@1895
   399
        char *sp;
slouken@1895
   400
        const char *s;
slouken@278
   401
slouken@1895
   402
        switch (hitem.kind) {
slouken@1895
   403
        case hid_collection:
slouken@1895
   404
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   405
            case HUP_GENERIC_DESKTOP:
slouken@1895
   406
                switch (HID_USAGE(hitem.usage)) {
slouken@1895
   407
                case HUG_JOYSTICK:
slouken@1895
   408
                case HUG_GAME_PAD:
slouken@1895
   409
                    s = hid_usage_in_page(hitem.usage);
slouken@1895
   410
                    sp = SDL_malloc(SDL_strlen(s) + 5);
slouken@1895
   411
                    SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
slouken@6700
   412
                                 s, device_index);
slouken@6700
   413
                    joydevnames[device_index] = sp;
slouken@1895
   414
                }
slouken@1895
   415
            }
slouken@1895
   416
            break;
slouken@1895
   417
        case hid_input:
slouken@1895
   418
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   419
            case HUP_GENERIC_DESKTOP:
slouken@1895
   420
                {
slouken@1895
   421
                    unsigned usage = HID_USAGE(hitem.usage);
slouken@1895
   422
                    int joyaxe = usage_to_joyaxe(usage);
slouken@1895
   423
                    if (joyaxe >= 0) {
slouken@1895
   424
                        hw->axis_map[joyaxe] = 1;
slouken@1895
   425
                    } else if (usage == HUG_HAT_SWITCH) {
slouken@1895
   426
                        joy->nhats++;
slouken@1895
   427
                    }
slouken@1895
   428
                    break;
slouken@1895
   429
                }
slouken@1895
   430
            case HUP_BUTTON:
slouken@1895
   431
                joy->nbuttons++;
slouken@1895
   432
                break;
slouken@1895
   433
            default:
slouken@1895
   434
                break;
slouken@1895
   435
            }
slouken@1895
   436
            break;
slouken@1895
   437
        default:
slouken@1895
   438
            break;
slouken@1895
   439
        }
slouken@1895
   440
    }
slouken@1895
   441
    hid_end_parse(hdata);
slouken@1895
   442
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   443
        if (hw->axis_map[i] > 0)
slouken@1895
   444
            hw->axis_map[i] = joy->naxes++;
slouken@278
   445
icculus@9986
   446
    if (joy->naxes == 0 && joy->nbuttons == 0 && joy->nhats == 0 && joy->nballs == 0) {
icculus@9986
   447
        SDL_SetError("%s: Not a joystick, ignoring", hw->path);
icculus@9986
   448
        goto usberr;
icculus@9986
   449
    }
icculus@9986
   450
slouken@1895
   451
  usbend:
slouken@1895
   452
    /* The poll blocks the event thread. */
slouken@1895
   453
    fcntl(fd, F_SETFL, O_NONBLOCK);
icculus@9986
   454
#ifdef __NetBSD__
icculus@9986
   455
    /* Flush pending events */
icculus@9986
   456
    if (rep) {
icculus@9986
   457
        while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size)
icculus@9986
   458
            ;
icculus@9986
   459
    }
icculus@9986
   460
#endif
slouken@278
   461
slouken@1895
   462
    return (0);
slouken@1895
   463
  usberr:
slouken@1895
   464
    close(hw->fd);
slouken@1895
   465
    SDL_free(hw->path);
slouken@1895
   466
    SDL_free(hw);
slouken@1895
   467
    return (-1);
slouken@278
   468
}
slouken@278
   469
philipp@9561
   470
/* Function to determine if this joystick is attached to the system right now */
slouken@6707
   471
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
slouken@6707
   472
{
slouken@6707
   473
    return SDL_TRUE;
slouken@6707
   474
}
slouken@6707
   475
slouken@278
   476
void
slouken@1895
   477
SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
slouken@278
   478
{
slouken@1895
   479
    struct hid_item hitem;
slouken@1895
   480
    struct hid_data *hdata;
slouken@1895
   481
    struct report *rep;
slouken@1895
   482
    int nbutton, naxe = -1;
slouken@1895
   483
    Sint32 v;
slouken@776
   484
slouken@4537
   485
#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
slouken@1895
   486
    struct joystick gameport;
slouken@1895
   487
    static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
slouken@1895
   488
slouken@1895
   489
    if (joy->hwdata->type == BSDJOY_JOY) {
slouken@7733
   490
        while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
slouken@7733
   491
            if (abs(x - gameport.x) > 8) {
slouken@7733
   492
                x = gameport.x;
slouken@7733
   493
                if (x < xmin) {
slouken@7733
   494
                    xmin = x;
slouken@7733
   495
                }
slouken@7733
   496
                if (x > xmax) {
slouken@7733
   497
                    xmax = x;
slouken@7733
   498
                }
slouken@7733
   499
                if (xmin == xmax) {
slouken@7733
   500
                    xmin--;
slouken@7733
   501
                    xmax++;
slouken@7733
   502
                }
slouken@7733
   503
                v = (Sint32) x;
slouken@7733
   504
                v -= (xmax + xmin + 1) / 2;
slouken@7733
   505
                v *= 32768 / ((xmax - xmin + 1) / 2);
slouken@7733
   506
                SDL_PrivateJoystickAxis(joy, 0, v);
slouken@1895
   507
            }
slouken@7733
   508
            if (abs(y - gameport.y) > 8) {
slouken@7733
   509
                y = gameport.y;
slouken@7733
   510
                if (y < ymin) {
slouken@7733
   511
                    ymin = y;
slouken@7733
   512
                }
slouken@7733
   513
                if (y > ymax) {
slouken@7733
   514
                    ymax = y;
slouken@7733
   515
                }
slouken@7733
   516
                if (ymin == ymax) {
slouken@7733
   517
                    ymin--;
slouken@7733
   518
                    ymax++;
slouken@7733
   519
                }
slouken@7733
   520
                v = (Sint32) y;
slouken@7733
   521
                v -= (ymax + ymin + 1) / 2;
slouken@7733
   522
                v *= 32768 / ((ymax - ymin + 1) / 2);
slouken@7733
   523
                SDL_PrivateJoystickAxis(joy, 1, v);
slouken@1895
   524
            }
slouken@10745
   525
            SDL_PrivateJoystickButton(joy, 0, gameport.b1);
slouken@10745
   526
            SDL_PrivateJoystickButton(joy, 1, gameport.b2);
slouken@1895
   527
        }
slouken@1895
   528
        return;
slouken@1895
   529
    }
slouken@1565
   530
#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
slouken@381
   531
slouken@1895
   532
    rep = &joy->hwdata->inreport;
slouken@1895
   533
slouken@7733
   534
    while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
slouken@4537
   535
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@7733
   536
        hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
slouken@407
   537
#else
slouken@7733
   538
        hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
slouken@407
   539
#endif
slouken@7733
   540
        if (hdata == NULL) {
slouken@7733
   541
            /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
slouken@7733
   542
            continue;
slouken@7733
   543
        }
slouken@278
   544
slouken@7733
   545
        for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
slouken@7733
   546
            switch (hitem.kind) {
slouken@7733
   547
            case hid_input:
slouken@7733
   548
                switch (HID_PAGE(hitem.usage)) {
slouken@7733
   549
                case HUP_GENERIC_DESKTOP:
slouken@7733
   550
                    {
slouken@7733
   551
                        unsigned usage = HID_USAGE(hitem.usage);
slouken@7733
   552
                        int joyaxe = usage_to_joyaxe(usage);
slouken@7733
   553
                        if (joyaxe >= 0) {
slouken@7733
   554
                            naxe = joy->hwdata->axis_map[joyaxe];
slouken@7733
   555
                            /* scaleaxe */
slouken@7733
   556
                            v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@7733
   557
                            v -= (hitem.logical_maximum +
slouken@7733
   558
                                  hitem.logical_minimum + 1) / 2;
slouken@7733
   559
                            v *= 32768 /
slouken@7733
   560
                                ((hitem.logical_maximum -
slouken@7733
   561
                                  hitem.logical_minimum + 1) / 2);
slouken@10745
   562
                            SDL_PrivateJoystickAxis(joy, naxe, v);
slouken@7733
   563
                        } else if (usage == HUG_HAT_SWITCH) {
slouken@7733
   564
                            v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@7733
   565
                            SDL_PrivateJoystickHat(joy, 0,
slouken@7733
   566
                                                   hatval_to_sdl(v) -
slouken@7733
   567
                                                   hitem.logical_minimum);
slouken@1895
   568
                        }
slouken@7733
   569
                        break;
slouken@1895
   570
                    }
slouken@7733
   571
                case HUP_BUTTON:
slouken@7733
   572
                    v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@10745
   573
                    SDL_PrivateJoystickButton(joy, nbutton, v);
slouken@7733
   574
                    nbutton++;
slouken@1895
   575
                    break;
slouken@7733
   576
                default:
slouken@7733
   577
                    continue;
slouken@1895
   578
                }
slouken@1895
   579
                break;
slouken@1895
   580
            default:
slouken@7733
   581
                break;
slouken@1895
   582
            }
slouken@1895
   583
        }
slouken@7733
   584
        hid_end_parse(hdata);
slouken@1895
   585
    }
slouken@278
   586
}
slouken@278
   587
slouken@278
   588
/* Function to close a joystick after use */
slouken@278
   589
void
slouken@1895
   590
SDL_SYS_JoystickClose(SDL_Joystick * joy)
slouken@278
   591
{
slouken@1895
   592
    if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
slouken@1895
   593
        report_free(&joy->hwdata->inreport);
slouken@1895
   594
        hid_dispose_report_desc(joy->hwdata->repdesc);
slouken@1895
   595
    }
slouken@1895
   596
    close(joy->hwdata->fd);
slouken@1895
   597
    SDL_free(joy->hwdata->path);
slouken@1895
   598
    SDL_free(joy->hwdata);
slouken@278
   599
}
slouken@278
   600
slouken@278
   601
void
slouken@278
   602
SDL_SYS_JoystickQuit(void)
slouken@278
   603
{
slouken@1895
   604
    int i;
slouken@278
   605
slouken@1895
   606
    for (i = 0; i < MAX_JOYS; i++) {
slouken@7719
   607
        SDL_free(joynames[i]);
slouken@7719
   608
        SDL_free(joydevnames[i]);
slouken@1895
   609
    }
slouken@278
   610
slouken@1895
   611
    return;
slouken@278
   612
}
slouken@278
   613
slouken@6744
   614
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6697
   615
{
slouken@6744
   616
    SDL_JoystickGUID guid;
slouken@7191
   617
    /* the GUID is just the first 16 chars of the name for now */
slouken@6707
   618
    const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
slouken@6697
   619
    SDL_zero( guid );
slouken@6697
   620
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6697
   621
    return guid;
slouken@6697
   622
}
slouken@6697
   623
slouken@6744
   624
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6697
   625
{
slouken@6744
   626
    SDL_JoystickGUID guid;
slouken@7191
   627
    /* the GUID is just the first 16 chars of the name for now */
slouken@6697
   628
    const char *name = joystick->name;
slouken@6697
   629
    SDL_zero( guid );
slouken@6697
   630
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6697
   631
    return guid;
slouken@6697
   632
}
slouken@6697
   633
slouken@278
   634
static int
slouken@278
   635
report_alloc(struct report *r, struct report_desc *rd, int repind)
slouken@278
   636
{
slouken@1895
   637
    int len;
slouken@278
   638
slouken@1565
   639
#ifdef __DragonFly__
slouken@1895
   640
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@1565
   641
#elif __FREEBSD__
slouken@3366
   642
# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
slouken@3366
   643
#  if (__FreeBSD_kernel_version <= 500111)
slouken@1895
   644
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@611
   645
#  else
slouken@1895
   646
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@611
   647
#  endif
slouken@552
   648
# else
slouken@1895
   649
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@1565
   650
# endif
slouken@552
   651
#else
slouken@552
   652
# ifdef USBHID_NEW
slouken@1895
   653
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@1565
   654
# else
slouken@1895
   655
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@552
   656
# endif
slouken@552
   657
#endif
slouken@552
   658
slouken@1895
   659
    if (len < 0) {
icculus@7037
   660
        return SDL_SetError("Negative HID report size");
slouken@1895
   661
    }
slouken@1895
   662
    r->size = len;
slouken@278
   663
slouken@1895
   664
    if (r->size > 0) {
slouken@6963
   665
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
slouken@6963
   666
        r->buf = SDL_malloc(r->size);
slouken@6963
   667
#else
slouken@1895
   668
        r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
slouken@1895
   669
                            r->size);
slouken@6963
   670
#endif
slouken@1895
   671
        if (r->buf == NULL) {
icculus@7037
   672
            return SDL_OutOfMemory();
slouken@1895
   673
        }
slouken@1895
   674
    } else {
slouken@1895
   675
        r->buf = NULL;
slouken@1895
   676
    }
slouken@278
   677
slouken@1895
   678
    r->status = SREPORT_CLEAN;
icculus@7037
   679
    return 0;
slouken@278
   680
}
slouken@278
   681
slouken@278
   682
static void
slouken@278
   683
report_free(struct report *r)
slouken@278
   684
{
slouken@7719
   685
    SDL_free(r->buf);
slouken@1895
   686
    r->status = SREPORT_UNINIT;
slouken@278
   687
}
slouken@278
   688
slouken@1635
   689
#endif /* SDL_JOYSTICK_USBHID */
slouken@6697
   690
slouken@1895
   691
/* vi: set ts=4 sw=4 expandtab: */