src/joystick/bsd/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Fri, 24 Aug 2012 10:04:07 -0700
branchSDL-1.2
changeset 6402 e786a4241cb5
parent 6289 62ff1c0a103f
permissions -rw-r--r--
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@278
     2
    SDL - Simple DirectMedia Layer
slouken@6137
     3
    Copyright (C) 1997-2012 Sam Lantinga
slouken@278
     4
slouken@278
     5
    This library is free software; you can redistribute it and/or
slouken@1312
     6
    modify it under the terms of the GNU Lesser General Public
slouken@278
     7
    License as published by the Free Software Foundation; either
slouken@1312
     8
    version 2.1 of the License, or (at your option) any later version.
slouken@278
     9
slouken@278
    10
    This library is distributed in the hope that it will be useful,
slouken@278
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@278
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@1312
    13
    Lesser General Public License for more details.
slouken@278
    14
slouken@1312
    15
    You should have received a copy of the GNU Lesser General Public
slouken@1312
    16
    License along with this library; if not, write to the Free Software
slouken@1312
    17
    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA
slouken@278
    18
slouken@278
    19
    Sam Lantinga
slouken@1312
    20
    slouken@libsdl.org
slouken@278
    21
*/
slouken@1402
    22
#include "SDL_config.h"
slouken@278
    23
slouken@1635
    24
#ifdef SDL_JOYSTICK_USBHID
slouken@1635
    25
slouken@278
    26
/*
slouken@278
    27
 * Joystick driver for the uhid(4) interface found in OpenBSD,
slouken@278
    28
 * NetBSD and FreeBSD.
slouken@278
    29
 *
slouken@278
    30
 * Maintainer: <vedge at csoft.org>
slouken@278
    31
 */
slouken@278
    32
slouken@552
    33
#include <sys/param.h>
slouken@552
    34
slouken@278
    35
#include <unistd.h>
slouken@278
    36
#include <fcntl.h>
slouken@278
    37
#include <errno.h>
slouken@278
    38
slouken@4306
    39
#ifndef __FreeBSD_kernel_version
slouken@4306
    40
#define __FreeBSD_kernel_version __FreeBSD_version
slouken@4306
    41
#endif
slouken@4306
    42
slouken@403
    43
#if defined(HAVE_USB_H)
slouken@403
    44
#include <usb.h>
slouken@403
    45
#endif
slouken@1565
    46
#ifdef __DragonFly__
slouken@1565
    47
#include <bus/usb/usb.h>
slouken@1565
    48
#include <bus/usb/usbhid.h>
slouken@1565
    49
#else
slouken@278
    50
#include <dev/usb/usb.h>
slouken@278
    51
#include <dev/usb/usbhid.h>
slouken@1565
    52
#endif
slouken@358
    53
slouken@381
    54
#if defined(HAVE_USBHID_H)
slouken@381
    55
#include <usbhid.h>
slouken@381
    56
#elif defined(HAVE_LIBUSB_H)
slouken@381
    57
#include <libusb.h>
slouken@381
    58
#elif defined(HAVE_LIBUSBHID_H)
slouken@381
    59
#include <libusbhid.h>
slouken@358
    60
#endif
slouken@278
    61
slouken@4540
    62
#if defined(__FREEBSD__) || defined(__FreeBSD_kernel__)
slouken@1565
    63
#ifndef __DragonFly__
slouken@611
    64
#include <osreldate.h>
slouken@1565
    65
#endif
icculus@6081
    66
#if __FreeBSD_kernel_version > 800063
icculus@6081
    67
#include <dev/usb/usb_ioctl.h>
icculus@6081
    68
#endif
slouken@776
    69
#include <sys/joystick.h>
slouken@776
    70
#endif
slouken@776
    71
slouken@1565
    72
#if SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H
slouken@776
    73
#include <machine/joystick.h>
slouken@611
    74
#endif
slouken@611
    75
slouken@278
    76
#include "SDL_joystick.h"
slouken@1361
    77
#include "../SDL_sysjoystick.h"
slouken@1361
    78
#include "../SDL_joystick_c.h"
slouken@278
    79
