src/joystick/linux/SDL_sysjoystick.c
author Sam Lantinga <slouken@libsdl.org>
Mon, 22 Oct 2001 21:34:50 +0000
changeset 211 0cc95f442f3a
parent 0 74212992fb08
child 221 50620ec9c86a
permissions -rw-r--r--
If we're looking at the /dev/input event devices, and we found
at least one, then we don't want to look at the input joystick
devices, since they're built on top of devices that we've already
seen, so we're done.
slouken@0
     1
/*
slouken@0
     2
    SDL - Simple DirectMedia Layer
slouken@0
     3
    Copyright (C) 1997, 1998, 1999, 2000, 2001  Sam Lantinga
slouken@0
     4
slouken@0
     5
    This library is free software; you can redistribute it and/or
slouken@0
     6
    modify it under the terms of the GNU Library General Public
slouken@0
     7
    License as published by the Free Software Foundation; either
slouken@0
     8
    version 2 of the License, or (at your option) any later version.
slouken@0
     9
slouken@0
    10
    This library is distributed in the hope that it will be useful,
slouken@0
    11
    but WITHOUT ANY WARRANTY; without even the implied warranty of
slouken@0
    12
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
slouken@0
    13
    Library General Public License for more details.
slouken@0
    14
slouken@0
    15
    You should have received a copy of the GNU Library General Public
slouken@0
    16
    License along with this library; if not, write to the Free
slouken@0
    17
    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
slouken@0
    18
slouken@0
    19
    Sam Lantinga
slouken@0
    20
    slouken@devolution.com
slouken@0
    21
*/
slouken@0
    22
slouken@0
    23
#ifdef SAVE_RCSID
slouken@0
    24
static char rcsid =
slouken@0
    25
 "@(#) $Id$";
slouken@0
    26
#endif
slouken@0
    27
slouken@0
    28
/* This is the system specific header for the SDL joystick API */
slouken@0
    29
slouken@0
    30
#include <stdio.h>		/* For the definition of NULL */
slouken@0
    31
#include <stdlib.h>		/* For getenv() prototype */
slouken@0
    32
#include <string.h>
slouken@0
    33
#include <sys/stat.h>
slouken@0
    34
#include <unistd.h>
slouken@0
    35
#include <fcntl.h>
slouken@0
    36
#include <sys/ioctl.h>
slouken@0
    37
#include <limits.h>		/* For the definition of PATH_MAX */
slouken@0
    38
slouken@0
    39
#include <linux/joystick.h>
slouken@0
    40
#ifdef USE_INPUT_EVENTS
slouken@0
    41
#include <linux/input.h>
slouken@0
    42
#endif
slouken@0
    43
slouken@0
    44
#include "SDL_error.h"
slouken@0
    45
#include "SDL_joystick.h"
slouken@0
    46
#include "SDL_sysjoystick.h"
slouken@0
    47
#include "SDL_joystick_c.h"
slouken@0
    48
slouken@0
    49
/* Define this if you want to map axes to hats and trackballs */
slouken@0
    50
#define FANCY_HATS_AND_BALLS
slouken@0
    51
slouken@0
    52
#ifdef FANCY_HATS_AND_BALLS
slouken@0
    53
/* Special joystick configurations:
slouken@0
    54
	'JoystickName' Naxes Nhats Nballs
slouken@0
    55
 */
slouken@0
    56
static const char *special_joysticks[] = {
slouken@0
    57
	"'MadCatz Panther XL' 3 2 1", /* We don't handle a rudder (axis 8) */
slouken@0
    58
	"'SideWinder Precision Pro' 4 1 0",
slouken@0
    59
	"'SideWinder 3D Pro' 4 1 0",
slouken@0
    60
	"'Microsoft SideWinder 3D Pro' 4 1 0",
slouken@0
    61
	"'Microsoft SideWinder Dual Strike USB version 1.0' 2 1 0",
slouken@0
    62
	"'WingMan Interceptor' 3 3 0",
slouken@0
    63
	/* WingMan Extreme Analog - not recognized by default
slouken@0
    64
	"'Analog 3-axis 4-button joystick' 2 1",
slouken@0
    65
	*/
slouken@0
    66
	"'WingMan Extreme Digital 3D' 4 1 0",
slouken@0
    67
	NULL
slouken@0
    68
};
slouken@0
    69
#else
slouken@0
    70
#undef USE_INPUT_EVENTS
slouken@0
    71
#endif
slouken@0
    72
slouken@0
    73
/* The maximum number of joysticks we'll detect */
slouken@0
    74
#define MAX_JOYSTICKS	32
slouken@0
    75
slouken@0
    76
/* A list of available joysticks */
slouken@0
    77
static char *SDL_joylist[MAX_JOYSTICKS];
slouken@0
    78
slouken@0
    79
/* The private structure used to keep track of a joystick */
slouken@0
    80
