src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 24 Aug 2012 10:03:05 -0700
changeset 6401 a4bd9821a796
parent 6290 4cf8e87aff95
child 6697 dbda91031456
permissions -rwxr-xr-x
Fixed bug 1561 - BSD joystick: Increase the number of uhid devices to scan

Brad Smith 2012-08-01 20:10:19 PDT

The attached patch from the OpenBSD ports tree is to increase the number of
uhid devices to scan for joysticks. It's somewhat easy to exhaust the default
number of devices which are scanned.
slouken@278
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6138
     3
  Copyright (C) 1997-2012 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
*/
slouken@1402
    21
#include "SDL_config.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
slouken@6401
    79
#define MAX_UHID_JOYS	16
slouken@278
    80
#define MAX_JOY_JOYS	2
slouken@278
    81
#define MAX_JOYS	(MAX_UHID_JOYS + MAX_JOY_JOYS)
slouken@278
    82
slouken@3385
    83
slouken@1895
    84
struct report
slouken@1895
    85
{
icculus@6080
    86
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
icculus@6080
    87
    struct usb_gen_descriptor *buf; /* Buffer */
icculus@6080
    88
#else
slouken@1895
    89
    struct usb_ctl_report *buf; /* Buffer */
icculus@6080
    90
#endif
slouken@1895
    91
    size_t size;                /* Buffer size */
slouken@1895
    92
    int rid;                    /* Report ID */
slouken@1895
    93
    enum
slouken@1895
    94
    {
slouken@1895
    95
        SREPORT_UNINIT,
slouken@1895
    96
        SREPORT_CLEAN,
slouken@1895
    97
        SREPORT_DIRTY
slouken@1895
    98
    } status;
slouken@278
    99
};
slouken@278
   100
slouken@1895
   101
static struct
slouken@1895
   102
{
slouken@1895
   103
    int uhid_report;
slouken@1895
   104
    hid_kind_t kind;
slouken@1895
   105
    const char *name;
slouken@278
   106
} const repinfo[] = {
slouken@1895
   107
    {UHID_INPUT_REPORT, hid_input, "input"},
slouken@1895
   108
    {UHID_OUTPUT_REPORT, hid_output, "output"},
slouken@1895
   109
    {UHID_FEATURE_REPORT, hid_feature, "feature"}
slouken@278
   110
};
slouken@307
   111
slouken@1895
   112
enum
slouken@1895
   113
{
slouken@1895
   114
    REPORT_INPUT = 0,
slouken@1895
   115
    REPORT_OUTPUT = 1,
slouken@1895
   116
    REPORT_FEATURE = 2
slouken@307
   117
};
slouken@307
   118
slouken@1895
   119
enum
slouken@1895
   120
{
slouken@1895
   121
    JOYAXE_X,
slouken@1895
   122
    JOYAXE_Y,
slouken@1895
   123
    JOYAXE_Z,
slouken@1895
   124
    JOYAXE_SLIDER,
slouken@1895
   125
    JOYAXE_WHEEL,
slouken@1895
   126
    JOYAXE_RX,
slouken@1895
   127
    JOYAXE_RY,
slouken@1895
   128
    JOYAXE_RZ,
slouken@1895
   129
    JOYAXE_count
slouken@307
   130
};
slouken@278
   131
slouken@1895
   132
struct joystick_hwdata
slouken@1895
   133
{
slouken@1895
   134
    int fd;
slouken@1895
   135
    char *path;
slouken@1895
   136
    enum
slouken@1895
   137
    {
slouken@1895
   138
        BSDJOY_UHID,            /* uhid(4) */
slouken@1895
   139
        BSDJOY_JOY              /* joy(4) */
slouken@1895
   140
    } type;
slouken@1895
   141
    struct report_desc *repdesc;
slouken@1895
   142
    struct report inreport;
slouken@1895
   143
    int axis_map[JOYAXE_count]; /* map present JOYAXE_* to 0,1,.. */
slouken@278
   144
};
slouken@278
   145
slouken@278
   146
static char *joynames[MAX_JOYS];
slouken@278
   147
static char *joydevnames[MAX_JOYS];
slouken@278
   148
slouken@1895
   149
static int report_alloc(struct report *, struct report_desc *, int);
slouken@1895
   150
static void report_free(struct report *);
slouken@278
   151
slouken@6290
   152
#if defined(USBHID_UCR_DATA)
slouken@381
   153
