src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 06 Sep 2013 20:54:14 -0700
changeset 7733 957d7137867c
parent 7719 31b5f9ff36ca
child 8093 b43765095a6f
permissions -rw-r--r--
Fixed bug 2090 - Some joystick inputs are delayed on FreeBSD

kikuchan

Some joysticks with high sampling rate need to be read() more fast,
otherwise it delay user inputs due to internal queue.
Especially, an app that issues SDL_PollEvent() not so frequent
slouken@278
     1
/*
slouken@5535
     2
  Simple DirectMedia Layer
slouken@6885
     3
  Copyright (C) 1997-2013 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@7191
    79
#define MAX_UHID_JOYS   16
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
slouken@6700
   182
        joynames[SDL_SYS_numjoysticks] = 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) {
slouken@6697
   196
            joynames[SDL_SYS_numjoysticks++] = 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
slouken@6707
   207
int SDL_SYS_NumJoysticks()
slouken@6707
   208
{
slouken@6707
   209
    return SDL_SYS_numjoysticks;
slouken@6707
   210
}
slouken@6707
   211
slouken@6707
   212
void SDL_SYS_JoystickDetect()
slouken@6707
   213
{
slouken@6707
   214
}
slouken@6707
   215
slouken@6707
   216
SDL_bool SDL_SYS_JoystickNeedsPolling()
slouken@6707
   217
{
slouken@6707
   218
    return SDL_FALSE;
slouken@6707
   219
}
slouken@6707
   220
slouken@278
   221
const char *
slouken@6707
   222
SDL_SYS_JoystickNameForDeviceIndex(int device_index)
slouken@278
   223
{
slouken@6707
   224
    if (joydevnames[device_index] != NULL) {
slouken@6707
   225
        return (joydevnames[device_index]);
slouken@1895
   226
    }
slouken@6707
   227
    return (joynames[device_index]);
slouken@6707
   228
}
slouken@6707
   229
slouken@6707
   230
/* Function to perform the mapping from device index to the instance id for this index */
slouken@6707
   231
SDL_JoystickID SDL_SYS_GetInstanceIdOfDeviceIndex(int device_index)
slouken@6707
   232
{
slouken@6707
   233
    return device_index;
slouken@278
   234
}
slouken@278
   235
slouken@632
   236
static int
slouken@632
   237
usage_to_joyaxe(unsigned usage)
slouken@632
   238
{
slouken@632
   239
    int joyaxe;
slouken@632
   240
    switch (usage) {
slouken@632
   241
    case HUG_X:
slouken@1895
   242
        joyaxe = JOYAXE_X;
slouken@1895
   243
        break;
slouken@632
   244
    case HUG_Y:
slouken@1895
   245
        joyaxe = JOYAXE_Y;
slouken@1895
   246
        break;
slouken@632
   247
    case HUG_Z:
slouken@1895
   248
        joyaxe = JOYAXE_Z;
slouken@1895
   249
        break;
slouken@632
   250
    case HUG_SLIDER:
slouken@1895
   251
        joyaxe = JOYAXE_SLIDER;
slouken@1895
   252
        break;
slouken@632
   253
    case HUG_WHEEL:
slouken@1895
   254
        joyaxe = JOYAXE_WHEEL;
slouken@1895
   255
        break;
slouken@632
   256
    case HUG_RX:
slouken@1895
   257
        joyaxe = JOYAXE_RX;
slouken@1895
   258
        break;
slouken@632
   259
    case HUG_RY:
slouken@1895
   260
        joyaxe = JOYAXE_RY;
slouken@1895
   261
        break;
slouken@632
   262
    case HUG_RZ:
slouken@1895
   263
        joyaxe = JOYAXE_RZ;
slouken@1895
   264
        break;
slouken@632
   265
    default:
slouken@1895
   266
        joyaxe = -1;
slouken@632
   267
    }
slouken@1895
   268
    return joyaxe;
slouken@632
   269
}
slouken@632
   270
slouken@632
   271