struct joystick_hwdata {
slouken@0
    81
	int fd;
slouken@0
    82
	/* The current linux joystick driver maps hats to two axes */
slouken@0
    83
	int analog_hat;		/* Well, except for analog hats */
slouken@0
    84
	struct hwdata_hat {
slouken@0
    85
		int axis[2];
slouken@0
    86
	} *hats;
slouken@0
    87
	/* The current linux joystick driver maps balls to two axes */
slouken@0
    88
	struct hwdata_ball {
slouken@0
    89
		int axis[2];
slouken@0
    90
	} *balls;
slouken@0
    91
slouken@0
    92
	/* Support for the Linux 2.4 unified input interface */
slouken@0
    93
	SDL_bool is_hid;
slouken@0
    94
#ifdef USE_INPUT_EVENTS
slouken@0
    95
	Uint8 key_map[KEY_MAX-BTN_MISC];
slouken@0
    96
	Uint8 abs_map[ABS_MAX];
slouken@0
    97
	struct axis_correct {
slouken@0
    98
		int used;
slouken@0
    99
		int coef[3];
slouken@0
   100
	} abs_correct[ABS_MAX];
slouken@0
   101
#endif
slouken@0
   102
};
slouken@0
   103
slouken@0
   104
static char *mystrdup(const char *string)
slouken@0
   105
{
slouken@0
   106
	char *newstring;
slouken@0
   107
slouken@0
   108
	newstring = (char *)malloc(strlen(string)+1);
slouken@0
   109
	if ( newstring ) {
slouken@0
   110
		strcpy(newstring, string);
slouken@0
   111
	}
slouken@0
   112
	return(newstring);
slouken@0
   113
}
slouken@0
   114
slouken@0
   115
#ifdef USE_INPUT_EVENTS
slouken@0
   116
#define test_bit(nr, addr) \
slouken@0
   117
	(((1UL << ((nr) & 31)) & (((const unsigned int *) addr)[(nr) >> 5])) != 0)
slouken@0
   118
slouken@0
   119
static int EV_IsJoystick(int fd)
slouken@0
   120
{
slouken@0
   121
	unsigned long evbit[40];
slouken@0
   122
	unsigned long keybit[40];
slouken@0
   123
	unsigned long absbit[40];
slouken@0
   124
slouken@0
   125
	if ( (ioctl(fd, EVIOCGBIT(0, sizeof(evbit)), evbit) < 0) ||
slouken@0
   126
	     (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) < 0) ||
slouken@0
   127
	     (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) < 0) ) {
slouken@0
   128
		return(0);
slouken@0
   129
	}
slouken@0
   130
	if (!(test_bit(EV_KEY, evbit) && test_bit(EV_ABS, evbit) &&
slouken@0
   131
	      test_bit(ABS_X, absbit) && test_bit(ABS_Y, absbit) &&
slouken@0
   132
	     (test_bit(BTN_TRIGGER, keybit) || test_bit(BTN_A, keybit) || test_bit(BTN_1, keybit)))) return 0;
slouken@0
   133
	return(1);
slouken@0
   134
}
slouken@0
   135
slouken@0
   136
#endif /* USE_INPUT_EVENTS */
slouken@0
   137
slouken@0
   138
/* Function to scan the system for joysticks */
slouken@0
   139