slouken@6402
    80
#define MAX_UHID_JOYS	16
slouken@278
    81
#define MAX_JOY_JOYS	2
slouken@278
    82
#define MAX_JOYS	(MAX_UHID_JOYS + MAX_JOY_JOYS)
slouken@278
    83
icculus@6081
    84
struct report {
icculus@6081
    85
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063)
icculus@6081
    86
	struct	usb_gen_descriptor *buf;	/* Buffer */
icculus@6081
    87
#else
icculus@6081
    88
	struct	usb_ctl_report *buf;	/* Buffer */
slouken@4323
    89
#endif
slouken@278
    90
	size_t	size;			/* Buffer size */
slouken@278
    91
	int	rid;			/* Report ID */
slouken@278
    92
	enum {
slouken@278
    93
		SREPORT_UNINIT,
slouken@278
    94
		SREPORT_CLEAN,
slouken@278
    95
		SREPORT_DIRTY
slouken@278
    96
	} status;
slouken@278
    97
};
slouken@278
    98
slouken@278
    99
static struct {
slouken@278
   100
	int	uhid_report;
slouken@402
   101
	hid_kind_t kind;
slouken@278
   102
	const	char *name;
slouken@278
   103
} const repinfo[] = {
slouken@278
   104
	{ UHID_INPUT_REPORT,	hid_input,	"input" },
slouken@278
   105
	{ UHID_OUTPUT_REPORT,	hid_output,	"output" },
slouken@278
   106
	{ UHID_FEATURE_REPORT,	hid_feature,	"feature" }
slouken@278
   107
};
slouken@307
   108
slouken@307
   109
enum {
slouken@307
   110
	REPORT_INPUT = 0,
slouken@307
   111
	REPORT_OUTPUT = 1,
slouken@307
   112
	REPORT_FEATURE = 2
slouken@307
   113
};
slouken@307
   114
slouken@307
   115
enum {
slouken@307
   116
	JOYAXE_X,
slouken@307
   117
	JOYAXE_Y,
slouken@307
   118
	JOYAXE_Z,
slouken@307
   119
	JOYAXE_SLIDER,
slouken@632
   120
	JOYAXE_WHEEL,
slouken@632
   121
	JOYAXE_RX,
slouken@632
   122
	JOYAXE_RY,
slouken@632
   123
	JOYAXE_RZ,
slouken@632
   124
	JOYAXE_count
slouken@307
   125
};
slouken@278
   126
slouken@278
   127
struct joystick_hwdata {
slouken@278
   128
	int	fd;
slouken@278
   129
	char	*path;
slouken@278
   130
	enum {
slouken@278
   131
		BSDJOY_UHID,	/* uhid(4) */
slouken@278
   132
		BSDJOY_JOY	/* joy(4) */
slouken@278
   133
	} type;
slouken@278
   134
	struct	report_desc *repdesc;
slouken@278
   135
	struct	report inreport;
slouken@632
   136
	int	axis_map[JOYAXE_count];	/* map present JOYAXE_* to 0,1,..*/
slouken@4022
   137
	int	x;
slouken@4022
   138
	int	y;
slouken@4022
   139
	int	xmin;
slouken@4022
   140
	int	ymin;
slouken@4022
   141
	int	xmax;
slouken@4022
   142
	int	ymax;
slouken@278
   143
};
slouken@278
   144
slouken@278
   145
static char *joynames[MAX_JOYS];
slouken@278
   146
static char *joydevnames[MAX_JOYS];
slouken@278
   147
slouken@278
   148
static int	report_alloc(struct report *, struct report_desc *, int);
slouken@278
   149
static void	report_free(struct report *);
slouken@278
   150
slouken@6289
   151
#if defined(USBHID_UCR_DATA)
slouken@381
   152
#define REP_BUF_DATA(rep) ((rep)->buf->ucr_data)
icculus@6081
   153
#elif (defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063))
icculus@6081
   154
#define REP_BUF_DATA(rep) ((rep)->buf->ugd_data)
slouken@381
   155
#else
slouken@381
   156