static unsigned
slouken@632
   272
hatval_to_sdl(Sint32 hatval)
slouken@632
   273
{
slouken@632
   274
    static const unsigned hat_dir_map[8] = {
slouken@1895
   275
        SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN,
slouken@1895
   276
        SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
slouken@632
   277
    };
slouken@632
   278
    unsigned result;
slouken@1895
   279
    if ((hatval & 7) == hatval)
slouken@1895
   280
        result = hat_dir_map[hatval];
slouken@1895
   281
    else
slouken@1895
   282
        result = SDL_HAT_CENTERED;
slouken@632
   283
    return result;
slouken@632
   284
}
slouken@632
   285
slouken@632
   286
slouken@278
   287
int
slouken@6697
   288
SDL_SYS_JoystickOpen(SDL_Joystick * joy, int device_index)
slouken@278
   289
{
slouken@6697
   290
    char *path = joynames[device_index];
slouken@1895
   291
    struct joystick_hwdata *hw;
slouken@1895
   292
    struct hid_item hitem;
slouken@1895
   293
    struct hid_data *hdata;
slouken@1895
   294
    struct report *rep;
slouken@1895
   295
    int fd;
slouken@1895
   296
    int i;
slouken@278
   297
slouken@1895
   298
    fd = open(path, O_RDONLY);
slouken@1895
   299
    if (fd == -1) {
icculus@7037
   300
        return SDL_SetError("%s: %s", path, strerror(errno));
slouken@1895
   301
    }
slouken@278
   302
slouken@6698
   303
    joy->instance_id = device_index;
slouken@1895
   304
    hw = (struct joystick_hwdata *)
slouken@1895
   305
        SDL_malloc(sizeof(struct joystick_hwdata));
slouken@1895
   306
    if (hw == NULL) {
slouken@1895
   307
        close(fd);
icculus@7037
   308
        return SDL_OutOfMemory();
slouken@1895
   309
    }
slouken@1895
   310
    joy->hwdata = hw;
slouken@1895
   311
    hw->fd = fd;
slouken@1895
   312
    hw->path = strdup(path);
slouken@1895
   313
    if (!SDL_strncmp(path, "/dev/joy", 8)) {
slouken@1895
   314
        hw->type = BSDJOY_JOY;
slouken@1895
   315
        joy->naxes = 2;
slouken@1895
   316
        joy->nbuttons = 2;
slouken@1895
   317
        joy->nhats = 0;
slouken@1895
   318
        joy->nballs = 0;
slouken@6700
   319
        joydevnames[device_index] = strdup("Gameport joystick");
slouken@1895
   320
        goto usbend;
slouken@1895
   321
    } else {
slouken@1895
   322
        hw->type = BSDJOY_UHID;
slouken@1895
   323
    }
slouken@776
   324
slouken@1895
   325
    {
slouken@1895
   326
        int ax;
slouken@1895
   327
        for (ax = 0; ax < JOYAXE_count; ax++)
slouken@1895
   328
            hw->axis_map[ax] = -1;
slouken@1895
   329
    }
slouken@1895
   330
    hw->repdesc = hid_get_report_desc(fd);
slouken@1895
   331
    if (hw->repdesc == NULL) {
slouken@1895
   332
        SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
slouken@1895
   333
                     strerror(errno));
slouken@1895
   334
        goto usberr;
slouken@1895
   335
    }
icculus@3703
   336
    rep = &hw->inreport;
slouken@4537
   337
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
slouken@3385
   338
    rep->rid = hid_get_report_id(fd);
slouken@3385
   339
    if (rep->rid < 0) {
slouken@3385
   340
#else
slouken@1895
   341
    if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
slouken@3385
   342
#endif
slouken@1895
   343
        rep->rid = -1;          /* XXX */
slouken@1895
   344
    }
slouken@1895
   345
    if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
slouken@1895
   346
        goto usberr;
slouken@1895
   347
    }