int SDL_SYS_JoystickInit(void)
slouken@0
   140
{
slouken@0
   141
	/* The base path of the joystick devices */
slouken@0
   142
	const char *joydev_pattern[2] = {
slouken@0
   143
		"/dev/js%d",
slouken@0
   144
#ifdef USE_INPUT_EVENTS
slouken@0
   145
		"/dev/input/event%d"
slouken@211
   146
#endif
slouken@0
   147
		"/dev/input/js%d"
slouken@0
   148
	};
slouken@0
   149
	int numjoysticks;
slouken@0
   150
	int i, j, done;
slouken@0
   151
	int fd;
slouken@0
   152
	char path[PATH_MAX];
slouken@0
   153
	dev_t dev_nums[MAX_JOYSTICKS];  /* major/minor device numbers */
slouken@0
   154
	struct stat sb;
slouken@0
   155
	int n, duplicate;
slouken@0
   156
slouken@0
   157
	numjoysticks = 0;
slouken@0
   158
slouken@0
   159
	/* First see if the user specified a joystick to use */
slouken@0
   160
	if ( getenv("SDL_JOYSTICK_DEVICE") != NULL ) {
slouken@0
   161
		strncpy(path, getenv("SDL_JOYSTICK_DEVICE"), sizeof(path));
slouken@0
   162
		path[sizeof(path)-1] = '\0';
slouken@0
   163
		if ( stat(path, &sb) == 0 ) {
slouken@0
   164
			fd = open(path, O_RDONLY, 0);
slouken@0
   165
			if ( fd >= 0 ) {
slouken@0
   166
				/* Assume the user knows what they're doing. */
slouken@0
   167
				SDL_joylist[numjoysticks] = mystrdup(path);
slouken@0
   168
				if ( SDL_joylist[numjoysticks] ) {
slouken@0
   169
					dev_nums[numjoysticks] = sb.st_rdev;
slouken@0
   170
					++numjoysticks;
slouken@0
   171
				}
slouken@0
   172
				close(fd);
slouken@0
   173
			}
slouken@0
   174
		}
slouken@0
   175
	}
slouken@0
   176
	for ( i=0; i<SDL_TABLESIZE(joydev_pattern); ++i ) {
slouken@0
   177
		done = 0;
slouken@0
   178
		for ( j=0; (j < MAX_JOYSTICKS) && !done; ++j ) {
slouken@0
   179
			sprintf(path, joydev_pattern[i], j);
slouken@0
   180
slouken@0
   181
			/* rcg06302000 replaced access(F_OK) call with stat().
slouken@0
   182
			 * stat() will fail if the file doesn't exist, so it's
slouken@0
   183
			 * equivalent behaviour.
slouken@0
   184
			 */
slouken@0
   185
			if ( stat(path, &sb) == 0 ) {
slouken@0
   186
				/* Check to make sure it's not already in list.
slouken@0
   187
				 * This happens when we see a stick via symlink.
slouken@0
   188
				 */
slouken@0
   189
				duplicate = 0;
slouken@0
   190
				for (n=0; (n<numjoysticks) && !duplicate; ++n) {
slouken@0
   191
					if ( sb.st_rdev == dev_nums[n] ) {
slouken@0
   192
						duplicate = 1;
slouken@0
   193
					}
slouken@0
   194
				}
slouken@0
   195
				if (duplicate) {
slouken@0
   196
					continue;
slouken@0
   197
				}
slouken@0
   198
slouken@0
   199
				fd = open(path, O_RDONLY, 0);
slouken@0
   200
				if ( fd < 0 ) {
slouken@0
   201
					continue;
slouken@0
   202
				}
slouken@0
   203
#ifdef USE_INPUT_EVENTS
slouken@0
   204
#ifdef DEBUG_INPUT_EVENTS
slouken@0
   205
				printf("Checking %s\n", path);
slouken@0
   206
#endif
slouken@0
   207
				if ( (i > 0) && ! EV_IsJoystick(fd) ) {
slouken@0
   208
					close(fd);
slouken@0
   209
					continue;
slouken@0
   210
				}
slouken@0
   211
#endif
slouken@0
   212
				close(fd);
slouken@0
   213
slouken@0
   214
				/* We're fine, add this joystick */
slouken@0
   215
				SDL_joylist[numjoysticks] = mystrdup(path);
slouken@0
   216
				if ( SDL_joylist[numjoysticks] ) {
slouken@0
   217
					dev_nums[numjoysticks] = sb.st_rdev;
slouken@0
   218
					++numjoysticks;
slouken@0
   219
				}
slouken@0
   220
			} else {
slouken@0
   221
				done = 1;
slouken@0
   222
			}
slouken@0
   223
		}
slouken@211
   224
        /* This is a special case...
slouken@211
   225
           If we're looking at the /dev/input event devices, and we found
slouken@211
   226
           at least one, then we don't want to look at the input joystick
slouken@211
   227
           devices, since they're built on top of devices that we've already
slouken@211
   228
           seen, so we're done.
slouken@211
   229
         */
slouken@211
   230
        if ( i > 0 && j > 0 ) {
slouken@211
   231
            done = 1;
slouken@211
   232
        }
slouken@0
   233
	}
slouken@0
   234
	return(numjoysticks);
slouken@0
   235
}
slouken@0
   236
slouken@0
   237
/* Function to get the device-dependent name of a joystick */
slouken@0
   238
const char *SDL_SYS_JoystickName(int index)
slouken@0
   239
{
slouken@0
   240
	int fd;
slouken@0
   241
	static char namebuf[128];
slouken@0
   242
	char *name;
slouken@0
   243
slouken@0
   244
	name = NULL;
slouken@0
   245
	fd = open(SDL_joylist[index], O_RDONLY, 0);
slouken@0
   246
	if ( fd >= 0 ) {
slouken@0
   247
		if ( 
slouken@0
   248
#ifdef USE_INPUT_EVENTS
slouken@0
   249
		     (ioctl(fd, EVIOCGNAME(sizeof(namebuf)), namebuf) <= 0) &&
slouken@0
   250
#endif
slouken@0
   251
		     (ioctl(fd, JSIOCGNAME(sizeof(namebuf)), namebuf) <= 0) ) {
slouken@0
   252
			name = SDL_joylist[index];
slouken@0
   253
		} else {
slouken@0
   254
			name = namebuf;
slouken@0
   255
		}
slouken@0
   256
		close(fd);
slouken@0
   257
	}
slouken@0
   258
	return name;
slouken@0
   259
}
slouken@0
   260
slouken@0
   261
#ifdef FANCY_HATS_AND_BALLS
slouken@0
   262
slouken@0
   263
static int allocate_hatdata(SDL_Joystick *joystick)
slouken@0
   264
{
slouken@0
   265
	int i;
slouken@0
   266
slouken@0
   267
	joystick->hwdata->hats = (struct hwdata_hat *)malloc(
slouken@0
   268
		joystick->nhats * sizeof(struct hwdata_hat));
slouken@0
   269
	if ( joystick->hwdata->hats == NULL ) {
slouken@0
   270
		return(-1);
slouken@0
   271
	}
slouken@0
   272
	for ( i=0; i<joystick->nhats; ++i ) {
slouken@0
   273
		joystick->hwdata->hats[i].axis[0] = 1;
slouken@0
   274
		joystick->hwdata->hats[i].axis[1] = 1;
slouken@0
   275
	}
slouken@0
   276
	return(0);
slouken@0
   277
}
slouken@0
   278
slouken@0
   279