#define REP_BUF_DATA(rep) ((rep)->buf->data)
slouken@381
   157
#endif
slouken@381
   158
slouken@278
   159
int
slouken@278
   160
SDL_SYS_JoystickInit(void)
slouken@278
   161
{
slouken@503
   162
	char s[16];
slouken@278
   163
	int i, fd;
slouken@278
   164
slouken@278
   165
	SDL_numjoysticks = 0;
slouken@278
   166
slouken@1336
   167
	SDL_memset(joynames, 0, sizeof(joynames));
slouken@1336
   168
	SDL_memset(joydevnames, 0, sizeof(joydevnames));
slouken@278
   169
slouken@278
   170
	for (i = 0; i < MAX_UHID_JOYS; i++) {
slouken@544
   171
		SDL_Joystick nj;
slouken@544
   172
slouken@1338
   173
		SDL_snprintf(s, SDL_arraysize(s), "/dev/uhid%d", i);
slouken@544
   174
slouken@544
   175
		nj.index = SDL_numjoysticks;
slouken@544
   176
		joynames[nj.index] = strdup(s);
slouken@544
   177
slouken@544
   178
		if (SDL_SYS_JoystickOpen(&nj) == 0) {
slouken@544
   179
			SDL_SYS_JoystickClose(&nj);
slouken@544
   180
			SDL_numjoysticks++;
slouken@544
   181
		} else {
slouken@1336
   182
			SDL_free(joynames[nj.index]);
slouken@965
   183
			joynames[nj.index] = NULL;
slouken@278
   184
		}
slouken@278
   185
	}
slouken@278
   186
	for (i = 0; i < MAX_JOY_JOYS; i++) {
slouken@1338
   187
		SDL_snprintf(s, SDL_arraysize(s), "/dev/joy%d", i);
slouken@544
   188
		fd = open(s, O_RDONLY);
slouken@544
   189
		if (fd != -1) {
slouken@278
   190
			joynames[SDL_numjoysticks++] = strdup(s);
slouken@278
   191
			close(fd);
slouken@278
   192
		}
slouken@278
   193
	}
slouken@278
   194
slouken@278
   195
	/* Read the default USB HID usage table. */
slouken@278
   196
	hid_init(NULL);
slouken@278
   197
slouken@278
   198
	return (SDL_numjoysticks);
slouken@278
   199
}
slouken@278
   200
slouken@278
   201
const char *
slouken@278
   202
SDL_SYS_JoystickName(int index)
slouken@278
   203
{
slouken@278
   204
	if (joydevnames[index] != NULL) {
slouken@278
   205
		return (joydevnames[index]);
slouken@278
   206
	}
slouken@278
   207
	return (joynames[index]);
slouken@278
   208
}
slouken@278
   209
slouken@632
   210
static int
slouken@632
   211
usage_to_joyaxe(unsigned usage)
slouken@632
   212
{
slouken@632
   213
    int joyaxe;
slouken@632
   214
    switch (usage) {
slouken@632
   215
    case HUG_X:
slouken@632
   216
	joyaxe = JOYAXE_X; break;
slouken@632
   217
    case HUG_Y:
slouken@632
   218
	joyaxe = JOYAXE_Y; break;
slouken@632
   219
    case HUG_Z:
slouken@632
   220
	joyaxe = JOYAXE_Z; break;
slouken@632
   221
    case HUG_SLIDER:
slouken@632
   222
	joyaxe = JOYAXE_SLIDER; break;
slouken@632
   223
    case HUG_WHEEL:
slouken@632
   224
	joyaxe = JOYAXE_WHEEL; break;
slouken@632
   225
    case HUG_RX:
slouken@632
   226
	joyaxe = JOYAXE_RX; break;
slouken@632
   227
    case HUG_RY:
slouken@632
   228
	joyaxe = JOYAXE_RY; break;
slouken@632
   229
    case HUG_RZ:
slouken@632
   230
	joyaxe = JOYAXE_RZ; break;
slouken@632
   231
    default:
slouken@632
   232
	joyaxe = -1;
slouken@632
   233
    }
slouken@632
   234
    return joyaxe;    
slouken@632
   235
}
slouken@632
   236