slouken@1895
   348
    if (rep->size <= 0) {
slouken@1895
   349
        SDL_SetError("%s: Input report descriptor has invalid length",
slouken@1895
   350
                     hw->path);
slouken@1895
   351
        goto usberr;
slouken@1895
   352
    }
slouken@4537
   353
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@1895
   354
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
slouken@1895
   355
#else
slouken@1895
   356
    hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
slouken@1895
   357
#endif
slouken@1895
   358
    if (hdata == NULL) {
slouken@1895
   359
        SDL_SetError("%s: Cannot start HID parser", hw->path);
slouken@1895
   360
        goto usberr;
slouken@1895
   361
    }
slouken@1895
   362
    joy->naxes = 0;
slouken@1895
   363
    joy->nbuttons = 0;
slouken@1895
   364
    joy->nhats = 0;
slouken@1895
   365
    joy->nballs = 0;
slouken@1895
   366
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   367
        hw->axis_map[i] = -1;
slouken@278
   368
slouken@1895
   369
    while (hid_get_item(hdata, &hitem) > 0) {
slouken@1895
   370
        char *sp;
slouken@1895
   371
        const char *s;
slouken@278
   372
slouken@1895
   373
        switch (hitem.kind) {
slouken@1895
   374
        case hid_collection:
slouken@1895
   375
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   376
            case HUP_GENERIC_DESKTOP:
slouken@1895
   377
                switch (HID_USAGE(hitem.usage)) {
slouken@1895
   378
                case HUG_JOYSTICK:
slouken@1895
   379
                case HUG_GAME_PAD:
slouken@1895
   380
                    s = hid_usage_in_page(hitem.usage);
slouken@1895
   381
                    sp = SDL_malloc(SDL_strlen(s) + 5);
slouken@1895
   382
                    SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)",
slouken@6700
   383
                                 s, device_index);
slouken@6700
   384
                    joydevnames[device_index] = sp;
slouken@1895
   385
                }
slouken@1895
   386
            }
slouken@1895
   387
            break;
slouken@1895
   388
        case hid_input:
slouken@1895
   389
            switch (HID_PAGE(hitem.usage)) {
slouken@1895
   390
            case HUP_GENERIC_DESKTOP:
slouken@1895
   391
                {
slouken@1895
   392
                    unsigned usage = HID_USAGE(hitem.usage);
slouken@1895
   393
                    int joyaxe = usage_to_joyaxe(usage);
slouken@1895
   394
                    if (joyaxe >= 0) {
slouken@1895
   395
                        hw->axis_map[joyaxe] = 1;
slouken@1895
   396
                    } else if (usage == HUG_HAT_SWITCH) {
slouken@1895
   397
                        joy->nhats++;
slouken@1895
   398
                    }
slouken@1895
   399
                    break;
slouken@1895
   400
                }
slouken@1895
   401
            case HUP_BUTTON:
slouken@1895
   402
                joy->nbuttons++;
slouken@1895
   403
                break;
slouken@1895
   404
            default:
slouken@1895
   405
                break;
slouken@1895
   406
            }
slouken@1895
   407
            break;
slouken@1895
   408
        default:
slouken@1895
   409
            break;
slouken@1895
   410
        }
slouken@1895
   411
    }
slouken@1895
   412
    hid_end_parse(hdata);
slouken@1895
   413
    for (i = 0; i < JOYAXE_count; i++)
slouken@1895
   414
        if (hw->axis_map[i] > 0)
slouken@1895
   415
            hw->axis_map[i] = joy->naxes++;
slouken@278
   416
slouken@1895
   417
  usbend:
slouken@1895
   418
    /* The poll blocks the event thread. */
slouken@1895
   419
    fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@278
   420
slouken@1895
   421
    return (0);
slouken@1895
   422
  usberr:
slouken@1895
   423
    close(hw->fd);
slouken@1895
   424
    SDL_free(hw->path);
slouken@1895
   425
    SDL_free(hw);
slouken@1895
   426
    return (-1);