#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
icculus@6080
   154
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
icculus@6080
   155
#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
slouken@381
   156
#else
slouken@381
   157
#define REP_BUF_DATA(rep) ((rep)->buf->data)
slouken@381
   158
#endif
slouken@381
   159
slouken@278
   160
int
slouken@278
   161
SDL_SYS_JoystickInit(void)
slouken@278
   162
{
slouken@1895
   163
    char s[16];
slouken@1895
   164
    int i, fd;
slouken@278
   165
slouken@1895
   166
    SDL_numjoysticks = 0;
slouken@278
   167
slouken@1895
   168
    SDL_memset(joynames, 0, sizeof(joynames));
slouken@1895
   169
    SDL_memset(joydevnames, 0, sizeof(joydevnames));
slouken@278
   170
slouken@1895
   171
    for (i = 0; i < MAX_UHID_JOYS; i++) {
slouken@1895
   172
        SDL_Joystick nj;
slouken@544
   173
slouken@1895
   174
        SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
slouken@544
   175
slouken@1895
   176
        nj.index = SDL_numjoysticks;
slouken@1895
   177
        joynames[nj.index] = strdup(s);
slouken@544
   178
slouken@1895
   179
        if (SDL_SYS_JoystickOpen(&nj) == 0) {
slouken@1895
   180
            SDL_SYS_JoystickClose(&nj);
slouken@1895
   181
            SDL_numjoysticks++;
slouken@1895
   182
        } else {
slouken@1895
   183
            SDL_free(joynames[nj.index]);
slouken@1895
   184
            joynames[nj.index] = NULL;
slouken@1895
   185
        }
slouken@1895
   186
    }
slouken@1895
   187
    for (i = 0; i < MAX_JOY_JOYS; i++) {
slouken@1895
   188
        SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
slouken@1895
   189
        fd = open(s, O_RDONLY);
slouken@1895
   190
        if (fd != -1) {
slouken@1895
   191
            joynames[SDL_numjoysticks++] = strdup(s);
slouken@1895
   192
            close(fd);
slouken@1895
   193
        }
slouken@1895
   194
    }
slouken@278
   195
slouken@1895
   196
    /* Read the default USB HID usage table. */
slouken@1895
   197
    hid_init(NULL);
slouken@278
   198
slouken@1895
   199
    return (SDL_numjoysticks);
slouken@278
   200
}
slouken@278
   201
slouken@278
   202
const char *
slouken@278
   203
SDL_SYS_JoystickName(int index)
slouken@278
   204
{
slouken@1895
   205
    if (joydevnames[index] != NULL) {
slouken@1895
   206
        return (joydevnames[index]);
slouken@1895
   207
    }
slouken@1895
   208
    return (joynames[index]);
slouken@278
   209
}
slouken@278
   210
slouken@632
   211
static int
slouken@632
   212
usage_to_joyaxe(unsigned usage)
slouken@632
   213
{
slouken@632
   214
    int joyaxe;
slouken@632
   215
    switch (usage) {
slouken@632
   216
    case HUG_X:
slouken@1895
   217
        joyaxe = JOYAXE_X;
slouken@1895
   218
        break;
slouken@632
   219
    case HUG_Y:
slouken@1895
   220
        joyaxe = JOYAXE_Y;
slouken@1895
   221
        break;
slouken@632
   222
    case HUG_Z:
slouken@1895
   223
        joyaxe = JOYAXE_Z;
slouken@1895
   224
        break;
slouken@632
   225
    case HUG_SLIDER:
slouken@1895
   226
        joyaxe = JOYAXE_SLIDER;
slouken@1895
   227
        break;
slouken@632
   228
    case HUG_WHEEL:
slouken@1895
   229
        joyaxe = JOYAXE_WHEEL;
slouken@1895
   230
        break;
slouken@632
   231
    case HUG_RX:
slouken@1895
   232
        joyaxe = JOYAXE_RX;
slouken@1895
   233
        break;
slouken@632
   234
    case HUG_RY:
slouken@1895
   235
        joyaxe = JOYAXE_RY;
slouken@1895
   236
        break;
slouken@632
   237
    case HUG_RZ:
slouken@1895
   238
        joyaxe = JOYAXE_RZ;
slouken@1895
   239
        break;
slouken@632
   240
    default:
slouken@1895
   241
        joyaxe = -1;
slouken@632
   242
    }
slouken@1895
   243
    return joyaxe;
slouken@632
   244
}
slouken@632
   245