slouken@632
   237
static unsigned
slouken@632
   238
hatval_to_sdl(Sint32 hatval)
slouken@632
   239
{
slouken@632
   240
    static const unsigned hat_dir_map[8] = {
slouken@632
   241
	SDL_HAT_UP, SDL_HAT_RIGHTUP, SDL_HAT_RIGHT, SDL_HAT_RIGHTDOWN, 
slouken@632
   242
	SDL_HAT_DOWN, SDL_HAT_LEFTDOWN, SDL_HAT_LEFT, SDL_HAT_LEFTUP
slouken@632
   243
    };
slouken@632
   244
    unsigned result;
slouken@632
   245
    if ((hatval & 7) == hatval) 
slouken@632
   246
	result = hat_dir_map[hatval];
slouken@632
   247
    else 
slouken@632
   248
	result = SDL_HAT_CENTERED;
slouken@632
   249
    return result;
slouken@632
   250
}
slouken@632
   251
slouken@632
   252
slouken@278
   253
int
slouken@278
   254
SDL_SYS_JoystickOpen(SDL_Joystick *joy)
slouken@278
   255
{
slouken@278
   256
	char *path = joynames[joy->index];
slouken@278
   257
	struct joystick_hwdata *hw;
slouken@278
   258
	struct hid_item hitem;
slouken@278
   259
	struct hid_data *hdata;
slouken@278
   260
	struct report *rep;
slouken@278
   261
	int fd;
slouken@1565
   262
	int i;
slouken@278
   263
slouken@715
   264
	fd = open(path, O_RDONLY);
slouken@544
   265
	if (fd == -1) {
slouken@278
   266
		SDL_SetError("%s: %s", path, strerror(errno));
slouken@278
   267
		return (-1);
slouken@278
   268
	}
slouken@278
   269
slouken@1336
   270
	hw = (struct joystick_hwdata *)SDL_malloc(sizeof(struct joystick_hwdata));
slouken@278
   271
	if (hw == NULL) {
slouken@278
   272
		SDL_OutOfMemory();
slouken@278
   273
		close(fd);
slouken@278
   274
		return (-1);
slouken@278
   275
	}
slouken@278
   276
	joy->hwdata = hw;
slouken@278
   277
	hw->fd = fd;
slouken@278
   278
	hw->path = strdup(path);
slouken@4022
   279
	hw->x = 0;
slouken@4022
   280
	hw->y = 0;
slouken@4022
   281
	hw->xmin = 0xffff;
slouken@4022
   282
	hw->ymin = 0xffff;
slouken@4022
   283
	hw->xmax = 0;
slouken@4022
   284
	hw->ymax = 0;
slouken@1336
   285
	if (! SDL_strncmp(path, "/dev/joy", 8)) {
slouken@776
   286
		hw->type = BSDJOY_JOY;
slouken@776
   287
		joy->naxes = 2;
slouken@776
   288
		joy->nbuttons = 2;
slouken@776
   289
		joy->nhats = 0;
slouken@776
   290
		joy->nballs = 0;
slouken@776
   291
		joydevnames[joy->index] = strdup("Gameport joystick");
slouken@776
   292
		goto usbend;
slouken@776
   293
	} else {
slouken@776
   294
		hw->type = BSDJOY_UHID;
slouken@776
   295
	}
slouken@776
   296
slouken@632
   297
	{
slouken@632
   298
	    int ax;
slouken@632
   299
	    for (ax = 0; ax < JOYAXE_count; ax++)
slouken@632
   300
		hw->axis_map[ax] = -1;
slouken@632
   301
	}
slouken@278
   302
	hw->repdesc = hid_get_report_desc(fd);
slouken@278
   303
	if (hw->repdesc == NULL) {
slouken@278
   304
		SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
slouken@278
   305
		    strerror(errno));
slouken@278
   306
		goto usberr;
slouken@278
   307
	}
icculus@4401
   308
	rep = &hw->inreport;
slouken@4540
   309