static int allocate_balldata(SDL_Joystick *joystick)
slouken@0
   280
{
slouken@0
   281
	int i;
slouken@0
   282
slouken@0
   283
	joystick->hwdata->balls = (struct hwdata_ball *)malloc(
slouken@0
   284
		joystick->nballs * sizeof(struct hwdata_ball));
slouken@0
   285
	if ( joystick->hwdata->balls == NULL ) {
slouken@0
   286
		return(-1);
slouken@0
   287
	}
slouken@0
   288
	for ( i=0; i<joystick->nballs; ++i ) {
slouken@0
   289
		joystick->hwdata->balls[i].axis[0] = 0;
slouken@0
   290
		joystick->hwdata->balls[i].axis[1] = 0;
slouken@0
   291
	}
slouken@0
   292
	return(0);
slouken@0
   293
}
slouken@0
   294
slouken@0
   295
static SDL_bool ConfigJoystick(SDL_Joystick *joystick,
slouken@0
   296
			const char *name, const char *config)
slouken@0
   297
{
slouken@0
   298
	char cfg_name[128];
slouken@0
   299
	SDL_bool handled;
slouken@0
   300
slouken@0
   301
	if ( config == NULL ) {
slouken@0
   302
		return(SDL_FALSE);
slouken@0
   303
	}
slouken@0
   304
	strcpy(cfg_name, "");
slouken@0
   305
	if ( *config == '\'' ) {
slouken@0
   306
		sscanf(config, "'%[^']s'", cfg_name);
slouken@0
   307
		config += strlen(cfg_name)+2;
slouken@0
   308
	} else {
slouken@0
   309
		sscanf(config, "%s", cfg_name);
slouken@0
   310
		config += strlen(cfg_name);
slouken@0
   311
	}
slouken@0
   312
	handled = SDL_FALSE;
slouken@0
   313
	if ( strcmp(cfg_name, name) == 0 ) {
slouken@0
   314
		/* Get the number of axes, hats and balls for this joystick */
slouken@0
   315
		int joystick_axes = joystick->naxes;
slouken@0
   316
		sscanf(config, "%d %d %d", 
slouken@0
   317
			&joystick->naxes, &joystick->nhats, &joystick->nballs);
slouken@0
   318
slouken@0
   319
		/* Allocate the extra data for mapping them */
slouken@0
   320
		if ( joystick->nhats > 0 ) {
slouken@0
   321
			/* HACK: Analog hats map to only one axis */
slouken@0
   322
			if (joystick_axes == (joystick->naxes+joystick->nhats)){
slouken@0
   323
				joystick->hwdata->analog_hat = 1;
slouken@0
   324
			} else {
slouken@0
   325
				if ( allocate_hatdata(joystick) < 0 ) {
slouken@0
   326
					joystick->nhats = 0;
slouken@0
   327
				}
slouken@0
   328
				joystick->hwdata->analog_hat = 0;
slouken@0
   329
			}
slouken@0
   330
		}
slouken@0
   331
		if ( joystick->nballs > 0 ) {
slouken@0
   332
			if ( allocate_balldata(joystick) < 0 ) {
slouken@0
   333
				joystick->nballs = 0;
slouken@0
   334
			}
slouken@0
   335
		}
slouken@0
   336
		handled = SDL_TRUE;
slouken@0
   337
	}
slouken@0
   338
	return(handled);
slouken@0
   339
}
slouken@0
   340
slouken@0
   341
#ifdef USE_INPUT_EVENTS
slouken@0
   342
slouken@0
   343