slouken@632
   246
static unsigned
slouken@632
   247
hatval_to_sdl(Sint32 hatval)
slouken@632
   248
{
slouken@632
   249
    static const unsigned hat_dir_map[8] = {
slouken@1895
   250
        SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
slouken@1895
   251
        SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
slouken@632
   252
    };
slouken@632
   253
    unsigned result;
slouken@1895
   254
    if ((hatval & 7) == hatval)
slouken@1895
   255
        result = hat_dir_map[hatval];
slouken@1895
   256
    else
slouken@1895
   257
        result = SDL_HAT_CENTERED;
slouken@632
   258
    return result;
slouken@632
   259
}
slouken@632
   260
slouken@632
   261
slouken@278
   262
int
slouken@1895
   263
SDL_SYS_JoystickOpen(SDL_Joystick * joy)
slouken@278
   264
{
slouken@1895
   265
    char *path = joynames[joy->index];
slouken@1895
   266
    struct joystick_hwdata *hw;
slouken@1895
   267
    struct hid_item hitem;
slouken@1895
   268
    struct hid_data *hdata;
slouken@1895
   269
    struct report *rep;
slouken@1895
   270
    int fd;
slouken@1895
   271
    int i;
slouken@278
   272
slouken@1895
   273
    fd = open(path, O_RDONLY);
slouken@1895
   274
    if (fd == -1) {
slouken@1895
   275
        SDL_SetError("%s: %s", path, strerror(errno));
slouken@1895
   276
        return (-1);
slouken@1895
   277
    }
slouken@278
   278
slouken@1895
   279
    hw = (struct joystick_hwdata *)
slouken@1895
   280
        SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   281
    if (hw == NULL) {
slouken@1895
   282
        SDL_OutOfMemory();
slouken@1895
   283
        close(fd);
slouken@1895
   284
        return (-1);
slouken@1895
   285
    }
slouken@1895
   286
    joy->hwdata = hw;
slouken@1895
   287
    hw->fd = fd;
slouken@1895
   288
    hw->path = strdup(path);
slouken@1895
   289
    if (!SDL_strncmp(path, "/dev/joy", 8)) {
slouken@1895
   290
        hw->type = BSDJOY_JOY;
slouken@1895
   291
        joy->naxes = 2;
slouken@1895
   292
        joy->nbuttons = 2;
slouken@1895
   293
        joy->nhats = 0;
slouken@1895
   294
        joy->nballs = 0;
slouken@1895
   295
        joydevnames[joy->index] = strdup("Gameport joystick");
slouken@1895
   296
        goto usbend;
slouken@1895
   297
    } else {
slouken@1895
   298
        hw->type = BSDJOY_UHID;
slouken@1895
   299
    }
slouken@776
   300
slouken@1895
   301
    {
slouken@1895
   302
        int ax;
slouken@1895
   303
        for (ax = 0; ax < JOYAXE_count; ax++)
slouken@1895
   304
            hw->axis_map[ax] = -1;
slouken@1895
   305
    }
slouken@1895
   306
    hw->repdesc = hid_get_report_desc(fd);
slouken@1895
   307
    if (hw->repdesc == NULL) {
slouken@1895
   308
        SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
slouken@1895
   309
                     strerror(errno));
slouken@1895
   310
        goto usberr;
slouken@1895
   311
    }
icculus@3703
   312
    rep = &hw->inreport;
slouken@4537
   313
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
slouken@3385
   314
    rep->rid = hid_get_report_id(fd);
slouken@3385
   315
    if (rep->rid < 0) {
slouken@3385
   316
#else
slouken@1895
   317
    if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
slouken@3385
   318
#endif
slouken@1895
   319
        rep->rid = -1;          /* XXX */
slouken@1895
   320
    }
slouken@1895
   321
    if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
slouken@1895
   322
        goto usberr;
slouken@1895
   323
    }
slouken@1895
   324
    if (rep->size <= 0) {
slouken@1895
   325
        SDL_SetError("%s: Input report descriptor has invalid length",
slouken@1895
   326
                     hw->path);
slouken@1895
   327
        goto usberr;
slouken@1895
   328
    }
slouken@4537
   329
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@1895
   330
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
slouken@1895
   331
#else
slouken@1895
   332
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
slouken@1895
   333
#endif
slouken@1895
   334
    if (hdata == NULL) {
slouken@1895
   335
        SDL_SetError("%s: Cannot start HID parser", hw->path);
slouken@1895
   336
        goto usberr;
slouken@1895
   337
    }