#if defined(__FREEBSD__) && (__FreeBSD_kernel_version > 800063) || defined(__FreeBSD_kernel__)
slouken@4323
   310
       rep->rid = hid_get_report_id(fd);
slouken@4323
   311
       if (rep->rid < 0) {
slouken@4323
   312
#else
slouken@1559
   313
	if (ioctl(fd, USB_GET_REPORT_ID, &rep->rid) < 0) {
slouken@4323
   314
#endif
slouken@1559
   315
		rep->rid = -1; /* XXX */
slouken@1559
   316
	}
slouken@278
   317
	if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
slouken@278
   318
		goto usberr;
slouken@278
   319
	}
slouken@278
   320
	if (rep->size <= 0) {
slouken@307
   321
		SDL_SetError("%s: Input report descriptor has invalid length",
slouken@307
   322
		    hw->path);
slouken@278
   323
		goto usberr;
slouken@278
   324
	}
slouken@278
   325
slouken@4540
   326
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@407
   327
	hdata = hid_start_parse(hw->repdesc, 1 << hid_input, rep->rid);
slouken@407
   328
#else
slouken@278
   329
	hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
slouken@407
   330
#endif
slouken@278
   331
	if (hdata == NULL) {
slouken@278
   332
		SDL_SetError("%s: Cannot start HID parser", hw->path);
slouken@278
   333
		goto usberr;
slouken@278
   334
	}
slouken@278
   335
	joy->naxes = 0;
slouken@278
   336
	joy->nbuttons = 0;
slouken@278
   337
	joy->nhats = 0;
slouken@278
   338
	joy->nballs = 0;
slouken@1565
   339
	for (i=0; i<JOYAXE_count; i++)
slouken@1565
   340
		hw->axis_map[i] = -1;
slouken@278
   341
slouken@278
   342
	while (hid_get_item(hdata, &hitem) > 0) {
slouken@358
   343
		char *sp;
slouken@358
   344
		const char *s;
slouken@278
   345
slouken@278
   346
		switch (hitem.kind) {
slouken@278
   347
		case hid_collection:
slouken@278
   348
			switch (HID_PAGE(hitem.usage)) {
slouken@278
   349
			case HUP_GENERIC_DESKTOP:
slouken@278
   350
				switch (HID_USAGE(hitem.usage)) {
slouken@278
   351
				case HUG_JOYSTICK:
slouken@278
   352
				case HUG_GAME_PAD:
slouken@278
   353
					s = hid_usage_in_page(hitem.usage);
slouken@1336
   354
					sp = SDL_malloc(SDL_strlen(s) + 5);
slouken@1338
   355
					SDL_snprintf(sp, SDL_strlen(s) + 5, "%s (%d)", s,
slouken@278
   356
					    joy->index);
slouken@278
   357
					joydevnames[joy->index] = sp;
slouken@278
   358
				}
slouken@278
   359
			}
slouken@278
   360
			break;
slouken@278
   361
		case hid_input:
slouken@278
   362
			switch (HID_PAGE(hitem.usage)) {
slouken@632
   363
			case HUP_GENERIC_DESKTOP: {
slouken@632
   364
			    unsigned usage = HID_USAGE(hitem.usage);
slouken@632
   365
			    int joyaxe = usage_to_joyaxe(usage);
slouken@632
   366
			    if (joyaxe >= 0) {
slouken@1565
   367
				hw->axis_map[joyaxe] = 1;
slouken@632
   368
			    } else if (usage == HUG_HAT_SWITCH) {
slouken@632
   369
				joy->nhats++;
slouken@632
   370
			    }
slouken@632
   371
			    break;
slouken@632
   372
			}
slouken@278
   373
			case HUP_BUTTON:
slouken@278
   374
				joy->nbuttons++;
slouken@278
   375
				break;
slouken@405
   376
			default:
slouken@405
   377
				break;
slouken@278
   378
			}
slouken@278
   379
			break;
slouken@278
   380
		default:
slouken@278
   381
			break;
slouken@278
   382
		}
slouken@278
   383
	}
slouken@278
   384
	hid_end_parse(hdata);
slouken@1565
   385
	for (i=0; i<JOYAXE_count; i++)
