Added support for joysticks on *BSD (thanks Wilbern!)
authorSam Lantinga <slouken@libsdl.org>
Thu, 14 Feb 2002 01:24:08 +0000
changeset 278dcd9f7b50a1c
parent 277 255c7ee077cb
child 279 04351f59b051
Added support for joysticks on *BSD (thanks Wilbern!)
configure.in
docs.html
src/joystick/Makefile.am
src/joystick/bsd/Makefile.am
src/joystick/bsd/SDL_sysjoystick.c
     1.1 --- a/configure.in	Thu Feb 14 00:47:46 2002 +0000
     1.2 +++ b/configure.in	Thu Feb 14 01:24:08 2002 +0000
     1.3 @@ -1452,10 +1452,9 @@
     1.4          #    AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la"
     1.5          #fi
     1.6          # Set up files for the joystick library
     1.7 -        # (No joystick support yet)
     1.8          if test x$enable_joystick = xyes; then
     1.9 -            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS dummy"
    1.10 -            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS dummy/libjoystick_dummy.la"
    1.11 +            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS bsd"
    1.12 +            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS bsd/libjoystick_bsd.la"
    1.13          fi
    1.14          # Set up files for the cdrom library
    1.15          if test x$enable_cdrom = xyes; then
    1.16 @@ -1504,10 +1503,9 @@
    1.17              AUDIO_DRIVERS="$AUDIO_DRIVERS sun/libaudio_sun.la"
    1.18          fi
    1.19          # Set up files for the joystick library
    1.20 -        # (No joystick support yet)
    1.21          if test x$enable_joystick = xyes; then
    1.22 -            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS dummy"
    1.23 -            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS dummy/libjoystick_dummy.la"
    1.24 +            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS bsd"
    1.25 +            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS bsd/libjoystick_bsd.la"
    1.26          fi
    1.27          # Set up files for the cdrom library
    1.28          if test x$enable_cdrom = xyes; then
    1.29 @@ -1564,10 +1562,9 @@
    1.30              SYSTEM_LIBS="$SYSTEM_LIBS -lossaudio"
    1.31          fi
    1.32          # Set up files for the joystick library
    1.33 -        # (No joystick support yet)
    1.34          if test x$enable_joystick = xyes; then
    1.35 -            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS dummy"
    1.36 -            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS dummy/libjoystick_dummy.la"
    1.37 +            JOYSTICK_SUBDIRS="$JOYSTICK_SUBDIRS bsd"
    1.38 +            JOYSTICK_DRIVERS="$JOYSTICK_DRIVERS bsd/libjoystick_bsd.la"
    1.39          fi
    1.40          # Set up files for the cdrom library
    1.41          if test x$enable_cdrom = xyes; then
     2.1 --- a/docs.html	Thu Feb 14 00:47:46 2002 +0000
     2.2 +++ b/docs.html	Thu Feb 14 01:24:08 2002 +0000
     2.3 @@ -16,6 +16,7 @@
     2.4  Major changes since SDL 1.0.0:
     2.5  </H2>
     2.6  <UL>
     2.7 +	<LI> 1.2.4: Added support for joysticks on *BSD (thanks Wilbern!)
     2.8  	<LI> 1.2.4: Added a YUV overlay test program (thanks Jon!)
     2.9  	<LI> 1.2.4: Added support for building SDL for EPOC/SymbianOS 6.0
    2.10  	<LI> 1.2.4: Added support for Xi Graphics XME fullscreen extension
     3.1 --- a/src/joystick/Makefile.am	Thu Feb 14 00:47:46 2002 +0000
     3.2 +++ b/src/joystick/Makefile.am	Thu Feb 14 01:24:08 2002 +0000
     3.3 @@ -5,7 +5,7 @@
     3.4  
     3.5  # Define which subdirectories need to be built
     3.6  SUBDIRS = @JOYSTICK_SUBDIRS@
     3.7 -DIST_SUBDIRS = dummy amigaos beos darwin linux macos win32
     3.8 +DIST_SUBDIRS = dummy amigaos beos bsd darwin linux macos win32
     3.9  
    3.10  DRIVERS = @JOYSTICK_DRIVERS@
    3.11  
     4.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.2 +++ b/src/joystick/bsd/Makefile.am	Thu Feb 14 01:24:08 2002 +0000
     4.3 @@ -0,0 +1,8 @@
     4.4 +
     4.5 +## Makefile.am for the BSD joystick driver for SDL
     4.6 +
     4.7 +noinst_LTLIBRARIES = libjoystick_bsd.la
     4.8 +libjoystick_bsd_la_SOURCES = $(SRCS)
     4.9 +
    4.10 +# The SDL joystick driver sources
    4.11 +SRCS =  SDL_sysjoystick.c
     5.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     5.2 +++ b/src/joystick/bsd/SDL_sysjoystick.c	Thu Feb 14 01:24:08 2002 +0000
     5.3 @@ -0,0 +1,388 @@
     5.4 +/*
     5.5 +    SDL - Simple DirectMedia Layer
     5.6 +    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
     5.7 +
     5.8 +    This library is free software; you can redistribute it and/or
     5.9 +    modify it under the terms of the GNU Library General Public
    5.10 +    License as published by the Free Software Foundation; either
    5.11 +    version 2 of the License, or (at your option) any later version.
    5.12 +
    5.13 +    This library is distributed in the hope that it will be useful,
    5.14 +    but WITHOUT ANY WARRANTY; without even the implied warranty of
    5.15 +    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    5.16 +    Library General Public License for more details.
    5.17 +
    5.18 +    You should have received a copy of the GNU Library General Public
    5.19 +    License along with this library; if not, write to the Free
    5.20 +    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
    5.21 +
    5.22 +    Sam Lantinga
    5.23 +    slouken@devolution.com
    5.24 +*/
    5.25 +
    5.26 +/*
    5.27 + * Joystick driver for the uhid(4) interface found in OpenBSD,
    5.28 + * NetBSD and FreeBSD.
    5.29 + *
    5.30 + * Maintainer: <vedge at csoft.org>
    5.31 + */
    5.32 +
    5.33 +#ifdef SAVE_RCSID
    5.34 +static char rcsid =
    5.35 + "@(#) $Id $";
    5.36 +#endif
    5.37 +
    5.38 +#include <stdio.h>
    5.39 +#include <stdlib.h>
    5.40 +#include <unistd.h>
    5.41 +#include <fcntl.h>
    5.42 +#include <string.h>
    5.43 +#include <errno.h>
    5.44 +
    5.45 +#include <dev/usb/usb.h>
    5.46 +#include <dev/usb/usbhid.h>
    5.47 +#include <usbhid.h>
    5.48 +
    5.49 +#include "SDL_error.h"
    5.50 +#include "SDL_joystick.h"
    5.51 +#include "SDL_sysjoystick.h"
    5.52 +#include "SDL_joystick_c.h"
    5.53 +
    5.54 +#define MAX_UHID_JOYS	4
    5.55 +#define MAX_JOY_JOYS	2
    5.56 +#define MAX_JOYS	(MAX_UHID_JOYS + MAX_JOY_JOYS)
    5.57 +
    5.58 +#define SDLAXIS_UINT8(v)		\
    5.59 +	((v == 127) ? 0 :		\
    5.60 +	 (v == 255) ? 32767 :		\
    5.61 +	 -32767)
    5.62 +
    5.63 +struct report {
    5.64 +	struct	usb_ctl_report *buf;	/* Buffer */
    5.65 +	size_t	size;			/* Buffer size */
    5.66 +	int	rid;			/* Report ID */
    5.67 +	enum {
    5.68 +		SREPORT_UNINIT,
    5.69 +		SREPORT_CLEAN,
    5.70 +		SREPORT_DIRTY
    5.71 +	} status;
    5.72 +};
    5.73 +
    5.74 +static struct {
    5.75 +	int	uhid_report;
    5.76 +	enum	hid_kind kind;
    5.77 +	const	char *name;
    5.78 +} const repinfo[] = {
    5.79 +	{ UHID_INPUT_REPORT,	hid_input,	"input" },
    5.80 +	{ UHID_OUTPUT_REPORT,	hid_output,	"output" },
    5.81 +	{ UHID_FEATURE_REPORT,	hid_feature,	"feature" }
    5.82 +};
    5.83 +#define REPORT_INPUT	0
    5.84 +#define REPORT_OUTPUT	1
    5.85 +#define REPORT_FEATURE	2
    5.86 +
    5.87 +struct joystick_hwdata {
    5.88 +	int	fd;
    5.89 +	char	*path;
    5.90 +	enum {
    5.91 +		BSDJOY_UHID,	/* uhid(4) */
    5.92 +		BSDJOY_JOY	/* joy(4) */
    5.93 +	} type;
    5.94 +	struct	report_desc *repdesc;
    5.95 +	struct	report inreport;
    5.96 +	int	axismin[3];
    5.97 +	int	axismax[3];
    5.98 +};
    5.99 +
   5.100 +static char *joynames[MAX_JOYS];
   5.101 +static char *joydevnames[MAX_JOYS];
   5.102 +
   5.103 +static int	report_alloc(struct report *, struct report_desc *, int);
   5.104 +static void	report_free(struct report *);
   5.105 +
   5.106 +int
   5.107 +SDL_SYS_JoystickInit(void)
   5.108 +{
   5.109 +	char s[10];
   5.110 +	int i, fd;
   5.111 +
   5.112 +	SDL_numjoysticks = 0;
   5.113 +
   5.114 +	memset(joynames, NULL, sizeof(joynames));
   5.115 +	memset(joydevnames, NULL, sizeof(joydevnames));
   5.116 +
   5.117 +	for (i = 0; i < MAX_UHID_JOYS; i++) {
   5.118 +		sprintf(s, "/dev/uhid%d", i);
   5.119 +		fd = open(s, O_RDWR);
   5.120 +		if (fd > 0) {
   5.121 +			joynames[SDL_numjoysticks++] = strdup(s);
   5.122 +			close(fd);
   5.123 +		}
   5.124 +	}
   5.125 +	for (i = 0; i < MAX_JOY_JOYS; i++) {
   5.126 +		sprintf(s, "/dev/joy%d", i);
   5.127 +		fd = open(s, O_RDWR);
   5.128 +		if (fd > 0) {
   5.129 +			joynames[SDL_numjoysticks++] = strdup(s);
   5.130 +			close(fd);
   5.131 +		}
   5.132 +	}
   5.133 +
   5.134 +	/* Read the default USB HID usage table. */
   5.135 +	hid_init(NULL);
   5.136 +
   5.137 +	return (SDL_numjoysticks);
   5.138 +}
   5.139 +
   5.140 +const char *
   5.141 +SDL_SYS_JoystickName(int index)
   5.142 +{
   5.143 +	if (joydevnames[index] != NULL) {
   5.144 +		return (joydevnames[index]);
   5.145 +	}
   5.146 +	return (joynames[index]);
   5.147 +}
   5.148 +
   5.149 +int
   5.150 +SDL_SYS_JoystickOpen(SDL_Joystick *joy)
   5.151 +{
   5.152 +	char *path = joynames[joy->index];
   5.153 +	struct joystick_hwdata *hw;
   5.154 +	struct hid_item hitem;
   5.155 +	struct hid_data *hdata;
   5.156 +	struct report *rep;
   5.157 +	int fd;
   5.158 +
   5.159 +	fd = open(path, O_RDWR);
   5.160 +	if (fd < 0) {
   5.161 +		SDL_SetError("%s: %s", path, strerror(errno));
   5.162 +		return (-1);
   5.163 +	}
   5.164 +
   5.165 +	hw = (struct joystick_hwdata *)malloc(sizeof(struct joystick_hwdata));
   5.166 +	if (hw == NULL) {
   5.167 +		SDL_OutOfMemory();
   5.168 +		close(fd);
   5.169 +		return (-1);
   5.170 +	}
   5.171 +	joy->hwdata = hw;
   5.172 +	hw->fd = fd;
   5.173 +	hw->path = strdup(path);
   5.174 +	hw->type = BSDJOY_UHID;
   5.175 +	hw->repdesc = hid_get_report_desc(fd);
   5.176 +	if (hw->repdesc == NULL) {
   5.177 +		SDL_SetError("%s: USB_GET_REPORT_DESC: %s", hw->path,
   5.178 +		    strerror(errno));
   5.179 +		goto usberr;
   5.180 +	}
   5.181 +
   5.182 +	rep = &hw->inreport;
   5.183 +	if (report_alloc(rep, hw->repdesc, REPORT_INPUT) < 0) {
   5.184 +		goto usberr;
   5.185 +	}
   5.186 +	if (rep->size <= 0) {
   5.187 +		SDL_SetError("Input report descriptor has invalid length");
   5.188 +		goto usberr;
   5.189 +	}
   5.190 +
   5.191 +	hdata = hid_start_parse(hw->repdesc, 1 << hid_input);
   5.192 +	if (hdata == NULL) {
   5.193 +		SDL_SetError("%s: Cannot start HID parser", hw->path);
   5.194 +		goto usberr;
   5.195 +	}
   5.196 +	joy->naxes = 0;
   5.197 +	joy->nbuttons = 0;
   5.198 +	joy->nhats = 0;
   5.199 +	joy->nballs = 0;
   5.200 +
   5.201 +	while (hid_get_item(hdata, &hitem) > 0) {
   5.202 +		char *s, *sp;
   5.203 +
   5.204 +		switch (hitem.kind) {
   5.205 +		case hid_collection:
   5.206 +			switch (HID_PAGE(hitem.usage)) {
   5.207 +			case HUP_GENERIC_DESKTOP:
   5.208 +				switch (HID_USAGE(hitem.usage)) {
   5.209 +				case HUG_JOYSTICK:
   5.210 +				case HUG_GAME_PAD:
   5.211 +					s = hid_usage_in_page(hitem.usage);
   5.212 +					sp = malloc(strlen(s) + 5);
   5.213 +					sprintf(sp, "%s (%d)", s,
   5.214 +					    joy->index);
   5.215 +					joydevnames[joy->index] = sp;
   5.216 +				}
   5.217 +			}
   5.218 +			break;
   5.219 +		case hid_input:
   5.220 +			switch (HID_PAGE(hitem.usage)) {
   5.221 +			case HUP_UNDEFINED:
   5.222 +				break;
   5.223 +			case HUP_GENERIC_DESKTOP:
   5.224 +				switch (HID_USAGE(hitem.usage)) {
   5.225 +				case HUG_X:
   5.226 +				case HUG_Y:
   5.227 +				case HUG_Z:
   5.228 +					hw->axismin[joy->naxes] =
   5.229 +					    hitem.logical_minimum;
   5.230 +					hw->axismax[joy->naxes] =
   5.231 +					    hitem.logical_maximum;
   5.232 +					joy->naxes++;
   5.233 +					break;
   5.234 +				}
   5.235 +				break;
   5.236 +			case HUP_BUTTON:
   5.237 +				joy->nbuttons++;
   5.238 +				break;
   5.239 +			}
   5.240 +			break;
   5.241 +		default:
   5.242 +			break;
   5.243 +		}
   5.244 +	}
   5.245 +	hid_end_parse(hdata);
   5.246 +
   5.247 +	/* The poll blocks the event thread. */
   5.248 +	fcntl(fd, F_SETFL, O_NONBLOCK);
   5.249 +
   5.250 +	return (0);
   5.251 +usberr:
   5.252 +	close(hw->fd);
   5.253 +	free(hw->path);
   5.254 +	free(hw);
   5.255 +	return (-1);
   5.256 +}
   5.257 +
   5.258 +void
   5.259 +SDL_SYS_JoystickUpdate(SDL_Joystick *joy)
   5.260 +{
   5.261 +	static struct hid_item hitem;
   5.262 +	static struct hid_data *hdata;
   5.263 +	static int nbutton, naxe, v, max, min;
   5.264 +	static struct report *rep;
   5.265 +	
   5.266 +	rep = &joy->hwdata->inreport;
   5.267 +	if (read(joy->hwdata->fd, rep->buf->data, rep->size) != rep->size) {
   5.268 +		return;
   5.269 +	}
   5.270 +	hdata = hid_start_parse(joy->hwdata->repdesc, 1 << hid_input);
   5.271 +	if (hdata == NULL) {
   5.272 +		fprintf(stderr, "%s: Cannot start HID parser\n",
   5.273 +		    joy->hwdata->path);
   5.274 +		return;
   5.275 +	}
   5.276 +
   5.277 +	for (nbutton = 0, naxe = 0; hid_get_item(hdata, &hitem) > 0;) {
   5.278 +		switch (hitem.kind) {
   5.279 +		case hid_input:
   5.280 +			switch (HID_PAGE(hitem.usage)) {
   5.281 +			case HUP_UNDEFINED:
   5.282 +				continue;
   5.283 +			case HUP_GENERIC_DESKTOP:
   5.284 +				switch (HID_USAGE(hitem.usage)) {
   5.285 +				case HUG_X:
   5.286 +				case HUG_Y:
   5.287 +				case HUG_Z:
   5.288 +					v = hid_get_data(rep->buf->data,
   5.289 +					    &hitem);
   5.290 +
   5.291 +					/*
   5.292 +					 * XXX revisit later. need to test
   5.293 +					 * with more devices.
   5.294 +					 */
   5.295 +					if (joy->hwdata->axismin[naxe] == 0 &&
   5.296 +					    joy->hwdata->axismax[naxe] == 255) {
   5.297 +						v = SDLAXIS_UINT8(v);
   5.298 +					}
   5.299 +
   5.300 +					if (v != joy->axes[naxe]) {
   5.301 +						SDL_PrivateJoystickAxis(joy,
   5.302 +						    naxe, (Sint32)v);
   5.303 +					}
   5.304 +					naxe++;
   5.305 +					break;
   5.306 +				}
   5.307 +				break;
   5.308 +			case HUP_BUTTON:
   5.309 +				/* XXX assume a 0..1 range */
   5.310 +				v = hid_get_data(rep->buf->data, &hitem);
   5.311 +				if (joy->buttons[nbutton] != v) {
   5.312 +					SDL_PrivateJoystickButton(joy,
   5.313 +					    nbutton, v);
   5.314 +				}
   5.315 +				nbutton++;
   5.316 +				break;
   5.317 +			}
   5.318 +			break;
   5.319 +		default:
   5.320 +			break;
   5.321 +		}
   5.322 +	}
   5.323 +	hid_end_parse(hdata);
   5.324 +
   5.325 +	return;
   5.326 +}
   5.327 +
   5.328 +/* Function to close a joystick after use */
   5.329 +void
   5.330 +SDL_SYS_JoystickClose(SDL_Joystick *joy)
   5.331 +{
   5.332 +	report_free(&joy->hwdata->inreport);
   5.333 +	hid_dispose_report_desc(joy->hwdata->repdesc);
   5.334 +	close(joy->hwdata->fd);
   5.335 +	free(joy->hwdata->path);
   5.336 +	free(joy->hwdata);
   5.337 +
   5.338 +	return;
   5.339 +}
   5.340 +
   5.341 +void
   5.342 +SDL_SYS_JoystickQuit(void)
   5.343 +{
   5.344 +	int i;
   5.345 +
   5.346 +	for (i = 0; i < MAX_JOYS; i++) {
   5.347 +		if (joynames[i] != NULL)
   5.348 +			free(joynames[i]);
   5.349 +		if (joydevnames[i] != NULL)
   5.350 +			free(joydevnames[i]);
   5.351 +	}
   5.352 +
   5.353 +	return;
   5.354 +}
   5.355 +
   5.356 +static int
   5.357 +report_alloc(struct report *r, struct report_desc *rd, int repind)
   5.358 +{
   5.359 +	int len;
   5.360 +
   5.361 +	len = hid_report_size(rd, repinfo[repind].kind, &r->rid);
   5.362 +	if (len < 0) {
   5.363 +		SDL_SetError("Negative HID report size");
   5.364 +		return (-1);
   5.365 +	}
   5.366 +	r->size = len;
   5.367 +
   5.368 +	if (r->size > 0) {
   5.369 +		r->buf = malloc(sizeof(*r->buf) - sizeof(r->buf->data) +
   5.370 +		    r->size);
   5.371 +		if (r->buf == NULL) {
   5.372 +			SDL_OutOfMemory();
   5.373 +			return (-1);
   5.374 +		}
   5.375 +	} else {
   5.376 +		r->buf = NULL;
   5.377 +	}
   5.378 +
   5.379 +	r->status = SREPORT_CLEAN;
   5.380 +	return (0);
   5.381 +}
   5.382 +
   5.383 +static void
   5.384 +report_free(struct report *r)
   5.385 +{
   5.386 +	if (r->buf != NULL) {
   5.387 +		free(r->buf);
   5.388 +	}
   5.389 +	r->status = SREPORT_UNINIT;
   5.390 +}
   5.391 +