slouken@278
   427
}
slouken@278
   428
slouken@6707
   429
/* Function to determine is this joystick is attached to the system right now */
slouken@6707
   430
SDL_bool SDL_SYS_JoystickAttached(SDL_Joystick *joystick)
slouken@6707
   431
{
slouken@6707
   432
    return SDL_TRUE;
slouken@6707
   433
}
slouken@6707
   434
slouken@278
   435
void
slouken@1895
   436
SDL_SYS_JoystickUpdate(SDL_Joystick * joy)
slouken@278
   437
{
slouken@1895
   438
    struct hid_item hitem;
slouken@1895
   439
    struct hid_data *hdata;
slouken@1895
   440
    struct report *rep;
slouken@1895
   441
    int nbutton, naxe = -1;
slouken@1895
   442
    Sint32 v;
slouken@776
   443
slouken@4537
   444
#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
slouken@1895
   445
    struct joystick gameport;
slouken@1895
   446
    static int x, y, xmin = 0xffff, ymin = 0xffff, xmax = 0, ymax = 0;
slouken@1895
   447
slouken@1895
   448
    if (joy->hwdata->type == BSDJOY_JOY) {
slouken@7733
   449
        while (read(joy->hwdata->fd, &gameport, sizeof gameport) == sizeof gameport) {
slouken@7733
   450
            if (abs(x - gameport.x) > 8) {
slouken@7733
   451
                x = gameport.x;
slouken@7733
   452
                if (x < xmin) {
slouken@7733
   453
                    xmin = x;
slouken@7733
   454
                }
slouken@7733
   455
                if (x > xmax) {
slouken@7733
   456
                    xmax = x;
slouken@7733
   457
                }
slouken@7733
   458
                if (xmin == xmax) {
slouken@7733
   459
                    xmin--;
slouken@7733
   460
                    xmax++;
slouken@7733
   461
                }
slouken@7733
   462
                v = (Sint32) x;
slouken@7733
   463
                v -= (xmax + xmin + 1) / 2;
slouken@7733
   464
                v *= 32768 / ((xmax - xmin + 1) / 2);
slouken@7733
   465
                SDL_PrivateJoystickAxis(joy, 0, v);
slouken@1895
   466
            }
slouken@7733
   467
            if (abs(y - gameport.y) > 8) {
slouken@7733
   468
                y = gameport.y;
slouken@7733
   469
                if (y < ymin) {
slouken@7733
   470
                    ymin = y;
slouken@7733
   471
                }
slouken@7733
   472
                if (y > ymax) {
slouken@7733
   473
                    ymax = y;
slouken@7733
   474
                }
slouken@7733
   475
                if (ymin == ymax) {
slouken@7733
   476
                    ymin--;
slouken@7733
   477
                    ymax++;
slouken@7733
   478
                }
slouken@7733
   479
                v = (Sint32) y;
slouken@7733
   480
                v -= (ymax + ymin + 1) / 2;
slouken@7733
   481
                v *= 32768 / ((ymax - ymin + 1) / 2);
slouken@7733
   482
                SDL_PrivateJoystickAxis(joy, 1, v);
slouken@1895
   483
            }
slouken@7733
   484
            if (gameport.b1 != joy->buttons[0]) {
slouken@7733
   485
                SDL_PrivateJoystickButton(joy, 0, gameport.b1);
slouken@1895
   486
            }
slouken@7733
   487
            if (gameport.b2 != joy->buttons[1]) {
slouken@7733
   488
                SDL_PrivateJoystickButton(joy, 1, gameport.b2);
slouken@1895
   489
            }
slouken@1895
   490
        }
slouken@1895
   491
        return;
slouken@1895
   492
    }
slouken@1565
   493
#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
slouken@381
   494
slouken@1895
   495
    rep = &joy->hwdata->inreport;
slouken@1895
   496
slouken@7733
   497
    while (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) == rep->size) {
slouken@4537
   498
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@7733
   499
        hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
slouken@407
   500
#else
slouken@7733
   501
        hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
slouken@407
   502
#endif
slouken@7733
   503
        if (hdata == NULL) {
slouken@7733
   504
            /*fprintf(stderr, "%s: Cannot start HID parser\n", joy->hwdata->path);*/
slouken@7733
   505
            continue;
slouken@7733
   506
        }
slouken@278
   507
slouken@7733
   508
        for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
slouken@7733
   509
            switch (hitem.kind) {
slouken@7733
   510
            case hid_input:
slouken@7733
   511
                switch (HID_PAGE(hitem.usage)) {
slouken@7733
   512
                case HUP_GENERIC_DESKTOP:
slouken@7733
   513
                    {
slouken@7733
   514
                        unsigned usage = HID_USAGE(hitem.usage);
slouken@7733
   515
                        int joyaxe = usage_to_joyaxe(usage);
slouken@7733
   516
                        if (joyaxe >= 0) {
slouken@7733
   517
                            naxe = joy->hwdata->axis_map[joyaxe];
slouken@7733
   518
                            /* scaleaxe */
slouken@7733
   519
                            v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@7733
   520
                            v -= (hitem.logical_maximum +
slouken@7733
   521
                                  hitem.logical_minimum + 1) / 2;
slouken@7733
   522
                            v *= 32768 /
slouken@7733
   523
                                ((hitem.logical_maximum -
slouken@7733
   524
                                  hitem.logical_minimum + 1) / 2);
slouken@7733
   525
                            if (v != joy->axes[naxe]) {
slouken@7733
   526
                                SDL_PrivateJoystickAxis(joy, naxe, v);
slouken@7733
   527
                            }
slouken@7733
   528
                        } else if (usage == HUG_HAT_SWITCH) {
slouken@7733
   529
                            v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@7733
   530
                            SDL_PrivateJoystickHat(joy, 0,
slouken@7733
   531
                                                   hatval_to_sdl(v) -
slouken@7733
   532
                                                   hitem.logical_minimum);
slouken@1895
   533
                        }
slouken@7733
   534
                        break;
slouken@1895
   535
                    }
slouken@7733
   536
                case HUP_BUTTON:
slouken@7733
   537
                    v = (Sint32) hid_get_data(REP_BUF_DATA(rep), &hitem);
slouken@7733
   538
                    if (joy->buttons[nbutton] != v) {
slouken@7733
   539
                        SDL_PrivateJoystickButton(joy, nbutton, v);
slouken@7733
   540
                    }
slouken@7733
   541
                    nbutton++;
slouken@1895
   542
                    break;
slouken@7733
   543
                default:
slouken@7733
   544
                    continue;
slouken@1895
   545
                }
slouken@1895
   546
                break;
slouken@1895
   547
            default:
slouken@7733
   548
                break;
slouken@1895
   549
            }
slouken@1895
   550
        }