slouken@1565
   386
		if (hw->axis_map[i] > 0)
slouken@1565
   387
			hw->axis_map[i] = joy->naxes++;
slouken@278
   388
slouken@776
   389
usbend:
slouken@278
   390
	/* The poll blocks the event thread. */
slouken@278
   391
	fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@278
   392
slouken@278
   393
	return (0);
slouken@278
   394
usberr:
slouken@278
   395
	close(hw->fd);
slouken@1336
   396
	SDL_free(hw->path);
slouken@1336
   397
	SDL_free(hw);
slouken@278
   398
	return (-1);
slouken@278
   399
}
slouken@278
   400
slouken@278
   401
void
slouken@278
   402
SDL_SYS_JoystickUpdate(SDL_Joystick *joy)
slouken@278
   403
{
slouken@381
   404
	struct hid_item hitem;
slouken@381
   405
	struct hid_data *hdata;
slouken@381
   406
	struct report *rep;
slouken@358
   407
	int nbutton, naxe = -1;
slouken@307
   408
	Sint32 v;
slouken@776
   409
slouken@4540
   410
#if defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H || defined(__FreeBSD_kernel__)
slouken@776
   411
	struct joystick gameport;
slouken@776
   412
 
slouken@776
   413
	if (joy->hwdata->type == BSDJOY_JOY) {
slouken@776
   414
		if (read(joy->hwdata->fd, &gameport, sizeof gameport) != sizeof gameport)
slouken@776
   415
			return;
slouken@4022
   416
		if (abs(joy->hwdata->x - gameport.x) > 8) {
slouken@4022
   417
			joy->hwdata->x = gameport.x;
slouken@4022
   418
			if (joy->hwdata->x < joy->hwdata->xmin) {
slouken@4022
   419
				joy->hwdata->xmin = joy->hwdata->x;
slouken@776
   420
			}
slouken@4022
   421
			if (joy->hwdata->x > joy->hwdata->xmax) {
slouken@4022
   422
				joy->hwdata->xmax = joy->hwdata->x;
slouken@776
   423
			}
slouken@4022
   424
			if (joy->hwdata->xmin == joy->hwdata->xmax) {
slouken@4022
   425
				joy->hwdata->xmin--;
slouken@4022
   426
				joy->hwdata->xmax++;
slouken@776
   427
			}
slouken@4022
   428
			v = (Sint32)joy->hwdata->x;
slouken@4022
   429
			v -= (joy->hwdata->xmax + joy->hwdata->xmin + 1)/2;
slouken@4022
   430
			v *= 32768/((joy->hwdata->xmax - joy->hwdata->xmin + 1)/2);
slouken@776
   431
			SDL_PrivateJoystickAxis(joy, 0, v);
slouken@776
   432
		}
slouken@4022
   433
		if (abs(joy->hwdata->y - gameport.y) > 8) {
slouken@4022
   434
			joy->hwdata->y = gameport.y;
slouken@4022
   435
			if (joy->hwdata->y < joy->hwdata->ymin) {
slouken@4022
   436
				joy->hwdata->ymin = joy->hwdata->y;
slouken@776
   437
			}
slouken@4022
   438
			if (joy->hwdata->y > joy->hwdata->ymax) {
slouken@4022
   439
				joy->hwdata->ymax = joy->hwdata->y;
slouken@776
   440
			}
slouken@4022
   441
			if (joy->hwdata->ymin == joy->hwdata->ymax) {
slouken@4022
   442
				joy->hwdata->ymin--;
slouken@4022
   443
				joy->hwdata->ymax++;
slouken@776
   444
			}
slouken@4022
   445
			v = (Sint32)joy->hwdata->y;
slouken@4022
   446
			v -= (joy->hwdata->ymax + joy->hwdata->ymin + 1)/2;
slouken@4022
   447
			v *= 32768/((joy->hwdata->ymax - joy->hwdata->ymin + 1)/2);
slouken@776
   448
			SDL_PrivateJoystickAxis(joy, 1, v);
slouken@776
   449
		}
slouken@776
   450
		if (gameport.b1 != joy->buttons[0]) {
slouken@776
   451
			SDL_PrivateJoystickButton(joy, 0, gameport.b1);
slouken@776
   452
		}
slouken@776
   453
		if (gameport.b2 != joy->buttons[1]) {
slouken@776
   454
			SDL_PrivateJoystickButton(joy, 1, gameport.b2);
slouken@776
   455
		}
slouken@776
   456
		return;
slouken@776
   457
	}
slouken@1565
   458
#endif /* defined(__FREEBSD__) || SDL_JOYSTICK_USBHID_MACHINE_JOYSTICK_H */
slouken@278
   459
	
slouken@278
   460
	rep = &joy->hwdata->inreport;
slouken@381
   461
slouken@381
   462
	if (read(joy->hwdata->fd, REP_BUF_DATA(rep), rep->size) != rep->size) {
slouken@278
   463
		return;
slouken@278
   464
	}
slouken@4540
   465
#if defined(USBHID_NEW) || (defined(__FREEBSD__) && __FreeBSD_kernel_version >= 500111) || defined(__FreeBSD_kernel__)
slouken@407
   466
	hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input, rep->rid);