slouken@1895
   338
    joy->naxes = 0;
slouken@1895
   339
    joy->nbuttons = 0;
slouken@1895
   340
    joy->nhats = 0;
slouken@1895
   341
    joy->nballs = 0;
slouken@1895
   342
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   343
        hw->axis_map[i] = -1;
slouken@278
   344
slouken@1895
   345
    while (hid_get_item(hdata, &hitem) > 0) {
slouken@1895
   346
        char *sp;
slouken@1895
   347
        const char *s;
slouken@278
   348
slouken@1895
   349
        switch (hitem.kind) {
slouken@1895
   350
        case hid_collection:
slouken@1895
   351
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   352
            case HUP_GENERIC_DESKTOP:
slouken@1895
   353
                switch (HID_USAGE(hitem.usage)) {
slouken@1895
   354
                case HUG_JOYSTICK:
slouken@1895
   355
                case HUG_GAME_PAD:
slouken@1895
   356
                    s = hid_usage_in_page(hitem.usage);
slouken@1895
   357
                    sp = SDL_malloc(SDL_strlen(s) + 5);
slouken@1895
   358
                    SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
slouken@1895
   359
                                 s, joy->index);
slouken@1895
   360
                    joydevnames[joy->index] = sp;
slouken@1895
   361
                }
slouken@1895
   362
            }
slouken@1895
   363
            break;
slouken@1895
   364
        case hid_input:
slouken@1895
   365
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   366
            case HUP_GENERIC_DESKTOP:
slouken@1895
   367
                {
slouken@1895
   368
                    unsigned usage = HID_USAGE(hitem.usage);
slouken@1895
   369
                    int joyaxe = usage_to_joyaxe(usage);
slouken@1895
   370
                    if (joyaxe >= 0) {
slouken@1895
   371
                        hw->axis_map[joyaxe] = 1;
slouken@1895
   372
                    } else if (usage == HUG_HAT_SWITCH) {
slouken@1895
   373
                        joy->nhats++;
slouken@1895
   374
                    }
slouken@1895
   375
                    break;
slouken@1895
   376
                }
slouken@1895
   377
            case HUP_BUTTON:
slouken@1895
   378
                joy->nbuttons++;
slouken@1895
   379
                break;
slouken@1895
   380
            default:
slouken@1895
   381
                break;
slouken@1895
   382
            }
slouken@1895
   383
            break;
slouken@1895
   384
        default:
slouken@1895
   385
            break;
slouken@1895
   386
        }
slouken@1895
   387
    }
slouken@1895
   388
    hid_end_parse(hdata);
slouken@1895
   389
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   390
        if (hw->axis_map[i] > 0)
slouken@1895
   391
            hw->axis_map[i] = joy->naxes++;
slouken@278
   392
slouken@1895
   393
  usbend:
slouken@1895
   394
    /* The poll blocks the event thread. */
slouken@1895
   395
    fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@278
   396
slouken@1895
   397
    return (0);
slouken@1895
   398
  usberr:
slouken@1895
   399
    close(hw->fd);
slouken@1895
   400
    SDL_free(hw->path);
slouken@1895
   401
    SDL_free(hw);
slouken@1895
   402
    return (-1);
slouken@278
   403
}
slouken@278
   404
slouken@278
   405
void
slouken@1895
   406
SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
slouken@278
   407
{
slouken@1895
   408
    struct hid_item hitem;
slouken@1895
   409
    struct hid_data *hdata;
slouken@1895
   410
    struct report *rep;
slouken@1895
   411
    int nbutton, naxe = -1;
slouken@1895
   412
    Sint32 v;
slouken@776
   413
slouken@4537
   414
#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
slouken@1895
   415
    struct joystick gameport;
slouken@1895
   416
    static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
slouken@1895
   417
slouken@1895
   418
    if (joy->hwdata->type == BSDJOY_JOY) {
slouken@1895
   419
        if (read(joy->hwdata->fd, &gameport, sizeof gameport) !=
slouken@1895
   420
            sizeof gameport)
slouken@1895
   421
            return;
slouken@1895
   422
        if (abs(x - gameport.x) > 8) {
slouken@1895
   423
            x = gameport.x;
slouken@1895
   424
            if (x < xmin) {
slouken@1895
   425
                xmin = x;
slouken@1895
   426
            }
slouken@1895
   427
            if (x > xmax) {
slouken@1895
   428
                xmax = x;
slouken@1895
   429
            }
slouken@1895
   430
            if (xmin == xmax) {
slouken@1895
   431
                xmin--;
slouken@1895
   432
                xmax++;
slouken@1895
   433
            }
slouken@1895
   434
            v = (Sint32) x;
slouken@1895
   435
            v -= (xmax + xmin + 1) / 2;
slouken@1895
   436
            v *= 32768 / ((xmax - xmin + 1) / 2);
slouken@1895
   437
            SDL_PrivateJoystickAxis(joy, 0, v);
slouken@1895
   438
        }
slouken@1895
   439
        if (abs(y - gameport.y) > 8) {
slouken@1895
   440
            y = gameport.y;
slouken@1895
   441
            if (y < ymin) {
slouken@1895
   442
                ymin = y;
slouken@1895
   443
            }
slouken@1895
   444
            if (y > ymax) {
slouken@1895
   445
                ymax = y;
slouken@1895
   446
            }
slouken@1895
   447
            if (ymin == ymax) {
slouken@1895
   448
                ymin--;
slouken@1895
   449
                ymax++;
slouken@1895
   450
            }
slouken@1895
   451
            v = (Sint32) y;
slouken@1895
   452
            v -= (ymax + ymin + 1) / 2;
slouken@1895
   453
            v *= 32768 / ((ymax - ymin + 1) / 2);
slouken@1895
   454
            SDL_PrivateJoystickAxis(joy, 1, v);
slouken@1895
   455
        }
slouken@1895
   456
        if (gameport.b1 != joy->buttons[0]) {
slouken@1895
   457
            SDL_PrivateJoystickButton(joy, 0, gameport.b1);
slouken@1895
   458
        }
slouken@1895
   459
        if (gameport.b2 != joy->buttons[1]) {
slouken@1895
   460
            SDL_PrivateJoystickButton(joy, 1, gameport.b2);
slouken@1895
   461
        }
slouken@1895
   462
        return;
slouken@1895
   463
    }
slouken@1565
   464
#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
slouken@381
   465
slouken@1895
   466
    rep = &joy->hwdata->inreport;
slouken@1895
   467
slouken@1895
   468
    if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) {
slouken@1895
   469
        return;
slouken@1895
   470
    }
slouken@4537
   471
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@1895
   472
    hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
slouken@407
   473
#else
slouken@1895
   474
    hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
slouken@407
   475
#endif
slouken@1895
   476
    if (hdata == NULL) {
slouken@1895
   477
        fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);
slouken@1895
   478
        return;
slouken@1895
   479
    }
slouken@278
   480
slouken@1895
   481
    for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
slouken@1895
   482
        switch (hitem.kind) {
slouken@1895
   483
        case hid_input:
slouken@1895
   484
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   485
            case HUP_GENERIC_DESKTOP:
slouken@1895
   486
                {
slouken@1895
   487
                    unsigned usage = HID_USAGE(hitem.usage);
slouken@1895
   488
                    int joyaxe = usage_to_joyaxe(usage);
slouken@1895
   489
                    if (joyaxe >= 0) {
slouken@1895
   490
                        naxe = joy->hwdata->axis_map[joyaxe];
slouken@1895
   491
                        /* scaleaxe */
slouken@1895
   492
                        v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@1895
   493
                        v -= (hitem.logical_maximum +
slouken@1895
   494
                              hitem.logical_minimum + 1) / 2;
slouken@1895
   495
                        v *= 32768 /
slouken@1895
   496
                            ((hitem.logical_maximum -
slouken@1895
   497
                              hitem.logical_minimum + 1) / 2);
slouken@1895
   498
                        if (v != joy->axes[naxe]) {
slouken@1895
   499
                            SDL_PrivateJoystickAxis(joy, naxe, v);
slouken@1895
   500
                        }
slouken@1895
   501
                    } else if (usage == HUG_HAT_SWITCH) {
slouken@1895
   502
                        v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@1895
   503
                        SDL_PrivateJoystickHat(joy, 0,
slouken@1895
   504
                                               hatval_to_sdl(v) -
slouken@1895
   505
                                               hitem.logical_minimum);
slouken@1895
   506
                    }
slouken@1895
   507
                    break;
slouken@1895
   508
                }
slouken@1895
   509
            case HUP_BUTTON:
slouken@1895
   510
                v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@1895
   511
                if (joy->buttons[nbutton] != v) {
slouken@1895
   512
                    SDL_PrivateJoystickButton(joy, nbutton, v);
slouken@1895
   513
                }
slouken@1895
   514
                nbutton++;
slouken@1895
   515
                break;
slouken@1895
   516
            default:
slouken@1895
   517
                continue;
slouken@1895
   518
            }