static SDL_bool EV_ConfigJoystick(SDL_Joystick *joystick, int fd)
slouken@0
   344
{
slouken@0
   345
	int i;
slouken@0
   346
	unsigned long keybit[40];
slouken@0
   347
	unsigned long absbit[40];
slouken@0
   348
	unsigned long relbit[40];
slouken@0
   349
slouken@0
   350
	/* See if this device uses the new unified event API */
slouken@0
   351
	if ( (ioctl(fd, EVIOCGBIT(EV_KEY, sizeof(keybit)), keybit) >= 0) &&
slouken@0
   352
	     (ioctl(fd, EVIOCGBIT(EV_ABS, sizeof(absbit)), absbit) >= 0) &&
slouken@0
   353
	     (ioctl(fd, EVIOCGBIT(EV_REL, sizeof(relbit)), relbit) >= 0) ) {
slouken@0
   354
		joystick->hwdata->is_hid = SDL_TRUE;
slouken@0
   355
slouken@0
   356
		/* Get the number of buttons, axes, and other thingamajigs */
slouken@0
   357
		for ( i=BTN_JOYSTICK; i < KEY_MAX; ++i ) {
slouken@0
   358
			if ( test_bit(i, keybit) ) {
slouken@0
   359
#ifdef DEBUG_INPUT_EVENTS
slouken@0
   360
				printf("Joystick has button: 0x%x\n", i);
slouken@0
   361
#endif
slouken@0
   362
				joystick->hwdata->key_map[i-BTN_MISC] =
slouken@0
   363
						joystick->nbuttons;
slouken@0
   364
				++joystick->nbuttons;
slouken@0
   365
			}
slouken@0
   366
		}
slouken@0
   367
		for ( i=BTN_MISC; i < BTN_JOYSTICK; ++i ) {
slouken@0
   368
			if ( test_bit(i, keybit) ) {
slouken@0
   369
#ifdef DEBUG_INPUT_EVENTS
slouken@0
   370
				printf("Joystick has button: 0x%x\n", i);
slouken@0
   371
#endif
slouken@0
   372
				joystick->hwdata->key_map[i-BTN_MISC] =
slouken@0
   373
						joystick->nbuttons;
slouken@0
   374
				++joystick->nbuttons;
slouken@0
   375
			}
slouken@0
   376
		}
slouken@0
   377
		for ( i=0; i<ABS_MAX; ++i ) {
slouken@0
   378
			/* Skip hats */
slouken@0
   379
			if ( i == ABS_HAT0X ) {
slouken@0
   380
				i = ABS_HAT3Y;
slouken@0
   381
				continue;
slouken@0
   382
			}
slouken@0
   383
			if ( test_bit(i, absbit) ) {
slouken@0
   384
				int values[5];
slouken@0
   385
slouken@0
   386
				ioctl(fd, EVIOCGABS(i), values);
slouken@0
   387
#ifdef DEBUG_INPUT_EVENTS
slouken@0
   388
				printf("Joystick has absolute axis: %x\n", i);
slouken@0
   389
				printf("Values = { %d, %d, %d, %d, %d }\n",
slouken@0
   390
					values[0], values[1],
slouken@0
   391
					values[2], values[3], values[4]);
slouken@0
   392
#endif /* DEBUG_INPUT_EVENTS */
slouken@0
   393
				joystick->hwdata->abs_map[i] = joystick->naxes;
slouken@0
   394
				if ( values[1] == values[2] ) {
slouken@0
   395
				    joystick->hwdata->abs_correct[i].used = 0;
slouken@0
   396
				} else {
slouken@0
   397
				    joystick->hwdata->abs_correct[i].used = 1;
slouken@0
   398
				    joystick->hwdata->abs_correct[i].coef[0] =
slouken@0
   399
					(values[2] + values[1]) / 2 - values[4];
slouken@0
   400
				    joystick->hwdata->abs_correct[i].coef[1] =
slouken@0
   401
					(values[2] + values[1]) / 2 + values[4];
slouken@0
   402
				    joystick->hwdata->abs_correct[i].coef[2] =
slouken@0
   403
					(1 << 29) / ((values[2] - values[1]) / 2 - 2 * values[4]);
slouken@0
   404
				}
slouken@0
   405
				++joystick->naxes;
slouken@0
   406
			}
slouken@0
   407
		}
slouken@0
   408
		for ( i=ABS_HAT0X; i <= ABS_HAT3Y; i += 2 ) {
slouken@0
   409
			if ( test_bit(i, absbit) || test_bit(i+1, absbit) ) {
slouken@0
   410
#ifdef DEBUG_INPUT_EVENTS
slouken@0
   411
				printf("Joystick has hat %d\n",(i-ABS_HAT0X)/2);
slouken@0
   412
#endif
slouken@0
   413
				++joystick->nhats;
slouken@0
   414
			}
slouken@0
   415
		}
slouken@0
   416
		if ( test_bit(REL_X, relbit) || test_bit(REL_Y, relbit) ) {
slouken@0
   417
			++joystick->nballs;
slouken@0
   418
		}
slouken@0
   419
slouken@0
   420
		/* Allocate data to keep track of these thingamajigs */
slouken@0
   421
		if ( joystick->nhats > 0 ) {
slouken@0
   422
			if ( allocate_hatdata(joystick) < 0 ) {
slouken@0
   423
				joystick->nhats = 0;
slouken@0
   424
			}
slouken@0
   425
		}
slouken@0
   426
		if ( joystick->nballs > 0 ) {
slouken@0
   427
			if ( allocate_balldata(joystick) < 0 ) {
slouken@0
   428
				joystick->nballs = 0;
slouken@0
   429
			}
slouken@0
   430
		}
slouken@0
   431
	}
slouken@0
   432
	return(joystick->hwdata->is_hid);
slouken@0
   433
}
slouken@0
   434
slouken@0
   435
#endif /* USE_INPUT_EVENTS */
slouken@0
   436
slouken@0
   437
#endif /* FANCY_HATS_AND_BALLS */
slouken@0
   438
slouken@0
   439
/* Function to open a joystick for use.
slouken@0
   440
   The joystick to open is specified by the index field of the joystick.
slouken@0
   441
   This should fill the nbuttons and naxes fields of the joystick structure.
slouken@0
   442
   It returns 0, or -1 if there is an error.
slouken@0
   443
 */
slouken@0
   444