slouken@407
   467
#else
slouken@278
   468
	hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
slouken@407
   469
#endif
slouken@278
   470
	if (hdata == NULL) {
slouken@278
   471
		fprintf(stderr, "%s: Cannot start HID parser\n",
slouken@278
   472
		    joy->hwdata->path);
slouken@278
   473
		return;
slouken@278
   474
	}
slouken@278
   475
slouken@307
   476
	for (nbutton = 0; hid_get_item(hdata, &hitem) > 0;) {
slouken@278
   477
		switch (hitem.kind) {
slouken@278
   478
		case hid_input:
slouken@278
   479
			switch (HID_PAGE(hitem.usage)) {
slouken@632
   480
			case HUP_GENERIC_DESKTOP: {
slouken@632
   481
			    unsigned usage = HID_USAGE(hitem.usage);
slouken@632
   482
			    int joyaxe = usage_to_joyaxe(usage);
slouken@632
   483
			    if (joyaxe >= 0) {
slouken@632
   484
				naxe = joy->hwdata->axis_map[joyaxe];
slouken@632
   485
				/* scaleaxe */
slouken@381
   486
				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
slouken@632
   487
							 &hitem);
slouken@461
   488
				v -= (hitem.logical_maximum + hitem.logical_minimum + 1)/2;
slouken@461
   489
				v *= 32768/((hitem.logical_maximum - hitem.logical_minimum + 1)/2);
slouken@307
   490
				if (v != joy->axes[naxe]) {
slouken@632
   491
				    SDL_PrivateJoystickAxis(joy, naxe, v);
slouken@278
   492
				}
slouken@632
   493
			    } else if (usage == HUG_HAT_SWITCH) {
slouken@632
   494
				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
slouken@632
   495
							 &hitem);
slouken@1565
   496
				SDL_PrivateJoystickHat(joy, 0,
slouken@1565
   497
					hatval_to_sdl(v)-hitem.logical_minimum);
slouken@632
   498
			    }
slouken@632
   499
			    break;
slouken@632
   500
			}
slouken@278
   501
			case HUP_BUTTON:
slouken@381
   502
				v = (Sint32)hid_get_data(REP_BUF_DATA(rep),
slouken@307
   503
				    &hitem);
slouken@278
   504
				if (joy->buttons[nbutton] != v) {
slouken@278
   505
					SDL_PrivateJoystickButton(joy,
slouken@278
   506
					    nbutton, v);
slouken@278
   507
				}
slouken@278
   508
				nbutton++;
slouken@278
   509
				break;
slouken@405
   510
			default:
slouken@405
   511
				continue;
slouken@278
   512
			}
slouken@278
   513
			break;
slouken@278
   514
		default:
slouken@278
   515
			break;
slouken@278
   516
		}
slouken@278
   517
	}
slouken@278
   518
	hid_end_parse(hdata);
slouken@278
   519
slouken@278
   520
	return;
slouken@278
   521
}
slouken@278
   522