slouken@1895
   519
            break;
slouken@1895
   520
        default:
slouken@1895
   521
            break;
slouken@1895
   522
        }
slouken@1895
   523
    }
slouken@1895
   524
    hid_end_parse(hdata);
slouken@278
   525
slouken@1895
   526
    return;
slouken@278
   527
}
slouken@278
   528
slouken@278
   529
/* Function to close a joystick after use */
slouken@278
   530
void
slouken@1895
   531
SDL_SYS_JoystickClose(SDL_Joystick * joy)
slouken@278
   532
{
slouken@1895
   533
    if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
slouken@1895
   534
        report_free(&joy->hwdata->inreport);
slouken@1895
   535
        hid_dispose_report_desc(joy->hwdata->repdesc);
slouken@1895
   536
    }
slouken@1895
   537
    close(joy->hwdata->fd);
slouken@1895
   538
    SDL_free(joy->hwdata->path);
slouken@1895
   539
    SDL_free(joy->hwdata);
slouken@278
   540
slouken@1895
   541
    return;
slouken@278
   542
}
slouken@278
   543
slouken@278
   544
void
slouken@278
   545
SDL_SYS_JoystickQuit(void)
slouken@278
   546
{
slouken@1895
   547
    int i;
slouken@278
   548
slouken@1895
   549
    for (i = 0; i < MAX_JOYS; i++) {
slouken@1895
   550
        if (joynames[i] != NULL)
slouken@1895
   551
            SDL_free(joynames[i]);
slouken@1895
   552
        if (joydevnames[i] != NULL)
slouken@1895
   553
            SDL_free(joydevnames[i]);
slouken@1895
   554
    }
slouken@278
   555
slouken@1895
   556
    return;
slouken@278
   557
}
slouken@278
   558
slouken@278
   559
static int
slouken@278
   560
report_alloc(struct report *r, struct report_desc *rd, int repind)
slouken@278
   561
{
slouken@1895
   562
    int len;
slouken@278
   563
slouken@1565
   564
#ifdef __DragonFly__
slouken@1895
   565
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@1565
   566
#elif __FREEBSD__
slouken@3366
   567
# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
slouken@3366
   568
#  if (__FreeBSD_kernel_version <= 500111)
slouken@1895
   569
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@611
   570
#  else
slouken@1895
   571
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@611
   572
#  endif
slouken@552
   573
# else
slouken@1895
   574
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@1565
   575
# endif
slouken@552
   576
#else
slouken@552
   577
# ifdef USBHID_NEW
slouken@1895
   578
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@1565
   579
# else
slouken@1895
   580
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@552
   581
# endif
slouken@552
   582
#endif
slouken@552
   583
slouken@1895
   584
    if (len < 0) {
slouken@1895
   585
        SDL_SetError("Negative HID report size");
slouken@1895
   586
        return (-1);
slouken@1895
   587
    }
slouken@1895
   588
    r->size = len;
slouken@278
   589
slouken@1895
   590
    if (r->size > 0) {
slouken@1895
   591
        r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
slouken@1895
   592
                            r->size);
slouken@1895
   593
        if (r->buf == NULL) {
slouken@1895
   594
            SDL_OutOfMemory();
slouken@1895
   595
            return (-1);
slouken@1895
   596
        }
slouken@1895
   597
    } else {
slouken@1895
   598
        r->buf = NULL;
slouken@1895
   599
    }
slouken@278
   600
slouken@1895
   601
    r->status = SREPORT_CLEAN;
slouken@1895
   602
    return (0);
slouken@278
   603
}
slouken@278
   604
slouken@278
   605
static void
slouken@278
   606
report_free(struct report *r)
slouken@278
   607
{
slouken@1895
   608
    if (r->buf != NULL) {
slouken@1895
   609
        SDL_free(r->buf);
slouken@1895
   610
    }
slouken@1895
   611
    r->status = SREPORT_UNINIT;
slouken@278
   612
}
slouken@278
   613
slouken@1635
   614
#endif /* SDL_JOYSTICK_USBHID */
slouken@1895
   615
/* vi: set ts=4 sw=4 expandtab: */