int SDL_SYS_JoystickOpen(SDL_Joystick *joystick)
slouken@0
   445
{
slouken@0
   446
#ifdef FANCY_HATS_AND_BALLS
slouken@0
   447
	const char *name;
slouken@0
   448
	int i;
slouken@0
   449
#endif
slouken@0
   450
	int fd;
slouken@0
   451
	unsigned char n;
slouken@0
   452
slouken@0
   453
	/* Open the joystick and set the joystick file descriptor */
slouken@0
   454
	fd = open(SDL_joylist[joystick->index], O_RDONLY, 0);
slouken@0
   455
	if ( fd < 0 ) {
slouken@0
   456
		SDL_SetError("Unable to open %s\n",
slouken@0
   457
		             SDL_joylist[joystick->index]);
slouken@0
   458
		return(-1);
slouken@0
   459
	}
slouken@0
   460
	joystick->hwdata = (struct joystick_hwdata *)
slouken@0
   461
	                   malloc(sizeof(*joystick->hwdata));
slouken@0
   462
	if ( joystick->hwdata == NULL ) {
slouken@0
   463
		SDL_OutOfMemory();
slouken@0
   464
		close(fd);
slouken@0
   465
		return(-1);
slouken@0
   466
	}
slouken@0
   467
	memset(joystick->hwdata, 0, sizeof(*joystick->hwdata));
slouken@0
   468
	joystick->hwdata->fd = fd;
slouken@0
   469
slouken@0
   470
	/* Set the joystick to non-blocking read mode */
slouken@0
   471
	fcntl(fd, F_SETFL, O_NONBLOCK);
slouken@0
   472
slouken@0
   473
	/* Get the number of buttons and axes on the joystick */
slouken@0
   474
#ifdef USE_INPUT_EVENTS
slouken@0
   475
	if ( ! EV_ConfigJoystick(joystick, fd) )
slouken@0
   476
#endif
slouken@0
   477
	{
slouken@0
   478
		if ( ioctl(fd, JSIOCGAXES, &n) < 0 ) {
slouken@0
   479
			joystick->naxes = 2;
slouken@0
   480
		} else {
slouken@0
   481
			joystick->naxes = n;
slouken@0
   482
		}
slouken@0
   483
		if ( ioctl(fd, JSIOCGBUTTONS, &n) < 0 ) {
slouken@0
   484
			joystick->nbuttons = 2;
slouken@0
   485
		} else {
slouken@0
   486
			joystick->nbuttons = n;
slouken@0
   487
		}
slouken@0
   488
#ifdef FANCY_HATS_AND_BALLS
slouken@0
   489
		/* Check for special joystick support */
slouken@0
   490
		name = SDL_SYS_JoystickName(joystick->index);
slouken@0
   491
		for ( i=0; special_joysticks[i]; ++i ) {
slouken@0
   492
			if (ConfigJoystick(joystick,name,special_joysticks[i])){
slouken@0
   493
				break;
slouken@0
   494
			}
slouken@0
   495
		}
slouken@0
   496
		if ( special_joysticks[i] == NULL ) {
slouken@0
   497
			ConfigJoystick(joystick, name,
slouken@0
   498
					getenv("SDL_LINUX_JOYSTICK"));
slouken@0
   499
		}
slouken@0
   500
#endif /* FANCY_HATS_AND_BALLS */
slouken@0
   501
	}
slouken@0
   502
	return(0);
slouken@0
   503
}
slouken@0
   504
slouken@0
   505
static __inline__
slouken@0
   506
void HandleHat(SDL_Joystick *stick, Uint8 hat, int axis, int value)
slouken@0
   507
{
slouken@0
   508
	struct hwdata_hat *the_hat;
slouken@0
   509
	const Uint8 position_map[3][3] = {
slouken@0
   510
		{ SDL_HAT_LEFTUP, SDL_HAT_UP, SDL_HAT_RIGHTUP },
slouken@0
   511
		{ SDL_HAT_LEFT, SDL_HAT_CENTERED, SDL_HAT_RIGHT },
slouken@0
   512
		{ SDL_HAT_LEFTDOWN, SDL_HAT_DOWN, SDL_HAT_RIGHTDOWN }
slouken@0
   513
	};
slouken@0
   514
slouken@0
   515
	the_hat = &stick->hwdata->hats[hat];
slouken@0
   516
	if ( value < 0 ) {
slouken@0
   517
		value = 0;
slouken@0
   518
	} else
slouken@0
   519
	if ( value == 0 ) {
slouken@0
   520
		value = 1;
slouken@0
   521
	} else
slouken@0
   522
	if ( value > 0 ) {
slouken@0
   523
		value = 2;
slouken@0
   524
	}
slouken@0
   525
	if ( value != the_hat->axis[axis] ) {
slouken@0
   526
		the_hat->axis[axis] = value;
slouken@0
   527
		SDL_PrivateJoystickHat(stick, hat,
slouken@0
   528
			position_map[the_hat->axis[1]][the_hat->axis[0]]);
slouken@0
   529
	}
slouken@0
   530
}
slouken@0
   531
slouken@0
   532
/* This was necessary for the Wingman Extreme Analog joystick */
slouken@0
   533
static __inline__
slouken@0
   534
void HandleAnalogHat(SDL_Joystick *stick, Uint8 hat, int value)
slouken@0
   535
{
slouken@0
   536
	const Uint8 position_map[] = {
slouken@0
   537
		SDL_HAT_UP,
slouken@0
   538
		SDL_HAT_RIGHT,
slouken@0
   539
		SDL_HAT_DOWN,
slouken@0
   540
		SDL_HAT_LEFT,
slouken@0
   541
		SDL_HAT_CENTERED
slouken@0
   542
	};
slouken@0
   543
	SDL_PrivateJoystickHat(stick, hat, position_map[(value/16000)+2]);
slouken@0
   544
}
slouken@0
   545