slouken@278
   523
/* Function to close a joystick after use */
slouken@278
   524
void
slouken@278
   525
SDL_SYS_JoystickClose(SDL_Joystick *joy)
slouken@278
   526
{
slouken@1336
   527
	if (SDL_strncmp(joy->hwdata->path, "/dev/joy", 8))	{
slouken@776
   528
		report_free(&joy->hwdata->inreport);
slouken@776
   529
		hid_dispose_report_desc(joy->hwdata->repdesc);
slouken@776
   530
	}
slouken@278
   531
	close(joy->hwdata->fd);
slouken@1336
   532
	SDL_free(joy->hwdata->path);
slouken@1336
   533
	SDL_free(joy->hwdata);
slouken@278
   534
slouken@278
   535
	return;
slouken@278
   536
}
slouken@278
   537
slouken@278
   538
void
slouken@278
   539
SDL_SYS_JoystickQuit(void)
slouken@278
   540
{
slouken@278
   541
	int i;
slouken@278
   542
slouken@278
   543
	for (i = 0; i < MAX_JOYS; i++) {
slouken@278
   544
		if (joynames[i] != NULL)
slouken@1336
   545
			SDL_free(joynames[i]);
slouken@278
   546
		if (joydevnames[i] != NULL)
slouken@1336
   547
			SDL_free(joydevnames[i]);
slouken@278
   548
	}
slouken@278
   549
slouken@278
   550
	return;
slouken@278
   551
}
slouken@278
   552
slouken@278
   553
static int
slouken@278
   554
report_alloc(struct report *r, struct report_desc *rd, int repind)
slouken@278
   555
{
slouken@278
   556
	int len;
slouken@278
   557
slouken@1565
   558
#ifdef __DragonFly__
slouken@1565
   559
	len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@1565
   560
#elif __FREEBSD__
slouken@4305
   561
# if (__FreeBSD_kernel_version >= 460000) || defined(__FreeBSD_kernel__)
slouken@4305
   562
#  if (__FreeBSD_kernel_version <= 500111)
slouken@552
   563
	len = hid_report_size(rd, r->rid, repinfo[repind].kind);
slouken@611
   564
#  else
slouken@611
   565
	len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@611
   566
#  endif
slouken@552
   567
# else
icculus@426
   568
	len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@1565
   569
# endif
slouken@552
   570
#else
slouken@552
   571
# ifdef USBHID_NEW
slouken@1565
   572
	len = hid_report_size(rd, repinfo[repind].kind, r->rid);
slouken@1565
   573
# else
slouken@552
   574
	len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
slouken@552
   575
# endif
slouken@552
   576
#endif
slouken@552
   577
slouken@278
   578
	if (len < 0) {
slouken@278
   579
		SDL_SetError("Negative HID report size");
slouken@278
   580
		return (-1);
slouken@278
   581
	}
slouken@278
   582
	r->size = len;
slouken@278
   583
slouken@278
   584
	if (r->size > 0) {
slouken@1336
   585
		r->buf = SDL_malloc(sizeof(*r->buf) - sizeof(REP_BUF_DATA(r)) +
slouken@278
   586
		    r->size);
slouken@278
   587
		if (r->buf == NULL) {
slouken@278
   588
			SDL_OutOfMemory();
slouken@278
   589
			return (-1);
slouken@278
   590
		}
slouken@278
   591
	} else {
slouken@278
   592
		r->buf = NULL;
slouken@278
   593
	}
slouken@278
   594
slouken@278
   595
	r->status = SREPORT_CLEAN;
slouken@278
   596
	return (0);
slouken@278
   597
}
slouken@278
   598
slouken@278
   599
static void
slouken@278
   600
report_free(struct report *r)
slouken@278
   601
{
slouken@278
   602
	if (r->buf != NULL) {
slouken@1336
   603
		SDL_free(r->buf);
slouken@278
   604
	}
slouken@278
   605
	r->status = SREPORT_UNINIT;
slouken@278
   606
}
slouken@278
   607
slouken@1635
   608
#endif /* SDL_JOYSTICK_USBHID */