slouken@7733
   551
        hid_end_parse(hdata);
slouken@1895
   552
    }
slouken@278
   553
}
slouken@278
   554
slouken@278
   555
/* Function to close a joystick after use */
slouken@278
   556
void
slouken@1895
   557
SDL_SYS_JoystickClose(SDL_Joystick * joy)
slouken@278
   558
{
slouken@1895
   559
    if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8)) {
slouken@1895
   560
        report_free(&joy->hwdata->inreport);
slouken@1895
   561
        hid_dispose_report_desc(joy->hwdata->repdesc);
slouken@1895
   562
    }
slouken@1895
   563
    close(joy->hwdata->fd);
slouken@1895
   564
    SDL_free(joy->hwdata->path);
slouken@1895
   565
    SDL_free(joy->hwdata);
slouken@278
   566
slouken@1895
   567
    return;
slouken@278
   568
}
slouken@278
   569
slouken@278
   570
void
slouken@278
   571
SDL_SYS_JoystickQuit(void)
slouken@278
   572
{
slouken@1895
   573
    int i;
slouken@278
   574
slouken@1895
   575
    for (i = 0; i < MAX_JOYS; i++) {
slouken@7719
   576
        SDL_free(joynames[i]);
slouken@7719
   577
        SDL_free(joydevnames[i]);
slouken@1895
   578
    }
slouken@278
   579
slouken@1895
   580
    return;
slouken@278
   581
}
slouken@278
   582