slouken@0
   546
static __inline__
slouken@0
   547
void HandleBall(SDL_Joystick *stick, Uint8 ball, int axis, int value)
slouken@0
   548
{
slouken@0
   549
	stick->hwdata->balls[ball].axis[axis] += value;
slouken@0
   550
}
slouken@0
   551
slouken@0
   552
/* Function to update the state of a joystick - called as a device poll.
slouken@0
   553
 * This function shouldn't update the joystick structure directly,
slouken@0
   554
 * but instead should call SDL_PrivateJoystick*() to deliver events
slouken@0
   555
 * and update joystick device state.
slouken@0
   556
 */
slouken@0
   557
static __inline__ void JS_HandleEvents(SDL_Joystick *joystick)
slouken@0
   558
{
slouken@0
   559
	struct js_event events[32];
slouken@0
   560
	int i, len;
slouken@0
   561
	Uint8 other_axis;
slouken@0
   562
slouken@0
   563
	while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
slouken@0
   564
		len /= sizeof(events[0]);
slouken@0
   565
		for ( i=0; i<len; ++i ) {
slouken@0
   566
			switch (events[i].type & ~JS_EVENT_INIT) {
slouken@0
   567
			    case JS_EVENT_AXIS:
slouken@0
   568
				if ( events[i].number < joystick->naxes ) {
slouken@0
   569
					SDL_PrivateJoystickAxis(joystick,
slouken@0
   570
				           events[i].number, events[i].value);
slouken@0
   571
					break;
slouken@0
   572
				}
slouken@0
   573
				events[i].number -= joystick->naxes;
slouken@0
   574
				if ( joystick->hwdata->analog_hat ) {
slouken@0
   575
					other_axis = events[i].number;
slouken@0
   576
					if ( other_axis < joystick->nhats ) {
slouken@0
   577
						HandleAnalogHat(joystick, other_axis,
slouken@0
   578
							events[i].value);
slouken@0
   579
						break;
slouken@0
   580
					}
slouken@0
   581
				} else {
slouken@0
   582
					other_axis = (events[i].number / 2);
slouken@0
   583
					if ( other_axis < joystick->nhats ) {
slouken@0
   584
						HandleHat(joystick, other_axis,
slouken@0
   585
							events[i].number%2,
slouken@0
   586
							events[i].value);
slouken@0
   587
						break;
slouken@0
   588
					}
slouken@0
   589
				}
slouken@0
   590
				events[i].number -= joystick->nhats*2;
slouken@0
   591
				other_axis = (events[i].number / 2);
slouken@0
   592
				if ( other_axis < joystick->nballs ) {
slouken@0
   593
					HandleBall(joystick, other_axis,
slouken@0
   594
						events[i].number%2,
slouken@0
   595
						events[i].value);
slouken@0
   596
					break;
slouken@0
   597
				}
slouken@0
   598
				break;
slouken@0
   599
			    case JS_EVENT_BUTTON:
slouken@0
   600
				SDL_PrivateJoystickButton(joystick,
slouken@0
   601
				           events[i].number, events[i].value);
slouken@0
   602
				break;
slouken@0
   603
			    default:
slouken@0
   604
				/* ?? */
slouken@0
   605
				break;
slouken@0
   606
			}
slouken@0
   607
		}
slouken@0
   608
	}
slouken@0
   609
}
slouken@0
   610
#ifdef USE_INPUT_EVENTS
slouken@0
   611
static __inline__ int EV_AxisCorrect(SDL_Joystick *joystick, int which, int value)
slouken@0
   612
{
slouken@0
   613
	struct axis_correct *correct;
slouken@0
   614
slouken@0
   615
	correct = &joystick->hwdata->abs_correct[which];
slouken@0
   616
	if ( correct->used ) {
slouken@0
   617
		if ( value > correct->coef[0] ) {
slouken@0
   618
			if ( value < correct->coef[1] ) {
slouken@0
   619
				return 0;
slouken@0
   620
			}
slouken@0
   621
			value -= correct->coef[1];
slouken@0
   622
		} else {
slouken@0
   623
			value -= correct->coef[0];
slouken@0
   624
		}
slouken@0
   625
		value *= correct->coef[2];
slouken@0
   626
		value >>= 14;
slouken@0
   627
	}
slouken@0
   628
	/* Clamp and return */
slouken@0
   629
	if ( value < -32767 ) {
slouken@0
   630
		value = -32767;
slouken@0
   631
	} else
slouken@0
   632
	if ( value > 32767 ) {
slouken@0
   633
		value = 32767;
slouken@0
   634
	}
slouken@0
   635
	return value;
slouken@0
   636
}
slouken@0
   637
slouken@0
   638
