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