slouken@6744
   583
SDL_JoystickGUID SDL_SYS_JoystickGetDeviceGUID( int device_index )
slouken@6697
   584
{
slouken@6744
   585
    SDL_JoystickGUID guid;
slouken@7191
   586
    /* the GUID is just the first 16 chars of the name for now */
slouken@6707
   587
    const char *name = SDL_SYS_JoystickNameForDeviceIndex( device_index );
slouken@6697
   588
    SDL_zero( guid );
slouken@6697
   589
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6697
   590
    return guid;
slouken@6697
   591
}
slouken@6697
   592
slouken@6744
   593
SDL_JoystickGUID SDL_SYS_JoystickGetGUID(SDL_Joystick * joystick)
slouken@6697
   594
{
slouken@6744
   595
    SDL_JoystickGUID guid;
slouken@7191
   596
    /* the GUID is just the first 16 chars of the name for now */
slouken@6697
   597
    const char *name = joystick->name;
slouken@6697
   598
    SDL_zero( guid );
slouken@6697
   599
    SDL_memcpy( &guid, name, SDL_min( sizeof(guid), SDL_strlen( name ) ) );
slouken@6697
   600
    return guid;
slouken@6697
   601
}
slouken@6697
   602
slouken@278
   603
static int
slouken@278
   604
report_alloc(struct report *r, struct report_desc *rd, int repind)
slouken@278
   605
{
slouken@1895
   606
    int len;
slouken@278
   607
slouken@1565
   608
#ifdef __DragonFly__
slouken@1895
   609
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@1565
   610
#elif __FREEBSD__
slouken@3366
   611
# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
slouken@3366
   612
#  if (__FreeBSD_kernel_version <= 500111)
slouken@1895
   613
    len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@611
   614
#  else
slouken@1895
   615
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@611
   616
#  endif
slouken@552
   617
# else
slouken@1895
   618
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@1565
   619
# endif
slouken@552
   620
#else
slouken@552
   621
# ifdef USBHID_NEW
slouken@1895
   622
    len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@1565
   623
# else
slouken@1895
   624
    len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@552
   625
# endif
slouken@552
   626
#endif
slouken@552
   627
slouken@1895
   628
    if (len < 0) {
icculus@7037
   629
        return SDL_SetError("Negative HID report size");
slouken@1895
   630
    }
slouken@1895
   631
    r->size = len;
slouken@278
   632
slouken@1895
   633
    if (r->size > 0) {
slouken@6963
   634
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 900000)
slouken@6963
   635
        r->buf = SDL_malloc(r->size);
slouken@6963
   636
#else
slouken@1895
   637
        r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
slouken@1895
   638
                            r->size);
slouken@6963
   639
#endif
slouken@1895
   640
        if (r->buf == NULL) {
icculus@7037
   641
            return SDL_OutOfMemory();
slouken@1895
   642
        }
slouken@1895
   643
    } else {
slouken@1895
   644
        r->buf = NULL;
slouken@1895
   645
    }
slouken@278
   646
slouken@1895
   647
    r->status = SREPORT_CLEAN;
icculus@7037
   648
    return 0;
slouken@278
   649
}
slouken@278
   650
slouken@278
   651
static void
slouken@278
   652
report_free(struct report *r)
slouken@278
   653
{
slouken@7719
   654
    SDL_free(r->buf);
slouken@1895
   655
    r->status = SREPORT_UNINIT;
slouken@278
   656
}
slouken@278
   657
slouken@1635
   658
#endif /* SDL_JOYSTICK_USBHID */
slouken@6697
   659
slouken@1895
   660
/* vi: set ts=4 sw=4 expandtab: */