static __inline__ void EV_HandleEvents(SDL_Joystick *joystick)
slouken@0
   639
{
slouken@0
   640
	struct input_event events[32];
slouken@0
   641
	int i, len;
slouken@0
   642
	int code;
slouken@0
   643
slouken@0
   644
	while ((len=read(joystick->hwdata->fd, events, (sizeof events))) > 0) {
slouken@0
   645
		len /= sizeof(events[0]);
slouken@0
   646
		for ( i=0; i<len; ++i ) {
slouken@0
   647
			code = events[i].code;
slouken@0
   648
			switch (events[i].type) {
slouken@0
   649
			    case EV_KEY:
slouken@0
   650
				if ( code >= BTN_MISC ) {
slouken@0
   651
					code -= BTN_MISC;
slouken@0
   652
					SDL_PrivateJoystickButton(joystick,
slouken@0
   653
				           joystick->hwdata->key_map[code],
slouken@0
   654
					   events[i].value);
slouken@0
   655
				}
slouken@0
   656
				break;
slouken@0
   657
			    case EV_ABS:
slouken@0
   658
				switch (code) {
slouken@0
   659
				    case ABS_HAT0X:
slouken@0
   660
				    case ABS_HAT0Y:
slouken@0
   661
				    case ABS_HAT1X:
slouken@0
   662
				    case ABS_HAT1Y:
slouken@0
   663
				    case ABS_HAT2X:
slouken@0
   664
				    case ABS_HAT2Y:
slouken@0
   665
				    case ABS_HAT3X:
slouken@0
   666
				    case ABS_HAT3Y:
slouken@0
   667
					code -= ABS_HAT0X;
slouken@0
   668
					HandleHat(joystick, code/2, code%2,
slouken@0
   669
							events[i].value);
slouken@0
   670
					break;
slouken@0
   671
				    default:
slouken@0
   672
					events[i].value = EV_AxisCorrect(joystick, code, events[i].value);
slouken@0
   673
					SDL_PrivateJoystickAxis(joystick,
slouken@0
   674
				           joystick->hwdata->abs_map[code],
slouken@0
   675
					   events[i].value);
slouken@0
   676
					break;
slouken@0
   677
				}
slouken@0
   678
				break;
slouken@0
   679
			    case EV_REL:
slouken@0
   680
				switch (code) {
slouken@0
   681
				    case REL_X:
slouken@0
   682
				    case REL_Y:
slouken@0
   683
					code -= REL_X;
slouken@0
   684
					HandleBall(joystick, code/2, code%2,
slouken@0
   685
							events[i].value);
slouken@0
   686
					break;
slouken@0
   687
				    default:
slouken@0
   688
					break;
slouken@0
   689
				}
slouken@0
   690
				break;
slouken@0
   691
			    default:
slouken@0
   692
				break;
slouken@0
   693
			}
slouken@0
   694
		}
slouken@0
   695
	}
slouken@0
   696
}
slouken@0
   697
#endif /* USE_INPUT_EVENTS */
slouken@0
   698
slouken@0
   699
void SDL_SYS_JoystickUpdate(SDL_Joystick *joystick)
slouken@0
   700
{
slouken@0
   701
	int i;
slouken@0
   702
	
slouken@0
   703
#ifdef USE_INPUT_EVENTS
slouken@0
   704
	if ( joystick->hwdata->is_hid )
slouken@0
   705
		EV_HandleEvents(joystick);
slouken@0
   706
	else
slouken@0
   707
#endif
slouken@0
   708
		JS_HandleEvents(joystick);
slouken@0
   709
slouken@0
   710
	/* Deliver ball motion updates */
slouken@0
   711
	for ( i=0; i<joystick->nballs; ++i ) {
slouken@0
   712
		int xrel, yrel;
slouken@0
   713
slouken@0
   714
		xrel = joystick->hwdata->balls[i].axis[0];
slouken@0
   715
		yrel = joystick->hwdata->balls[i].axis[1];
slouken@0
   716
		if ( xrel || yrel ) {
slouken@0
   717
			joystick->hwdata->balls[i].axis[0] = 0;
slouken@0
   718
			joystick->hwdata->balls[i].axis[1] = 0;
slouken@0
   719
			SDL_PrivateJoystickBall(joystick, (Uint8)i, xrel, yrel);
slouken@0
   720
		}
slouken@0
   721
	}
slouken@0
   722
}
slouken@0
   723
slouken@0
   724
/* Function to close a joystick after use */
slouken@0
   725
void SDL_SYS_JoystickClose(SDL_Joystick *joystick)
slouken@0
   726
{
slouken@0
   727
	if ( joystick->hwdata ) {
slouken@0
   728
		close(joystick->hwdata->fd);
slouken@0
   729
		if ( joystick->hwdata->hats ) {
slouken@0
   730
			free(joystick->hwdata->hats);
slouken@0
   731
		}
slouken@0
   732
		if ( joystick->hwdata->balls ) {
slouken@0
   733
			free(joystick->hwdata->balls);
slouken@0
   734
		}
slouken@0
   735
		free(joystick->hwdata);
slouken@0
   736
		joystick->hwdata = NULL;
slouken@0
   737
	}
slouken@0
   738
}
slouken@0
   739
slouken@0
   740
/* Function to perform any system-specific joystick related cleanup */
slouken@0
   741
void SDL_SYS_JoystickQuit(void)
slouken@0
   742
{
slouken@0
   743
	int i;
slouken@0
   744
slouken@0
   745
	for ( i=0; SDL_joylist[i]; ++i ) {
slouken@0
   746
		free(SDL_joylist[i]);
slouken@0
   747
	}
slouken@0
   748
	SDL_joylist[0] = NULL;
slouken@0
   749
}
slouken@0
   750