Filewatcher File Search
FTP Search
  
Directory 
  
Content Search 
   
pkg://joystick-1.2.15-2.src.rpm:94072/joystick-1.2.15.tar.gz  info  downloads

joystick-1.2.15/ 40755    766    144           0  7023722206  12412 5ustar  vojtechusersjoystick-1.2.15/Makefile100644    766    144       14230  7023722151  14166 0ustar  vojtechusers#
# Makefile for Linux joystick driver v1.2
#
# (c) 1998-1999 Vojtech Pavlik
#
# Sponsored by SuSE
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
#
# Should you need to contact me, the author, you can do so either by
# e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
# Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
#
#
# Edit the options below to suit your needs
#

CC		= gcc

CPPFLAGS	= -I.#						# for joystick.h

CFLAGS		= -O2 -Wall -pipe -m486 -fomit-frame-pointer#	# i386
# CFLAGS	= -O2 -Wall -pipe -m68020 -ffixed-a2#		# m68k
# CFLAGS	= -O2 -Wall -pipe -fomit-frame-pointer -ffixed-8# Alpha
# CFLAGS	= -O2 -Wall -pipe#				# Generic

MODFLAGS	= -D__KERNEL__ -DMODULE#			# Normal modules
#MODFLAGS	= -D__KERNEL__ -DMODULE -DMODVERSIONS\
#		  -include /usr/src/linux/include/linux/modversions.h # Versioned modules

DRIVERS		= joy-analog.o joy-sidewinder.o joy-logitech.o\
		  joy-assassin.o joy-gravis.o joy-lightning.o\
		  joy-thrustmaster.o joy-creative.o joy-console.o\
		  joy-db9.o joy-turbografx.o joy-spaceorb.o\
		  joy-spaceball.o joy-magellan.o joy-warrior.o\
		  joy-pci.o#					# PC drivers
# DRIVERS	= joy-amiga.o#					# Amiga driver

MODDIR		= /lib/modules/preferred/misc#			# RedHat location
# MODDIR	= /lib/modules/current/misc#			# For some others?

PROGRAMS	= jstest jscal jsattach 

#
# Nothing should need to be changed below this line
#

JOYPATH		:= $(shell pwd)
JOYDIR		:= $(shell basename "$(JOYPATH)")
JOYVER		:= $(shell expr "$(JOYDIR)" : "joystick-\(.*\)")
JOYOPRE		:= $(shell if [ -f .prerelease ]; then cat .prerelease; else echo 0; fi)
JOYPRE		:= $(shell expr $(JOYOPRE) + 1)

compile: joystick.o $(DRIVERS) $(PROGRAMS)

install: compile
	mkdir -p $(MODDIR)
	rm -f $(MODDIR)/joy*.o
	cp joy*.o $(MODDIR)
	/sbin/depmod -a
	install -m 644 joystick.h /usr/include/linux
	install -m 755 jscal /usr/local/bin
	install -m 755 jstest /usr/local/bin
	install -m 755 jsattach /usr/local/bin
	install -m 644 jscal.1 /usr/local/man/man1
	install -m 644 jstest.1 /usr/local/man/man1
	install -m 644 jsattach.1 /usr/local/man/man1

joystick.o: joystick.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -DEXPORT_SYMTAB -c joystick.c -o joystick.o

joy-analog.o: joy-analog.c joy-analog.h joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-analog.c -o joy-analog.o

joy-sidewinder.o: joy-sidewinder.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-sidewinder.c -o joy-sidewinder.o

joy-logitech.o: joy-logitech.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-logitech.c -o joy-logitech.o

joy-gravis.o: joy-gravis.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-gravis.c -o joy-gravis.o

joy-assassin.o: joy-assassin.c joy-analog.h joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-assassin.c -o joy-assassin.o

joy-thrustmaster.o: joy-thrustmaster.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-thrustmaster.c -o joy-thrustmaster.o

joy-creative.o: joy-creative.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-creative.c -o joy-creative.o

joy-lightning.o: joy-lightning.c joy-analog.h joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-lightning.c -o joy-lightning.o

joy-pci.o: joy-pci.c joy-analog.h joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-pci.c -o joy-pci.o

joy-amiga.o: joy-amiga.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-amiga.c -o joy-amiga.o

joy-console.o: joy-console.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-console.c -o joy-console.o

joy-db9.o: joy-db9.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-db9.c -o joy-db9.o

joy-turbografx.o: joy-turbografx.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-turbografx.c -o joy-turbografx.o

joy-spaceorb.o: joy-spaceorb.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-spaceorb.c -o joy-spaceorb.o

joy-spaceball.o: joy-spaceball.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-spaceball.c -o joy-spaceball.o

joy-magellan.o: joy-magellan.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-magellan.c -o joy-magellan.o

joy-warrior.o: joy-warrior.c joystick.h
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joy-warrior.c -o joy-warrior.o

joydump: joydump.o
	
joydump.o: joydump.c
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c joydump.c -o joydump.o

legacy.o: legacy.c
	$(CC) $(CFLAGS) $(CPPFLAGS) $(MODFLAGS) -c legacy.c -o legacy.o

jscal: jscal.o
	$(CC) $(cflags) $(cppflags) -lm $^ -o $@

jstest: jstest.o
	$(CC) $(cflags) $(cppflags) $^ -o $@

devs:
	-$(RM) /dev/js0 /dev/js1 /dev/js2 /dev/js3
	mknod /dev/js0 c 15 0
	mknod /dev/js1 c 15 1
	mknod /dev/js2 c 15 2
	mknod /dev/js3 c 15 3

clean:
	-$(RM) *.o *.swp $(PROGRAMS) *.orig *.rej map

dist: clean
	( \
	  rm -f *.diff ;\
	  cd .. ;\
	  mkdir -p arch ;\
	  rm -f arch/$(JOYDIR).tar.gz ;\
	  tar czf arch/$(JOYDIR).tar.gz $(JOYDIR) ;\
	)

bumprel: clean
	echo $(JOYPRE) > .prerelease

pre: compile bumprel dist
	( \
	  cd .. ;\
	  mv arch/$(JOYDIR).tar.gz arch/devel/joystick-pre-$(JOYVER)-$(JOYPRE).tar.gz ;\
	  scp arch/devel/joystick-pre-$(JOYVER)-$(JOYPRE).tar.gz atrey:joystick/devel ;\
	  scp arch/devel/joystick-pre-$(JOYVER)-$(JOYPRE).tar.gz suse-ftp:joystick/devel ;\
	)

relclean: clean
	$(RM) .prerelease

release: compile relclean dist
	( \
	  echo 0 > .prerelease ;\
	  cd .. ;\
	  scp arch/$(JOYDIR).tar.gz atrey:joystick ;\
	  scp arch/$(JOYDIR).tar.gz suse-ftp:joystick ;\
	  ssh atrey rm -f "joystick/devel/*" &\
	  ssh suse-ftp rm -f "joystick/devel/*" &\
	)

jstest.o: jstest.c joystick.h
jscal.o: jscal.c joystick.h
jsattach.o: jsattach.c
joystick-1.2.15/joy-console.c100644    766    144       51503  7022237132  15136 0ustar  vojtechusers/*
 *  joy-console.c  Version 0.14V
 *
 *  Copyright (c) 1998 Andree Borrmann
 *  Copyright (c) 1999 John Dahlstrom
 *  Copyright (c) 1999 David Kuder
 *  Copyright (c) 1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads 
 * connected via parallel port. Up to five such controllers 
 * can be connected to one parallel port.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>


MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_console, "2-6i");
MODULE_PARM(js_console_2,"2-6i");
MODULE_PARM(js_console_3,"2-6i");


#define JS_NO_PAD	0
#define JS_SNES_PAD	1
#define JS_NES_PAD	2
#define JS_NES4_PAD	3
#define JS_MULTI_STICK	4
#define JS_MULTI2_STICK	5
#define JS_PSX_PAD	6
#define JS_N64_PAD	7	
#define JS_N64_PAD_DPP	8	/* DirectPad Pro compatible layout */
 
#define JS_MAX_PAD	JS_N64_PAD_DPP

struct js_console_info {
	struct pardevice *port;	/* parport device */
	int pads;		/* total number of pads */
	int pad_to_device[5];   /* pad to js device mapping (js0, js1, etc.) */
	int snes;		/* SNES pads */
	int nes;		/* NES pads */
	int n64;		/* N64 pads */
	int n64_dpp;		/* bits indicate N64 pads treated 14 button, 2 axis */
	int multi;		/* Multi joysticks */
	int multi2;		/* Multi joysticks with 2 buttons */
	int psx;		/* PSX controllers */
};

static struct js_port* js_console_port = NULL;

static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 };
static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 };

static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };

/*
 * NES/SNES support.
 */

#define JS_NES_DELAY	6	/* Delay between bits - 6us */

#define JS_NES_LENGTH	8	/* The NES pads use 8 bits of data */

#define JS_NES_A	0
#define JS_NES_B	1
#define JS_NES_START	2
#define JS_NES_SELECT	3
#define JS_NES_UP	4
#define JS_NES_DOWN	5
#define JS_NES_LEFT	6
#define JS_NES_RIGHT	7

#define JS_SNES_LENGTH	12	/* The SNES true length is 16, but the last 4 bits are unused */

#define JS_SNES_B	0
#define JS_SNES_Y	1
#define JS_SNES_START	2
#define JS_SNES_SELECT	3
#define JS_SNES_UP	4
#define JS_SNES_DOWN	5
#define JS_SNES_LEFT	6
#define JS_SNES_RIGHT	7
#define JS_SNES_A	8
#define JS_SNES_X	9
#define JS_SNES_L	10
#define JS_SNES_R	11

#define JS_NES_POWER	0xfc
#define JS_NES_CLOCK	0x01
#define JS_NES_LATCH	0x02

/*
 * js_nes_read_packet() reads a NES/SNES packet.
 * Each pad uses one bit per byte. So all pads connected to
 * this port are read in parallel.
 */

static void js_nes_read_packet(struct js_console_info *info, int length, unsigned char *data)
{
	int i;

	JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port);
	udelay(JS_NES_DELAY * 2);
	JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);

	for (i = 0; i < length; i++) {
		udelay(JS_NES_DELAY);
		JS_PAR_DATA_OUT(JS_NES_POWER, info->port);
		data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
		udelay(JS_NES_DELAY);
		JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
	}
}

/*
 * N64 support.
 */

#define JS_N64_A	0
#define JS_N64_B	1
#define JS_N64_Z	2
#define JS_N64_START	3
#define JS_N64_UP	4
#define JS_N64_DOWN	5
#define JS_N64_LEFT	6
#define JS_N64_RIGHT	7
#define JS_N64_UNUSED1	8
#define JS_N64_UNUSED2	9
#define JS_N64_L	10
#define JS_N64_R	11
#define JS_N64_CU	12
#define JS_N64_CD	13
#define JS_N64_CL	14
#define JS_N64_CR	15
#define JS_N64_X	23			/* 16 - 23, signed 8-bit int */
#define JS_N64_Y	31			/* 24 - 31, signed 8-bit int */

#define JS_N64_LENGTH		32		/* N64 bit length, not including stop bit */
#define JS_N64_REQUEST_LENGTH	37		/* transmit request sequence is 9 bits long */
#define JS_N64_DELAY		133		/* delay between transmit request, and response ready (us) */
#define JS_N64_REQUEST		0x1dd1111111ULL /* the request data command (encoded for 000000011) */
#define JS_N64_DWS		3		/* delay between write segments (required for sound playback because of ISA DMA) */
						/* JS_N64_DWS > 24 is known to fail */ 
#define JS_N64_POWER_W		0xe2		/* power during write (transmit request) */
#define JS_N64_POWER_R		0xfd		/* power during read */
#define JS_N64_OUT		0x1d		/* output bits to the 4 pads */
						/* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
						/* in JS_N64_OUT is pulled low on the output port (by any routine) for more */
						/* than 0.123 consecutive ms */
#define JS_N64_CLOCK		0x02		/* clock bits for read */

/* 
 * js_n64_read_packet() reads an N64 packet. 
 * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
 */

static void js_n64_read_packet(struct js_console_info *info, unsigned char *data)
{
	int i;
	unsigned long flags;

/*
 * Request the pad to transmit data
 */

	save_flags(flags);
	cli();
	for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) {
		JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port);
		udelay(JS_N64_DWS);
	}
	restore_flags(flags);

/*
 * Wait for the pad response to be loaded into the 33-bit register of the adapter
 */

	udelay(JS_N64_DELAY);

/*
 * Grab data (ignoring the last bit, which is a stop bit)
 */

	for (i = 0; i < JS_N64_LENGTH; i++) {
		JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port);
		data[i] = JS_PAR_STATUS(info->port);
		JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port);
	 }

/*
 * We must wait ~0.2 ms here for the controller to reinitialize before the next read request.
 * No worries as long as js_console_read is polled less frequently than this.
 */

}

/*
 * Multisystem joystick support
 */

#define JS_MULTI_LENGTH		5	/* Multi system joystick packet lenght is 5 */
#define JS_MULTI2_LENGTH	6	/* One more bit for one more button */

#define JS_MULTI_UP		0
#define JS_MULTI_DOWN		1
#define JS_MULTI_LEFT		2
#define JS_MULTI_RIGHT		3
#define JS_MULTI_BUTTON		4
#define JS_MULTI_BUTTON2	5

/*
 * js_multi_read_packet() reads a Multisystem joystick packet.
 */

static void js_multi_read_packet(struct js_console_info *info, int length, unsigned char *data)
{
	int i;

	for (i = 0; i < length; i++) {
		JS_PAR_DATA_OUT(~(1 << i), info->port);
		data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
		printk(" %d", data[i]);
	}
	printk("\n");
}

/*
 * PSX support
 */

#define JS_PSX_DELAY	10
#define JS_PSX_LENGTH	8    /* talk to the controller in bytes */

#define JS_PSX_NORMAL	0x41 /* Standard Digital controller */
#define JS_PSX_NEGCON	0x23 /* NegCon pad */
#define JS_PSX_MOUSE	0x12 /* PSX Mouse */
#define JS_PSX_ANALOGR	0x73 /* Analog controller in Red mode */
#define JS_PSX_ANALOGG	0x53 /* Analog controller in Green mode */

#define JS_PSX_JOYR	0x02 /* These are for the Analog/Dual Shock controller in RED mode */
#define JS_PSX_JOYL	0x04 /* I'm not sure the exact purpose of these but its in the docs */
#define JS_PSX_SELBUT	0x01 /* Standard buttons on almost all PSX controllers. */
#define JS_PSX_START	0x08
#define JS_PSX_UP	0x10 /* Digital direction pad */
#define JS_PSX_RIGHT	0x20
#define JS_PSX_DOWN	0x40
#define JS_PSX_LEFT	0x80

#define JS_PSX_CLOCK	0x04 /* Pin 3 */
#define JS_PSX_COMMAND	0x01 /* Pin 1 */
#define JS_PSX_POWER	0xf8 /* Pins 5-9 */
#define JS_PSX_SELECT	0x02 /* Pin 2 */
#define JS_PSX_NOPOWER  0x04

/*
 * js_psx_command() writes 8bit command and reads 8bit data from
 * the psx pad.
 */

static int js_psx_command(struct js_console_info *info, int b)
{
	int i, cmd, ret=0;

	cmd = (b&1)?JS_PSX_COMMAND:0;
	for (i=0; i<8; i++) {
		JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port);
		udelay(JS_PSX_DELAY);
		ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<<i) : 0;
		cmd = (b&1)?JS_PSX_COMMAND:0;
		JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
		udelay(JS_PSX_DELAY);
		b >>= 1;
	}
	return ret;
}

/*
 * js_psx_read_packet() reads a whole psx packet and returns
 * device identifier code.
 */

static int js_psx_read_packet(struct js_console_info *info, int length, unsigned char *data)
{
	int i, ret;
	unsigned long flags;

	__save_flags(flags);
	__cli();

	JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);

	JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port);	/* Select pad */
	udelay(JS_PSX_DELAY*2);
	js_psx_command(info, 0x01);					/* Access pad */
	ret = js_psx_command(info, 0x42);				/* Get device id */
	if (js_psx_command(info, 0)=='Z')				/* okay? */
		for (i=0; i<length; i++)
			data[i]=js_psx_command(info, 0);
	else ret = -1;

	JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
	__restore_flags(flags);

	return ret;
}


/*
 * js_console_read() reads and analyzes console pads data.
 */

#define JS_MAX_LENGTH JS_N64_LENGTH

static int js_console_read(void *xinfo, int **axes, int **buttons)
{
	struct js_console_info *info = xinfo;
	unsigned char data[JS_MAX_LENGTH];

	int i, j, s;
	int n = 0;

/*
 * NES and SNES pads
 */

	if (info->nes || info->snes) {

		js_nes_read_packet(info, info->snes ? JS_SNES_LENGTH : JS_NES_LENGTH, data);

		for (i = 0; i < 5; i++) {
			s = status_bit[i];
			n = info->pad_to_device[i];
			if (info->nes & s) {
				axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
				axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP]  &s?1:0);

				buttons[n][0] = (data[JS_NES_A]    &s?1:0) | (data[JS_NES_B]     &s?2:0)
					      | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0);
			} else
			if (info->snes & s) {
				axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
				axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP]  &s?1:0);

				buttons[n][0] = (data[JS_SNES_A]    &s?0x01:0) | (data[JS_SNES_B]     &s?0x02:0)
					      | (data[JS_SNES_X]    &s?0x04:0) | (data[JS_SNES_Y]     &s?0x08:0)
					      | (data[JS_SNES_L]    &s?0x10:0) | (data[JS_SNES_R]     &s?0x20:0)
					      | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0);
			}
		}
	}

/*
 * N64 pads
 */

	if (info->n64) {
		if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) {
					/* SNES/NES compatibility */
			udelay(240);	/* 200 us delay + 20% tolerance */
		}

		js_n64_read_packet(info, data);

		for (i = 0; i < 5; i++) {
			s = status_bit[i];
			n = info->pad_to_device[i];
			if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) {

				buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0) 
						| ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0) 
						| ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0)
						| ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s)   ? 0x80:0)
						| ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s)   ?0x200:0) );

				if (info->n64_dpp & s) { 
					buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0)
							|((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0);
				} else {
					axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0);
					axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP]  &s?1:0);
				}

						/* build int from bits of signed 8-bit int's */
				j = 7;
				axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0;
				axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0;
				while ( j-- > 0 ) {
					axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0; 
					axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0; 
				}
						/* flip Y-axis for conformity */
				axes[n][1] = -axes[n][1];

			}
		}
	}

/*
 * Multi and Multi2 joysticks
 */

	if (info->multi || info->multi2) {

		js_multi_read_packet(info, info->multi2 ? JS_MULTI2_LENGTH : JS_MULTI_LENGTH, data);

		for (i = 0; i < 5; i++) {
			s = status_bit[i];
			n = info->pad_to_device[i];
			if (info->multi & s) {
				axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
				axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP]  &s?1:0);

				buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0;
			} else
			if (info->multi2 & s) {
				axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
				axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP]  &s?1:0);

				buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0;
			}
		}
	}

/*
 * PSX controllers
 */

	if (info->psx) {

		for ( i = 0; i < 5; i++ )
	       		if ( info->psx & status_bit[i] ) {
				n = info->pad_to_device[i];
				break;
			}

		buttons[n][0] = 0;

 		switch (js_psx_read_packet(info, 6, data)) {

			case JS_PSX_ANALOGR:

				buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400);

			case JS_PSX_ANALOGG:
	
				axes[n][2] = data[2];
				axes[n][3] = data[3];
				axes[n][4] = data[4];
				axes[n][5] = data[5];

			case JS_PSX_NORMAL:
			case JS_PSX_NEGCON:

				axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
				axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP  ?0:1);

				buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
					(data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
		
				break;

		}
	}

	return 0;
}

/*
 * open callback: claim parport.
 */

int js_console_open(struct js_dev *dev)
{
	struct js_console_info *info = dev->port->info;
	if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * close callback: release parport
 */

int js_console_close(struct js_dev *dev)
{
	struct js_console_info *info = dev->port->info;
	MOD_DEC_USE_COUNT;
	if (!MOD_IN_USE) parport_release(info->port);
	return 0;
}

#ifdef MODULE
void cleanup_module(void)
{
	struct js_console_info *info;
	int i;

	while (js_console_port) {
		for (i = 0; i < js_console_port->ndevs; i++)
			if (js_console_port->devs[i])
				js_unregister_device(js_console_port->devs[i]);
		info = js_console_port->info;
		parport_unregister_device(info->port);
		js_console_port = js_unregister_port(js_console_port);
	}
}
#endif

/*
 * js_console_init_corr() initializes correction values of
 * console gamepads.
 */

static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr)
{
	int i;

	for (i = 0; i < num_axes; i++) {
		corr[i].type = JS_CORR_BROKEN;
		corr[i].prec = 0;
		corr[i].coef[0] = 0;
		corr[i].coef[1] = 0;
		corr[i].coef[2] = (1 << 29);
		corr[i].coef[3] = (1 << 29);
	}

	if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) {
		for (i = 0; i < 2; i++) {
			corr[i].type = JS_CORR_BROKEN;
			corr[i].prec = 0;
			corr[i].coef[0] = 0;
			corr[i].coef[1] = 0;
			corr[i].coef[2] = (1 << 22);
			corr[i].coef[3] = (1 << 22);
		}
	}

	if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) {
		for (i = 2; i < 6; i++)  {
			corr[i].type = JS_CORR_BROKEN;
			corr[i].prec = 0;
			corr[i].coef[0] = 127 - 2;
			corr[i].coef[1] = 128 + 2;
			corr[i].coef[2] = (1 << 29) / (127 - 4);
			corr[i].coef[3] = (1 << 29) / (127 - 4);
		}
	}
}

/*
 * js_console_probe() probes for console gamepads.
 * Only PSX pads can really be probed for.
 */

static struct js_port __init *js_console_probe(int *config, struct js_port *port)
{
	char *name[5];
	int i, psx, axes[5], buttons[5], type[5];
	unsigned char data[2];			/* used for PSX probe */
	struct js_console_info info;
	struct parport *pp;

	memset(&info, 0, sizeof(struct js_console_info));

	if (config[0] < 0) return port;

	if (config[0] > 0x10)
		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
	else
		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;

	if (!pp) {
		printk(KERN_ERR "joy-console: no such parport\n");
		return port;
	}

	info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
	if (!info.port)
		return port;

	if (parport_claim(info.port))
	{
		parport_unregister_device(info.port);	/* port currently not available ... */
		return port;
	}

	for (i = 0; i < 5; i++) {

		type[info.pads] = config[i+1];
		info.pad_to_device[i] = info.pads;

		switch(config[i+1]) {

			case JS_NO_PAD:

				break;

			case JS_SNES_PAD:

				axes[info.pads]    = 2;
				buttons[info.pads] = 8;
				name[info.pads]    = "SNES pad";
				info.snes |= status_bit[i];
				info.pads++;
				break;

			case JS_NES_PAD:

				axes[info.pads]    = 2;
				buttons[info.pads] = 4;
				name[info.pads]    = "NES pad";
				info.nes |= status_bit[i];
				info.pads++;
				break;

			case JS_N64_PAD:
				axes[info.pads]    = 4;
				buttons[info.pads] = 10;
				name[info.pads]    = "N64 pad";
				info.n64 |= status_bit[i];
				info.pads++;
				break;

			case JS_N64_PAD_DPP:
				axes[info.pads]    = 2;
				buttons[info.pads] = 14;
				name[info.pads]    = "N64 pad (DPP mode)";
				info.n64 |= status_bit[i];
				info.n64_dpp |= status_bit[i];
				info.pads++;
				break;
				
			case JS_MULTI_STICK:

				axes[info.pads]    = 2;
				buttons[info.pads] = 1;
				name[info.pads]    = "Multisystem joystick";
				info.multi |= status_bit[i];
				info.pads++;
				break;

			case JS_MULTI2_STICK:

				axes[info.pads]    = 2;
				buttons[info.pads] = 2;
				name[info.pads]    = "Multisystem joystick (2 fire)";
				info.multi |= status_bit[i];
				info.pads++;
				break;

			case JS_PSX_PAD:
				
				info.psx |= status_bit[i];
				psx = js_psx_read_packet(&info, 2, data);
				psx = js_psx_read_packet(&info, 2, data);
				info.psx &= ~status_bit[i];

				type[i] = psx;

				switch(psx) {
					case JS_PSX_NORMAL:
						axes[info.pads]    = 2;
						buttons[info.pads] = 10;
						name[info.pads]    = "PSX pad";
						info.psx |= status_bit[i];
						info.pads++;
						break;

					case JS_PSX_ANALOGR:
						axes[info.pads]    = 6;
						buttons[info.pads] = 12;
						name[info.pads]    = "Analog Red PSX pad";
						info.psx |= status_bit[i];
						info.pads++;
						break;

					case JS_PSX_ANALOGG:
						axes[info.pads]    = 6;
						buttons[info.pads] = 10;
						name[info.pads]    = "Analog Green PSX pad";
						info.psx |= status_bit[i];
						info.pads++;
						break;

					case JS_PSX_NEGCON:
						axes[info.pads]    = 2;
						buttons[info.pads] = 10;
						name[info.pads]    = "NegCon PSX pad";
						info.psx |= status_bit[i];
						info.pads++;
						break;

					case JS_PSX_MOUSE:
						printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n");
						break;

					case -1:
						printk(KERN_ERR "joy-psx: no PSX controller found...\n");
						break;

					default:
						printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x,"
							" please report to <vojtech@suse.cz>.\n", psx);
				}
				break;

			default:

				printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
		}
	}

	if (!info.pads) {
		parport_release(info.port);
		parport_unregister_device(info.port);
		return port;
	}

	port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read);

	for (i = 0; i < info.pads; i++) {
		printk(KERN_INFO "js%d: %s on %s\n",
			js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
			name[i], info.port->port->name);

		js_console_init_corr(axes[i], type[i], port->corr[i]);
	}

	parport_release(info.port);
	return port;
}

#ifndef MODULE
int __init js_console_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(6);
	for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
	return 1;
}
int __init js_console_setup_2(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(6);
	for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1];
	return 1;
}
int __init js_console_setup_3(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(6);
	for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1];
	return 1;
}
__setup("js_console=", js_console_setup);
__setup("js_console_2=", js_console_setup_2);
__setup("js_console_3=", js_console_setup_3);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_console_init(void)
#endif
{
	js_console_port = js_console_probe(js_console, js_console_port);
	js_console_port = js_console_probe(js_console_2, js_console_port);
	js_console_port = js_console_probe(js_console_3, js_console_port);

	if (js_console_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-console: no joysticks specified\n");
#endif
	return -ENODEV;
}
joystick-1.2.15/joy-db9.c100644    766    144       25067  7020457034  14163 0ustar  vojtechusers/*
 *  joy-db9.c  Version 0.6V
 *
 *  Copyright (c) 1998 Andree Borrmann
 *  Copyright (c) 1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * console (Atari, Amstrad, Commodore, Amiga, Sega) joysticks
 * and gamepads connected to the parallel port.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>

MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_db9, "2i");
MODULE_PARM(js_db9_2, "2i");
MODULE_PARM(js_db9_3, "2i");

#define JS_MULTI_STICK	0x01
#define JS_MULTI2_STICK 0x02
#define JS_GENESIS_PAD  0x03
#define JS_GENESIS5_PAD 0x05
#define JS_GENESIS6_PAD	0x06
#define JS_SATURN_PAD	0x07
#define JS_MULTI_0802	0x08
#define JS_MULTI_0802_2	0x09
#define JS_MAX_PAD	0x0A

#define JS_DB9_UP	0x01
#define JS_DB9_DOWN	0x02
#define JS_DB9_LEFT	0x04
#define JS_DB9_RIGHT	0x08
#define JS_DB9_FIRE1	0x10
#define JS_DB9_FIRE2	0x20
#define JS_DB9_FIRE3	0x40
#define JS_DB9_FIRE4	0x80

#define JS_DB9_NORMAL	0x2a
#define JS_DB9_NOSELECT	0x28

#define JS_DB9_SATURN0	0x20
#define JS_DB9_SATURN1	0x22
#define JS_DB9_SATURN2	0x24
#define JS_DB9_SATURN3	0x26

#define JS_GENESIS6_DELAY	14

static struct js_port* js_db9_port = NULL;

static int js_db9[] __initdata = { -1, 0 };
static int js_db9_2[] __initdata = { -1, 0 };
static int js_db9_3[] __initdata = { -1, 0 };

struct js_db9_info {
	struct pardevice *port;	/* parport device */
	int mode;		/* pad mode */
};

/*
 * js_db9_read() reads and analyzes db9 joystick data.
 */

static int js_db9_read(void *xinfo, int **axes, int **buttons)
{
	struct js_db9_info *info = xinfo;
	int data;

	switch(info->mode)
	{
	  case JS_MULTI_0802_2:

		data = JS_PAR_DATA_IN(info->port) >> 3;

		axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[1][0] = (data&JS_DB9_FIRE1?0:1);

	  case JS_MULTI_0802:

		data = JS_PAR_STATUS(info->port) >> 3;

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?1:0);

		break;

	  case JS_MULTI_STICK:

		data = JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?0:1);

		break;

	  case JS_MULTI2_STICK:

		data=JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:2);

		break;

	  case JS_GENESIS_PAD:

		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port);
		data = JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?0:2) | (data&JS_DB9_FIRE2?0:4);

		JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port);
		data=JS_PAR_DATA_IN(info->port);

		buttons[0][0] |= (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:8);

		break;

	  case JS_GENESIS5_PAD:

		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port);
		data=JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);

		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
		data=JS_PAR_DATA_IN(info->port);

		buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08) |
				 (data&JS_DB9_LEFT ?0:0x10) | (data&JS_DB9_RIGHT?0:0x20);
		break;

	  case JS_GENESIS6_PAD:

		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port); /* 1 */
		udelay(JS_GENESIS6_DELAY);
		data=JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);

		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
		udelay(JS_GENESIS6_DELAY);
		data=JS_PAR_DATA_IN(info->port);

		buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08);

		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 2 */
		udelay(JS_GENESIS6_DELAY);
		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
		udelay(JS_GENESIS6_DELAY);
		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */
		udelay(JS_GENESIS6_DELAY);
		data=JS_PAR_DATA_IN(info->port);

		buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) |
				 (data&JS_DB9_UP  ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80);

		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
		udelay(JS_GENESIS6_DELAY);
		JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */
		udelay(JS_GENESIS6_DELAY);
		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);

		break;

	  case JS_SATURN_PAD:

		JS_PAR_CTRL_OUT(JS_DB9_SATURN0, info->port);
		data = JS_PAR_DATA_IN(info->port);

		buttons[0][0] = (data&JS_DB9_UP  ?0:0x20) | (data&JS_DB9_DOWN ?0:0x10) |
				(data&JS_DB9_LEFT?0:0x08) | (data&JS_DB9_RIGHT?0:0x40);

		JS_PAR_CTRL_OUT(JS_DB9_SATURN2, info->port);
		data = JS_PAR_DATA_IN(info->port);

		axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP  ?0:1);
		axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);

		JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
		data = JS_PAR_DATA_IN(info->port);

		buttons[0][0] |= (data&JS_DB9_UP  ?0:0x02) | (data&JS_DB9_DOWN ?0:0x04) |
				 (data&JS_DB9_LEFT?0:0x01) | (data&JS_DB9_RIGHT?0:0x80);


		break;

	  default:
		return -1;
	}

	return 0;
}

/*
 * open callback: claim parport.
 */

int js_db9_open(struct js_dev *dev)
{
	struct js_db9_info *info = dev->port->info;

	if (!MOD_IN_USE) {
		if (parport_claim(info->port)) return -EBUSY;

		JS_PAR_DATA_OUT(0xff, info->port);
		if (info->mode != JS_MULTI_0802)
			JS_PAR_ECTRL_OUT(0x35,info->port);	/* enable PS/2 mode: */
		JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port);	/* reverse direction, enable Select signal */
	}
		
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * close callback: release parport
 */

int js_db9_close(struct js_dev *dev)
{
	struct js_db9_info *info = dev->port->info;

	MOD_DEC_USE_COUNT;

	if (!MOD_IN_USE) {

		JS_PAR_CTRL_OUT(0x00,info->port);		/* normal direction */
		if (info->mode != JS_MULTI_0802)
			JS_PAR_ECTRL_OUT(0x15,info->port);	/* enable normal mode */

		parport_release(info->port);
	}
	return 0;
}

#ifdef MODULE
void cleanup_module(void)
{
	struct js_db9_info *info;
	int i;

	while (js_db9_port) {
		info = js_db9_port->info;

		for (i = 0; i < js_db9_port->ndevs; i++)
			if (js_db9_port->devs[i])
				js_unregister_device(js_db9_port->devs[i]);
		parport_unregister_device(info->port);
		js_db9_port = js_unregister_port(js_db9_port);
	}

}
#endif

/*
 * js_db9_init_corr() initializes correction values of
 * db9 gamepads.
 */

static void __init js_db9_init_corr(struct js_corr *corr)
{
	int i;

	for (i = 0; i < 2; i++) {
		corr[i].type = JS_CORR_BROKEN;
		corr[i].prec = 0;
		corr[i].coef[0] = 0;
		corr[i].coef[1] = 0;
		corr[i].coef[2] = (1 << 29);
		corr[i].coef[3] = (1 << 29);
	}
}

/*
 * js_db9_probe() probes for db9 gamepads.
 */

static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
{
	struct js_db9_info info;
	struct parport *pp;
	int i;
	char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1};
	char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
					NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
					"Multisystem (0.8.0.2-dual) joystick"};

	if (config[0] < 0) return port;
	if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port;

	info.mode = config[1];

	if (config[0] > 0x10)
		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
	else
		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;

	if (!pp) {
		printk(KERN_ERR "joy-db9: no such parport\n");
		return port;
	}

	if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) {
		printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
		return port;
	}

	info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
	if (!info.port)
		return port;

	port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read);

	for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
		printk(KERN_INFO "js%d: %s on %s\n",
			js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
			name[info.mode], info.port->port->name);

		js_db9_init_corr(port->corr[i]);
	}


	return port;
}

#ifndef MODULE
int __init js_db9_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
	return 1;
}
int __init js_db9_setup_2(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
	return 1;
}
int __init js_db9_setup_3(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
	return 1;
}
__setup("js_db9=", js_db9_setup);
__setup("js_db9_2=", js_db9_setup_2);
__setup("js_db9_3=", js_db9_setup_3);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_db9_init(void)
#endif
{
	js_db9_port = js_db9_probe(js_db9, js_db9_port);
	js_db9_port = js_db9_probe(js_db9_2, js_db9_port);
	js_db9_port = js_db9_probe(js_db9_3, js_db9_port);

	if (js_db9_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-db9: no joysticks specified\n");
#endif
	return -ENODEV;
}
joystick-1.2.15/joy-gravis.c100644    766    144       21642  7022705324  14773 0ustar  vojtechusers/*
 *  joy-gravis.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * Gravis GrIP digital joystick family.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/init.h>

#define JS_GR_MODE_GPP		1
#define JS_GR_LENGTH_GPP	24
#define JS_GR_STROBE_GPP	400

#define JS_GR_MODE_XT		2
#define JS_GR_MODE_BD		3
#define JS_GR_LENGTH_XT		4
#define JS_GR_STROBE_XT		200
#define JS_GR_MAX_CHUNKS_XT	10	
#define JS_GR_MAX_BITS_XT	30	

static int js_gr_port_list[] __initdata = {0x201, 0};
static struct js_port* js_gr_port __initdata = NULL;

struct js_gr_info {
	int io;
	unsigned char mode[2];
};

/*
 * js_gr_gpp_read_packet() reads a Gravis GamePad Pro packet.
 */

static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
{
	unsigned long flags;
	unsigned char u, v;
	unsigned int t, p;
	int i;

	i = 0;
	data[0] = 0;
	p = t = JS_GR_STROBE_GPP;
	p += JS_GR_STROBE_GPP;

	__save_flags(flags);
	__cli();

	v = inb(io) >> shift;

	do {
		t--;
		u = v; v = (inb(io) >> shift) & 3;
		if (~v & u & 1) {
			data[0] |= (v >> 1) << i++;
			p = t = (p - t) << 1;
		}
	} while (i < JS_GR_LENGTH_GPP && t > 0);

	__restore_flags(flags);

	if (i < JS_GR_LENGTH_GPP) return -1;

	for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
		data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1);

	return -(i == JS_GR_LENGTH_GPP);
}

/*
 * js_gr_xt_read_packet() reads a Gravis Xterminator packet.
 */

static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
{
	unsigned int i, j, buf, crc;
	unsigned char u, v, w;
	unsigned long flags;
	unsigned int t, p;
	char status;

	data[0] = data[1] = data[2] = data[3] = 0;
	status = buf = i = j = 0;
	p = t = JS_GR_STROBE_XT;
	p += JS_GR_STROBE_XT;

	__save_flags(flags);
	__cli();

	v = w = (inb(io) >> shift) & 3;

	do {
		t--;
		u = (inb(io) >> shift) & 3;

		if (u ^ v) {

			if ((u ^ v) & 1) {
				p = t = (p - t) << 2;
				buf = (buf << 1) | (u >> 1);
				i++;
			} else 

			if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
				p = t = (p - t) << 2;
				if (i == 20) {
					crc = buf ^ (buf >> 7) ^ (buf >> 14);
					if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
						data[buf >> 18] = buf >> 4;
						status |= 1 << (buf >> 18);
					}
					j++;
				}
				buf = 0;
				i = 0;
			}

			w = v;
			v = u;
		}

	} while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0);

	__restore_flags(flags);

	return -(status != 0xf);
}

/*
 * js_gr_read() reads and analyzes GrIP joystick data.
 */

static int js_gr_read(void *xinfo, int **axes, int **buttons)
{
	struct js_gr_info *info = xinfo;
	unsigned int data[JS_GR_LENGTH_XT];
	int i;

	for (i = 0; i < 2; i++)
		switch (info->mode[i]) {

			case JS_GR_MODE_GPP:

				if (js_gr_gpp_read_packet(info->io, (i << 1) + 4, data)) return -1;

				axes[i][0] = ((data[0] >> 15) & 1) - ((data[0] >> 16) & 1);
				axes[i][1] = ((data[0] >> 13) & 1) - ((data[0] >> 12) & 1);

				data[0] = ((data[0] >> 6) & 0x37) | (data[0] & 0x08) | ((data[0] << 1) & 0x40) |
				       ((data[0] << 5) & 0x80) | ((data[0] << 8) & 0x300);

				buttons[i][0] = (data[0] & 0xfc) | ((data[0] >> 1) & 0x101) | ((data[0] << 1) & 0x202);

				break;

			case JS_GR_MODE_XT:

				if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;

				axes[i][0] =       (data[0] >> 2) & 0x3f;
				axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
				axes[i][2] =       (data[1] >> 2) & 0x3f;
				axes[i][3] =       (data[1] >> 8) & 0x3f;
				axes[i][4] =       (data[2] >> 8) & 0x3f;

				axes[i][5] = ((data[2] >> 1) & 1) - ( data[2]       & 1);
				axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
				axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1);
				axes[i][8] = ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1);

				buttons[i][0] = (data[3] >> 3) & 0x7ff;

				break;

			case JS_GR_MODE_BD:

				if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;

				axes[i][0] =       (data[0] >> 2) & 0x3f;
				axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
				axes[i][2] =       (data[2] >> 8) & 0x3f;

				axes[i][3] = ((data[2] >> 1) & 1) - ( data[2]       & 1);
				axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);

				buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06)
					      | ((data[3] >> 4) & 0x18);

				break;

			default:
				break;

		}


	return 0;
}

/*
 * js_gr_open() is a callback from the file open routine.
 */

static int js_gr_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_gr_close() is a callback from the file release routine.
 */

static int js_gr_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_gr_init_corr() initializes correction values of
 * GrIP joysticks.
 */

static void __init js_gr_init_corr(int mode, struct js_corr *corr)
{
	int i;

	switch (mode) {

		case JS_GR_MODE_GPP:

			for (i = 0; i < 2; i++) {
				corr[i].type = JS_CORR_BROKEN;
				corr[i].prec = 0;
				corr[i].coef[0] = 0;
				corr[i].coef[1] = 0;
				corr[i].coef[2] = (1 << 29);
				corr[i].coef[3] = (1 << 29);
			}

			break;

		case JS_GR_MODE_XT:

			for (i = 0; i < 5; i++) {
				corr[i].type = JS_CORR_BROKEN;
				corr[i].prec = 0;
				corr[i].coef[0] = 31 - 4;
				corr[i].coef[1] = 32 + 4;
				corr[i].coef[2] = (1 << 29) / (32 - 14);
				corr[i].coef[3] = (1 << 29) / (32 - 14);
			}

			for (i = 5; i < 9; i++) {
				corr[i].type = JS_CORR_BROKEN;
				corr[i].prec = 0;
				corr[i].coef[0] = 0;
				corr[i].coef[1] = 0;
				corr[i].coef[2] = (1 << 29);
				corr[i].coef[3] = (1 << 29);
			}

			break;

		case JS_GR_MODE_BD:

			for (i = 0; i < 3; i++) {
				corr[i].type = JS_CORR_BROKEN;
				corr[i].prec = 0;
				corr[i].coef[0] = 31 - 4;
				corr[i].coef[1] = 32 + 4;
				corr[i].coef[2] = (1 << 29) / (32 - 14);
				corr[i].coef[3] = (1 << 29) / (32 - 14);
			}

			for (i = 3; i < 5; i++) {
				corr[i].type = JS_CORR_BROKEN;
				corr[i].prec = 0;
				corr[i].coef[0] = 0;
				corr[i].coef[1] = 0;
				corr[i].coef[2] = (1 << 29);
				corr[i].coef[3] = (1 << 29);
			}
			
			break;

	}
}

/*
 * js_gr_probe() probes for GrIP joysticks.
 */

static struct js_port __init *js_gr_probe(int io, struct js_port *port)
{
	struct js_gr_info info;
	char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
	char axes[] = { 0, 2, 9, 5};
	char buttons[] = { 0, 10, 11, 5};
	unsigned int data[JS_GR_LENGTH_XT];
	int i;

	if (check_region(io, 1)) return port;

	info.mode[0] = info.mode[1] = 0;

	for (i = 0; i < 2; i++) {
		if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP;
		if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) {
			if ((data[3] & 7) == 7)
				info.mode[i] = JS_GR_MODE_XT;
			if ((data[3] & 7) == 0)
				info.mode[i] = JS_GR_MODE_BD;
		}
	}

	if (!info.mode[0] && !info.mode[1]) return port;

	info.io = io;

	request_region(io, 1, "joystick (gravis)");
	port = js_register_port(port, &info, 2, sizeof(struct js_gr_info), js_gr_read);

	for (i = 0; i < 2; i++)
		if (info.mode[i]) {
			printk(KERN_INFO "js%d: %s at %#x\n",
				js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
					names[info.mode[i]], js_gr_open, js_gr_close),
				names[info.mode[i]], io);
			js_gr_init_corr(info.mode[i], port->corr[i]);
		}

	return port;
}

#ifdef MODULE
int init_module(void)
#else
int __init js_gr_init(void)
#endif
{
	int *p;

	for (p = js_gr_port_list; *p; p++) js_gr_port = js_gr_probe(*p, js_gr_port);
	if (js_gr_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-gravis: no joysticks found\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	int i;
	struct js_gr_info *info;

	while (js_gr_port) {
		for (i = 0; i < js_gr_port->ndevs; i++)
			if (js_gr_port->devs[i])
				js_unregister_device(js_gr_port->devs[i]);
		info = js_gr_port->info;
		release_region(info->io, 1);
		js_gr_port = js_unregister_port(js_gr_port);
	}
}
#endif
joystick-1.2.15/joy-logitech.c100644    766    144       33062  7023004500  15262 0ustar  vojtechusers/*
 *  joy-logitech.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * Logitech ADI joystick family.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/malloc.h>
#include <linux/init.h>

/*
 * Times array sizes, flags, ids.
 */

#undef JS_LT_DEBUG

#define JS_LT_MAX_START		400	/* Trigger to packet timeout [400us] */

#define JS_LT_MAX_LENGTH	256
#define JS_LT_MIN_LENGTH	8
#define JS_LT_MIN_LEN_LENGTH	10
#define JS_LT_MIN_ID_LENGTH	66
#define JS_LT_MAX_NAME_LENGTH	16

#define JS_LT_INIT_DELAY	10	/* Delay after init packet [10ms] */
#define JS_LT_DATA_DELAY	4	/* Delay after data packet [4ms] */

#define JS_LT_FLAG_HAT		0x04
#define JS_LT_FLAG_10BIT	0x08

#define JS_LT_ID_WMED		0x00
#define JS_LT_ID_TPD		0x01
#define JS_LT_ID_WMI		0x04
#define JS_LT_ID_WGP		0x06
#define JS_LT_ID_WM3D		0x07
#define JS_LT_ID_WGPE		0x08

#define JS_LT_BUG_BUTTONS	0x01
#define JS_LT_BUG_LONGID	0x02
#define JS_LT_BUG_LONGDATA	0x04
#define JS_LT_BUG_IGNTRIG	0x08

/*
 * Port probing variables.
 */

static int js_lt_port_list[] __initdata = { 0x201, 0 };
static struct js_port* js_lt_port __initdata = NULL;

/*
 * Device names.
 */

#define JS_LT_MAX_ID		10

static char *js_lt_names[] = {	"WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
				"WingMan Interceptor", "WingMan Formula", "WingMan GamePad", 
				"WingMan Extreme Digital 3D", "WingMan GamePad Extreme", 
				"WingMan GamePad USB", "Unknown Device %#x"};

/*
 * Hat to axis conversion arrays.
 */

static struct {
	int x;
	int y;
} js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};

/*
 * Per-port information.
 */

struct js_lt_info {
	int  io;
	int  length[2];
	int  ret[2];
	int  idx[2];
	unsigned char id[2];
	char buttons[2];
	char axes10[2];
	char axes8[2];
	char pad[2];
	char hats[2];
	char name[2][JS_LT_MAX_NAME_LENGTH];
	unsigned char data[2][JS_LT_MAX_LENGTH];
	char bugs[2];
};

/*
 * js_lt_read_packet() reads a Logitech ADI packet.
 */

static void js_lt_read_packet(struct js_lt_info *info)
{
	unsigned char u, v, w, x, z;
	int t[2], s[2], p[2], i;
	unsigned long flags;

	for (i = 0; i < 2; i++) {
		info->ret[i] = -1;
		p[i] = t[i] = JS_LT_MAX_START;
		s[i] = 0;
	}

	__save_flags(flags);
	__cli();

	outb(0xff, info->io);
	v = z = inb(info->io);

	do {
		u = v;
		w = u ^ (v = x = inb(info->io));
		for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
			t[i]--;
			if ((w & 0x30) && s[i]) {
				if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) {
					info->data[i][++info->ret[i]] = w;
					p[i] = t[i] = (p[i] - t[i]) << 1;
				} else t[i] = 0;
			} else if (!(x & 0x30)) s[i] = 1;
		}
	} while (t[0] > 0 || t[1] > 0);

	__restore_flags(flags);

	for (i = 0; i < 2; i++, z >>= 2)
		if ((z & 0x30) && info->ret[i] > 0)
			info->bugs[i] |= JS_LT_BUG_BUTTONS;

#ifdef JS_LT_DEBUG
	printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]);
	printk(KERN_DEBUG "joy-logitech: stream0:");
	for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1);
	printk("\n");
	printk(KERN_DEBUG "joy-logitech: stream1:");
	for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1);
	printk("\n");
#endif

	return;
}

/*
 * js_lt_move_bits() detects a possible 2-stream mode, and moves
 * the bits accordingly. 
 */

static void js_lt_move_bits(struct js_lt_info *info, int length)
{
	int i;

 	info->idx[0] = info->idx[1] = 0;

	if (info->ret[0] <= 0 || info->ret[1] <= 0) return;
	if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return;

	for (i = 1; i <= info->ret[1]; i++)
		info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i];

	info->ret[0] += info->ret[1];
	info->ret[1] = -1;
}

/*
 * js_lt_get_bits() gathers bits from the data packet.
 */

static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count)
{
	int bits = 0;
	int i;
	if ((info->idx[device] += count) > info->ret[device]) return 0;
	for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i; 
	return bits;
}

/*
 * js_lt_read() reads and analyzes Logitech joystick data.
 */

static int js_lt_read(void *xinfo, int **axes, int **buttons)
{
	struct js_lt_info *info = xinfo;
	int i, j, k, l, t;
	int ret = 0;

	js_lt_read_packet(info);
	js_lt_move_bits(info, info->length[0]);

	for (i = 0; i < 2; i++) {

		if (!info->length[i]) continue;
		
		if (info->length[i] > info->ret[i] ||
		    info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) {
			ret = -1;
			continue;
		}

		if (info->length[i] < info->ret[i])
			info->bugs[i] |= JS_LT_BUG_LONGDATA;
			
		k = l = 0;

		for (j = 0; j < info->axes10[i]; j++) 
			axes[i][k++] = js_lt_get_bits(info, i, 10);

		for (j = 0; j < info->axes8[i]; j++) 
			axes[i][k++] = js_lt_get_bits(info, i, 8);

		for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0;

		for (j = 0; j < info->buttons[i] && j < 63; j++) {
			if (j == info->pad[i]) {
				t = js_lt_get_bits(info, i, 4);
				axes[i][k++] = ((t >> 2) & 1) - ( t       & 1);
				axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1);
			}
			buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
			l++;
		}

		for (j = 0; j < info->hats[i]; j++) {
			if((t = js_lt_get_bits(info, i, 4)) > 8) {
				if (t != 15) ret = -1; /* Hat press */
				t = 0;
			}
			axes[i][k++] = js_lt_hat_to_axis[t].x;
			axes[i][k++] = js_lt_hat_to_axis[t].y;
		}

		for (j = 63; j < info->buttons[i]; j++) {
			buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
			l++;
		}
	}

	return ret;
}

/*
 * js_lt_open() is a callback from the file open routine.
 */

static int js_lt_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_lt_close() is a callback from the file release routine.
 */

static int js_lt_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_lt_init_digital() sends a trigger & delay sequence
 * to reset and initialize a Logitech joystick into digital mode.
 */

static void __init js_lt_init_digital(int io)
{
	int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 };
	int i;

	for (i = 0; seq[i]; i++) {
		outb(0xff,io);
		mdelay(seq[i]);
	}
}

/*
 * js_lt_init_corr() initializes the correction values for
 * Logitech joysticks.
 */

static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr)
{
	int j;
	
	if (id == JS_LT_ID_WMED) axes[2] = 128;	/* Throttle fixup */
	if (id == JS_LT_ID_WMI)  axes[2] = 512;
	if (id == JS_LT_ID_WM3D) axes[3] = 128;	

	if (id == JS_LT_ID_WGPE) {		/* Tilt fixup */
		axes[0] = 512;
		axes[1] = 512;
	}

	for (j = 0; j < naxes10; j++) {
		corr[j].type = JS_CORR_BROKEN;
		corr[j].prec = 2;
		corr[j].coef[0] = axes[j] - 16;
		corr[j].coef[1] = axes[j] + 16;
		corr[j].coef[2] = (1 << 29) / (256 - 32);
		corr[j].coef[3] = (1 << 29) / (256 - 32);
	}

	for (; j < naxes8 + naxes10; j++) {
		corr[j].type = JS_CORR_BROKEN;
		corr[j].prec = 1;
		corr[j].coef[0] = axes[j] - 2;
		corr[j].coef[1] = axes[j] + 2;
		corr[j].coef[2] = (1 << 29) / (64 - 16);
		corr[j].coef[3] = (1 << 29) / (64 - 16);
	}

	for (; j < naxes1 + naxes8 + naxes10; j++) {
		corr[j].type = JS_CORR_BROKEN;
		corr[j].prec = 0;
		corr[j].coef[0] = 0;
		corr[j].coef[1] = 0;
		corr[j].coef[2] = (1 << 29);
		corr[j].coef[3] = (1 << 29);
	}
}

/*
 * js_lt_probe() probes for Logitech type joysticks.
 */

static struct js_port __init *js_lt_probe(int io, struct js_port *port)
{
	struct js_lt_info iniinfo;
	struct js_lt_info *info = &iniinfo;
	char name[32];
	int i, j, t;

	if (check_region(io, 1)) return port;

	js_lt_init_digital(io);

	memset(info, 0, sizeof(struct js_lt_info));

	info->length[0] = info->length[1] = JS_LT_MAX_LENGTH;

	info->io = io;
	js_lt_read_packet(info);
	
	if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH)
		js_lt_move_bits(info, js_lt_get_bits(info, 0, 10));

	info->length[0] = info->length[1] = 0;

	for (i = 0; i < 2; i++) {

		if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */

		if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) {
			printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n",
				t, info->ret[i]); 
			continue;
		}

		if (info->ret[i] > t)
			info->bugs[i] |= JS_LT_BUG_LONGID;

#ifdef JS_LT_DEBUG
		printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t);
#endif

		info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4);

		if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++;

#ifdef JS_LT_DEBUG
		printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t);
#endif

		if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) {
			printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n",
				info->length[i]);
			continue;
		}

		if (info->length[i] < JS_LT_MIN_LENGTH) {
			printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n",
				info->length[i]);
			continue;
		}

		info->axes8[i] = js_lt_get_bits(info, i, 4);
		info->buttons[i] = js_lt_get_bits(info, i, 6);

		if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) {
			printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n");
			continue;
		}

		info->buttons[i] += js_lt_get_bits(info, i, 6);
		info->hats[i] += js_lt_get_bits(info, i, 4);

		j = js_lt_get_bits(info, i, 4);

		if (t & JS_LT_FLAG_10BIT) {
			info->axes10[i] = info->axes8[i] - j;
			info->axes8[i] = j;
		}

		t = js_lt_get_bits(info, i, 4);

		for (j = 0; j < t; j++)
			info->name[i][j] = js_lt_get_bits(info, i, 8);
		info->name[i][j] = 0;

		switch (info->id[i]) {
			case JS_LT_ID_TPD:
				info->pad[i] = 4;
				info->buttons[i] -= 4;
				break;
			case JS_LT_ID_WGP:
				info->pad[i] = 0;
				info->buttons[i] -= 4;
				break;
			default:
				info->pad[i] = -1;
				break;
		}

		if (info->length[i] != 
			(t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
			info->hats[i] * 4 + (info->pad[i] != -1) * 4)) {
			printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]);
		}

	}

	if (!info->length[0] && !info->length[1])
		return port;

	request_region(io, 1, "joystick (logitech)");

	port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read);
	info = port->info;

	for (i = 0; i < 2; i++)
		if (info->length[i] > 0) {
			sprintf(name, info->id[i] < JS_LT_MAX_ID ?
				js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]); 
			printk(KERN_INFO "js%d: %s [%s] at %#x\n",
				js_register_device(port, i,
					info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
					info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io);
		}

	mdelay(JS_LT_INIT_DELAY);
	if (js_lt_read(info, port->axes, port->buttons)) {
		if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG;
		if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG;
		mdelay(JS_LT_DATA_DELAY);
		js_lt_read(info, port->axes, port->buttons);
	}

	for (i = 0; i < 2; i++)
		if (info->length[i] > 0) {
#ifdef JS_LT_DEBUG
				printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d "
						  "pad %d hats %d name %s explen %d\n",
					i, info->length[i], info->ret[i], info->id[i],
					info->buttons[i], info->axes10[i], info->axes8[i],
					info->pad[i], info->hats[i], info->name[i],
					8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
					info->hats[i] * 4 + (info->pad[i] != -1) * 4);
#endif
				if (info->bugs[i]) {
					printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i,
						info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "",
						info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "",
						info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "",
						info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : "");
				}
				js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i],
					((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]);
	}

	return port;
}

#ifdef MODULE
int init_module(void)
#else
int __init js_lt_init(void)
#endif
{
	int *p;

	for (p = js_lt_port_list; *p; p++) js_lt_port = js_lt_probe(*p, js_lt_port);
	if (js_lt_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-logitech: no joysticks found\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	int i;
	struct js_lt_info *info;

	while (js_lt_port) {
		for (i = 0; i < js_lt_port->ndevs; i++)
			 if (js_lt_port->devs[i])
				js_unregister_device(js_lt_port->devs[i]);
		info = js_lt_port->info;
		release_region(info->io, 1);
		js_lt_port = js_unregister_port(js_lt_port);
	}
}
#endif
joystick-1.2.15/joy-sidewinder.c100644    766    144       53031  7022671655  15643 0ustar  vojtechusers/*
 *  joy-sidewinder.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * Microsoft SideWinder digital joystick family.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/init.h>

/*
 * These are really magic values. Changing them can make a problem go away,
 * as well as break everything.
 */

#undef JS_SW_DEBUG

#define JS_SW_START		400	/* The time we wait for the first bit [400 us] */
#define JS_SW_STROBE		45	/* Max time per bit [45 us] */
#define JS_SW_TIMEOUT		4000	/* Wait for everything to settle [4 ms] */
#define JS_SW_KICK		45	/* Wait after A0 fall till kick [45 us] */
#define JS_SW_END		8	/* Number of bits before end of packet to kick */
#define JS_SW_FAIL		16	/* Number of packet read errors to fail and reinitialize */
#define JS_SW_BAD		2	/* Number of packet read errors to switch off 3d Pro optimization */
#define JS_SW_OK		64	/* Number of packet read successes to switch optimization back on */
#define JS_SW_LENGTH		512	/* Max number of bits in a packet */

/*
 * SideWinder joystick types ...
 */

#define JS_SW_TYPE_3DP		1
#define JS_SW_TYPE_F23		2
#define JS_SW_TYPE_GP		3
#define JS_SW_TYPE_PP		4
#define JS_SW_TYPE_FFP		5
#define JS_SW_TYPE_FSP		6
#define JS_SW_TYPE_FFW		7

static int js_sw_port_list[] __initdata = {0x201, 0};
static struct js_port* js_sw_port __initdata = NULL;

static struct {
	int x;
	int y;
} js_sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};

struct js_sw_info {
	int io;
	int length;
	int speed;
	unsigned char type;
	unsigned char bits;
	unsigned char number;
	unsigned char fail;
	unsigned char ok;
};

/*
 * Gameport speed.
 */

unsigned int js_sw_io_speed = 0;

/*
 * js_sw_measure_speed() measures the gameport i/o speed.
 */

static int __init js_sw_measure_speed(int io)
{
#ifdef __i386__

#define GET_TIME(x)     do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
#define DELTA(x,y)      ((y)-(x)+((y)<(x)?1193180L/HZ:0))

	unsigned int i, t, t1, t2, t3, tx;
	unsigned long flags;

	tx = 1 << 30;

	for(i = 0; i < 50; i++) {
		save_flags(flags);	/* Yes, all CPUs */
		cli();
		GET_TIME(t1);
		for(t = 0; t < 50; t++) inb(io);
		GET_TIME(t2);
		GET_TIME(t3);
		restore_flags(flags);
		udelay(i * 10);
		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
	}

	return 59659 / t;

#else

	unsigned int j, t = 0;

	j = jiffies; while (j == jiffies);
	j = jiffies; while (j == jiffies) { t++; inb(0x201); }

	return t * HZ / 1000;

#endif
}

/*
 * js_sw_read_packet() is a function which reads either a data packet, or an
 * identification packet from a SideWinder joystick. Better don't try to
 * understand this, since all the ugliness of the Microsoft Digital
 * Overdrive protocol is concentrated in this function. If you really want
 * to know how this works, first go watch a couple horror movies, so that
 * you are well prepared, read US patent #5628686 and then e-mail me,
 * and I'll send you an explanation.
 *					Vojtech <vojtech@suse.cz>
 */

static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id)
{
	unsigned long flags;
	int timeout, bitout, sched, i, kick, start, strobe;
	unsigned char pending, u, v;

	i = -id;						/* Don't care about data, only want ID */
	timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0;	/* Set up global timeout for ID packet */
	kick = id ? (JS_SW_KICK * speed) >> 10 : 0;		/* Set up kick timeout for ID packet */
	start = (JS_SW_START * speed) >> 10;
	strobe = (JS_SW_STROBE * speed) >> 10;
	bitout = start;
	pending = 0;
	sched = 0;

        __save_flags(flags);					/* Quiet, please */
        __cli();

	outb(0xff, io);						/* Trigger */
	v = inb(io);

	do {
		bitout--;
		u = v;
		v = inb(io);
	} while (!(~v & u & 0x10) && (bitout > 0));		/* Wait for first falling edge on clock */

	if (bitout > 0) bitout = strobe;			/* Extend time if not timed out */

	while ((timeout > 0 || bitout > 0) && (i < length)) {

		timeout--;
		bitout--;					/* Decrement timers */
		sched--;

		u = v;
		v = inb(io);

		if ((~u & v & 0x10) && (bitout > 0)) {		/* Rising edge on clock - data bit */
			if (i >= 0)				/* Want this data */
				buf[i] = v >> 5;		/* Store it */
			i++;					/* Advance index */
			bitout = strobe;			/* Extend timeout for next bit */
		} 

		if (kick && (~v & u & 0x01)) {			/* Falling edge on axis 0 */
			sched = kick;				/* Schedule second trigger */
			kick = 0;				/* Don't schedule next time on falling edge */
			pending = 1;				/* Mark schedule */
		} 

		if (pending && sched < 0 && (i > -JS_SW_END)) {	/* Second trigger time */
			outb(0xff, io);				/* Trigger */
			bitout = start;				/* Long bit timeout */
			pending = 0;				/* Unmark schedule */
			timeout = 0;				/* Switch from global to bit timeouts */ 
		}
	}

	__restore_flags(flags);					/* Done - relax */

#ifdef JS_SW_DEBUG
	{
		int j;
		printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i);
		for (j = 0; j < i; j++) printk("%d", buf[j]);
		printk("]\n");
	}
#endif

	return i;
}

/*
 * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
 * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
 * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
 * is number of bits per triplet.
 */

#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits)

static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits)
{
	__u64 data = 0;
	int tri = pos % bits;						/* Start position */
	int i   = pos / bits;
	int bit = shift;

	while (num--) {
		data |= (__u64)((buf[i] >> tri++) & 1) << bit++;	/* Transfer bit */
		if (tri == bits) {
			i++;						/* Next triplet */
			tri = 0;
		}
	}

	return data;
}

/*
 * js_sw_init_digital() initializes a SideWinder 3D Pro joystick
 * into digital mode.
 */

static void js_sw_init_digital(int io, int speed)
{
	int seq[] = { 140, 140+725, 140+300, 0 };
	unsigned long flags;
	int i, t;

        __save_flags(flags);
        __cli();

	i = 0;
        do {
                outb(0xff, io);					/* Trigger */
		t = (JS_SW_TIMEOUT * speed) >> 10;
		while ((inb(io) & 1) && t) t--;			/* Wait for axis to fall back to 0 */
                udelay(seq[i]);					/* Delay magic time */
        } while (seq[++i]);

	outb(0xff, io);						/* Last trigger */

	__restore_flags(flags);
}

/*
 * js_sw_parity() computes parity of __u64
 */

static int js_sw_parity(__u64 t)
{
	int x = t ^ (t >> 32);
	x ^= x >> 16;
	x ^= x >> 8;
	x ^= x >> 4;
	x ^= x >> 2;
	x ^= x >> 1;
	return x & 1;
}

/*
 * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
 */

static int js_sw_check(__u64 t)
{
	char sum = 0;

	if ((t & 0x8080808080808080ULL) ^ 0x80)			/* Sync */
		return -1;

	while (t) {						/* Sum */
		sum += t & 0xf;
		t >>= 4;
	}

	return sum & 0xf;
}

/*
 * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
 * the axes and buttons arrays.
 */

static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons)
{
	int hat, i;

	switch (info->type) {

		case JS_SW_TYPE_3DP:
		case JS_SW_TYPE_F23:

			if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0))  > 8) return -1;

			axes[0][0] = GB( 3,3,7) | GB(16,7,0);
			axes[0][1] = GB( 0,3,7) | GB(24,7,0);
			axes[0][2] = GB(35,2,7) | GB(40,7,0);
			axes[0][3] = GB(32,3,7) | GB(48,7,0);
			axes[0][4] = js_sw_hat_to_axis[hat].x;
			axes[0][5] = js_sw_hat_to_axis[hat].y;
			buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));

			return 0;

		case JS_SW_TYPE_GP:

			for (i = 0; i < info->number * 15; i += 15) {

				if (js_sw_parity(GB(i,15,0))) return -1;

				axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0);
				axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0);
				buttons[i][0] = ~GB(i+4,10,0);

			}

			return 0;

		case JS_SW_TYPE_PP:
		case JS_SW_TYPE_FFP:

			if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1;

			axes[0][0] = GB( 9,10,0);
			axes[0][1] = GB(19,10,0);
			axes[0][2] = GB(36, 6,0);
			axes[0][3] = GB(29, 7,0);
			axes[0][4] = js_sw_hat_to_axis[hat].x;
			axes[0][5] = js_sw_hat_to_axis[hat].y;
			buttons[0][0] = ~GB(0,9,0);

			return 0;

		case JS_SW_TYPE_FSP:

			if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1;

			axes[0][0] = GB( 0,10,0);
			axes[0][1] = GB(16,10,0);
			axes[0][2] = GB(32, 6,0);
			axes[0][3] = js_sw_hat_to_axis[hat].x;
			axes[0][4] = js_sw_hat_to_axis[hat].y;
			buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8));

			return 0;

		case JS_SW_TYPE_FFW:

			if (!js_sw_parity(GB(0,33,0))) return -1;

			axes[0][0] = GB( 0,10,0);
			axes[0][1] = GB(10, 6,0);
			axes[0][2] = GB(16, 6,0);
			buttons[0][0] = ~GB(22,8,0);

			return 0;
	}

	return -1;
}

/*
 * js_sw_read() reads SideWinder joystick data, and reinitializes
 * the joystick in case of persistent problems. This is the function that is
 * called from the generic code to poll the joystick.
 */

static int js_sw_read(void *xinfo, int **axes, int **buttons)
{
	struct js_sw_info *info = xinfo;
	unsigned char buf[JS_SW_LENGTH];
	int i;

	i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0);

	if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) {	/* Broken packet, try to fix */

		if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) {	/* Last init failed, 1 bit mode */
			printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x"
				" - going to reinitialize.\n", info->io);
			info->fail = JS_SW_FAIL;				/* Reinitialize */
			i = 128;						/* Bogus value */
		}

		if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0))			/* 1 == 3 */
			i = 66;							/* Everything is fine */

		if (i < 66 && GB(0,64,0) == GB(66,64,0))			/* 1 == 2 */
			i = 66;							/* Everything is fine */

		if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) {		/* 2 == 3 */
			memmove(buf, buf + i - 22, 22);				/* Move data */
			i = 66;							/* Carry on */
		}
	}

	if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) {	/* Parse data */

		info->fail = 0;
		info->ok++;

		if (info->type <= JS_SW_TYPE_F23 && info->length == 66		/* Many packets OK */
			&& info->ok > JS_SW_OK) {

			printk(KERN_INFO "joy-sidewinder: No more trouble on %#x"
				" - enabling optimization again.\n", info->io);
			info->length = 22;
		}

		return 0;
	}

	info->ok = 0;
	info->fail++;

	if (info->type <= JS_SW_TYPE_F23 && info->length == 22			/* Consecutive bad packets */
			&& info->fail > JS_SW_BAD) {

		printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x"
			" - disabling optimization.\n", info->io);
		info->length = 66;
	}

	if (info->fail < JS_SW_FAIL) return -1;					/* Not enough, don't reinitialize yet */

	printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x"
		" - reinitializing joystick.\n", info->io);

	if (!i && info->type <= JS_SW_TYPE_F23) {				/* 3D Pro can be in analog mode */
		udelay(3 * JS_SW_TIMEOUT);
		js_sw_init_digital(info->io, info->speed);
	}

	udelay(JS_SW_TIMEOUT);
	i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0);	/* Read normal data packet */
	udelay(JS_SW_TIMEOUT);
	js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i);		/* Read ID packet, this initializes the stick */

	info->fail = JS_SW_FAIL;
	
	return -1;
}

/*
 * js_sw_open() is a callback from the file open routine.
 */

static int js_sw_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_sw_close() is a callback from the file release routine.
 */

static int js_sw_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_sw_init_corr() initializes the correction values for
 * SideWinders.
 */

static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr)
{
	int i, j;

	for (i = 0; i < number; i++) {

		for (j = 0; j < num_axes; j++) {
			corr[i][j].type = JS_CORR_BROKEN;
			corr[i][j].prec = 8;
			corr[i][j].coef[0] = 511 - 32;
			corr[i][j].coef[1] = 512 + 32;
			corr[i][j].coef[2] = (1 << 29) / (511 - 32);
			corr[i][j].coef[3] = (1 << 29) / (511 - 32);
		}

		switch (type) {

			case JS_SW_TYPE_3DP:
			case JS_SW_TYPE_F23:

				corr[i][2].type = JS_CORR_BROKEN;
				corr[i][2].prec = 4;
				corr[i][2].coef[0] = 255 - 16;
				corr[i][2].coef[1] = 256 + 16;
				corr[i][2].coef[2] = (1 << 29) / (255 - 16);
				corr[i][2].coef[3] = (1 << 29) / (255 - 16);

				j = 4;

			break;

			case JS_SW_TYPE_PP:
			case JS_SW_TYPE_FFP:

				corr[i][2].type = JS_CORR_BROKEN;
				corr[i][2].prec = 0;
				corr[i][2].coef[0] = 31 - 2;
				corr[i][2].coef[1] = 32 + 2;
				corr[i][2].coef[2] = (1 << 29) / (31 - 2);
				corr[i][2].coef[3] = (1 << 29) / (31 - 2);

				corr[i][3].type = JS_CORR_BROKEN;
				corr[i][3].prec = 1;
				corr[i][3].coef[0] = 63 - 4;
				corr[i][3].coef[1] = 64 + 4;
				corr[i][3].coef[2] = (1 << 29) / (63 - 4);
				corr[i][3].coef[3] = (1 << 29) / (63 - 4);

				j = 4;

			break;

			case JS_SW_TYPE_FFW:

				corr[i][0].type = JS_CORR_BROKEN;
				corr[i][0].prec = 2;
				corr[i][0].coef[0] = 511 - 8;
				corr[i][0].coef[1] = 512 + 8;
				corr[i][0].coef[2] = (1 << 29) / (511 - 8);
				corr[i][0].coef[3] = (1 << 29) / (511 - 8);

				corr[i][1].type = JS_CORR_BROKEN;
				corr[i][1].prec = 1;
				corr[i][1].coef[0] = 63;
				corr[i][1].coef[1] = 63;
				corr[i][1].coef[2] = (1 << 29) / -63;
				corr[i][1].coef[3] = (1 << 29) / -63;

				corr[i][2].type = JS_CORR_BROKEN;
				corr[i][2].prec = 1;
				corr[i][2].coef[0] = 63;
				corr[i][2].coef[1] = 63;
				corr[i][2].coef[2] = (1 << 29) / -63;
				corr[i][2].coef[3] = (1 << 29) / -63;

				j = 3;

			break;

			case JS_SW_TYPE_FSP:
				
				corr[i][2].type = JS_CORR_BROKEN;
				corr[i][2].prec = 0;
				corr[i][2].coef[0] = 31 - 2;
				corr[i][2].coef[1] = 32 + 2;
				corr[i][2].coef[2] = (1 << 29) / (31 - 2);
				corr[i][2].coef[3] = (1 << 29) / (31 - 2);

				j = 3;

			break;

			default:

				j = 0;
		}

		for (; j < num_axes; j++) {				/* Hats & other binary axes */
			corr[i][j].type = JS_CORR_BROKEN;
			corr[i][j].prec = 0;
			corr[i][j].coef[0] = 0;
			corr[i][j].coef[1] = 0;
			corr[i][j].coef[2] = (1 << 29);
			corr[i][j].coef[3] = (1 << 29);
		}
	}
}

/*
 * js_sw_print_packet() prints the contents of a SideWinder packet.
 */

static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits)
{
	int i;

	printk("joy-sidewinder: %s packet, %d bits. [", name, length);
	for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
		printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits));
	printk("]\n");
}

/*
 * js_sw_3dp_id() translates the 3DP id into a human legible string.
 * Unfortunately I don't know how to do this for the other SW types.
 */

static void js_sw_3dp_id(unsigned char *buf, char *comment)
{
	int i;
	char pnp[8], rev[9];

	for (i = 0; i < 7; i++)						/* ASCII PnP ID */
		pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1);

	for (i = 0; i < 8; i++)						/* ASCII firmware revision */
		rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1);

	pnp[7] = rev[8] = 0;

	sprintf(comment, " [PnP %d.%02d id %s rev %s]",
		(int) (js_sw_get_bits(buf, 8, 6, 6, 1) |		/* Two 6-bit values */
			js_sw_get_bits(buf, 16, 6, 0, 1)) / 100,
		(int) (js_sw_get_bits(buf, 8, 6, 6, 1) |
			js_sw_get_bits(buf, 16, 6, 0, 1)) % 100,
		 pnp, rev);
}

/*
 * js_sw_guess_mode() checks the upper two button bits for toggling -
 * indication of that the joystick is in 3-bit mode. This is documented
 * behavior for 3DP ID packet, and for example the FSP does this in
 * normal packets instead. Fun ...
 */

static int js_sw_guess_mode(unsigned char *buf, int len)
{
	int i;
	unsigned char xor = 0;
	for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
	return !!xor * 2 + 1;
}

/*
 * js_sw_probe() probes for SideWinder type joysticks.
 */

static struct js_port __init *js_sw_probe(int io, struct js_port *port)
{
	struct js_sw_info info;
	char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro",
			"SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" };
	char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 };
	char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 };
	int i, j, k, l, speed;
	unsigned char buf[JS_SW_LENGTH];
	unsigned char idbuf[JS_SW_LENGTH];
	unsigned char m = 1;
	char comment[40];

	comment[0] = 0;

	if (check_region(io, 1)) return port;

	speed = js_sw_measure_speed(io);

	i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);		/* Read normal packet */
	m |= js_sw_guess_mode(buf, i);					/* Data packet (1-bit) can carry mode info [FSP] */
	udelay(JS_SW_TIMEOUT);

#ifdef JS_SW_DEBUG
	printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i);
#endif

	if (!i) {							/* No data. 3d Pro analog mode? */
		js_sw_init_digital(io, speed);				/* Switch to digital */
		udelay(JS_SW_TIMEOUT);
		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Retry reading packet */
		udelay(JS_SW_TIMEOUT);
#ifdef JS_SW_DEBUG
	printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i);
#endif
		if (!i) return port;					/* No data -> FAIL */
	}

	j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);	/* Read ID. This initializes the stick */
	m |= js_sw_guess_mode(idbuf, j);				/* ID packet should carry mode info [3DP] */

#ifdef JS_SW_DEBUG
	printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j);
#endif

	if (!j) {							/* Read ID failed. Happens in 1-bit mode on PP */
		udelay(JS_SW_TIMEOUT);
		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Retry reading packet */
#ifdef JS_SW_DEBUG
	printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i);
#endif
		if (!i) return port;
		udelay(JS_SW_TIMEOUT);
		j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */
#ifdef JS_SW_DEBUG
	printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j);
#endif

	}

	k = JS_SW_FAIL;							/* Try JS_SW_FAIL times */
	l = 0;

	do {
		k--;
		udelay(JS_SW_TIMEOUT);
		i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0);	/* Read data packet */
#ifdef JS_SW_DEBUG
		printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i);
#endif

		if (i > l) {						/* Longer? As we can only lose bits, it makes */
									/* no sense to try detection for a packet shorter */
			l = i;						/* than the previous one */

			info.number = 1;
			info.io = io;
			info.speed = speed;
			info.length = i;
			info.bits = m;
			info.fail = 0;
			info.ok = 0;
			info.type = 0;

			switch (i * m) {
				case 60:
					info.number++;
				case 45:				/* Ambiguous packet length */
					if (j <= 40) {			/* ID length less or eq 40 -> FSP */	
				case 43:
						info.type = JS_SW_TYPE_FSP;
						break;
					}
					info.number++;
				case 30:
					info.number++;
				case 15:
					info.type = JS_SW_TYPE_GP;
					break;
				case 33:
				case 31:
					info.type = JS_SW_TYPE_FFW;
					break;
				case 48:				/* Ambiguous */
					if (j == 14) {			/* ID lenght 14*3 -> FFP */
						info.type = JS_SW_TYPE_FFP;
						sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on");
					} else
					info.type = JS_SW_TYPE_PP;
					break;
				case 198:
					info.length = 22;
				case 64:
					info.type = JS_SW_TYPE_3DP;
					if (j == 160) js_sw_3dp_id(idbuf, comment);
					break;
			}
		}

	} while (k && !info.type);

	if (!info.type) {
		printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
			"(io=%#x), contact <vojtech@suse.cz>\n", io);
		js_sw_print_packet("ID", j * 3, idbuf, 3);
		js_sw_print_packet("Data", i * m, buf, m);
		return port;
	}

#ifdef JS_SW_DEBUG
	js_sw_print_packet("ID", j * 3, idbuf, 3);
	js_sw_print_packet("Data", i * m, buf, m);
#endif

	k = i;

	request_region(io, 1, "joystick (sidewinder)");

	port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read);

	for (i = 0; i < info.number; i++)
		printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
			js_register_device(port, i, axes[info.type], buttons[info.type],
				names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io,
				1000000 / speed, m, j, k);

	js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);

	return port;
}

#ifdef MODULE
int init_module(void)
#else
int __init js_sw_init(void)
#endif
{
	int *p;

	for (p = js_sw_port_list; *p; p++) js_sw_port = js_sw_probe(*p, js_sw_port);
	if (js_sw_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-sidewinder: no joysticks found\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	int i;
	struct js_sw_info *info;

	while (js_sw_port) {
		for (i = 0; i < js_sw_port->ndevs; i++)
			if (js_sw_port->devs[i])
				js_unregister_device(js_sw_port->devs[i]);
		info = js_sw_port->info;
		release_region(info->io, 1);
		js_sw_port = js_unregister_port(js_sw_port);
	}

}
#endif
joystick-1.2.15/joy-thrustmaster.c100644    766    144       15464  7020172152  16245 0ustar  vojtechusers/*
 *  joy-thrustmaster.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * ThrustMaster DirectConnect (BSP) joystick family.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/init.h>

#define JS_TM_MAX_START		400
#define JS_TM_MAX_STROBE	45
#define JS_TM_MAX_LENGTH	13

#define JS_TM_MODE_M3DI		1
#define JS_TM_MODE_3DRP		3
#define JS_TM_MODE_FGP		163

#define JS_TM_BYTE_ID		10
#define JS_TM_BYTE_REV		11
#define JS_TM_BYTE_DEF		12

static int js_tm_port_list[] __initdata = {0x201, 0};
static struct js_port* js_tm_port __initdata = NULL;

static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 };

struct js_tm_info {
	int io;
	unsigned char mode;
};

/*
 * js_tm_read_packet() reads a ThrustMaster packet.
 */

static int js_tm_read_packet(int io, unsigned char *data)
{
	unsigned int t, p;
	unsigned char u, v, error;
	int i, j;
	unsigned long flags;

	error = 0;
	i = j = 0;
	p = t = JS_TM_MAX_START;

	__save_flags(flags);
	__cli();
	outb(0xff,io);
	
	v = inb(io) >> 4;

	do {
		t--;
		u = v; v = inb(io) >> 4;
		if (~v & u & 2) {
			if (j) {
				if (j < 9) {				/* Data bit */
					data[i] |= (~v & 1) << (j - 1);
					j++;
				} else {				/* Stop bit */
					error |= v & 1;
					j = 0;
					i++;
				}
			} else {					/* Start bit */
				data[i] = 0;
				error |= ~v & 1;
				j++;
			}
			p = t = (p - t) << 1;
		}
	} while (!error && i < JS_TM_MAX_LENGTH && t > 0);

	__restore_flags(flags);

	return -(i != JS_TM_MAX_LENGTH);
}

/*
 * js_tm_read() reads and analyzes ThrustMaster joystick data.
 */

static int js_tm_read(void *xinfo, int **axes, int **buttons)
{
	struct js_tm_info *info = xinfo;
	unsigned char data[JS_TM_MAX_LENGTH];
	int i;

	if (js_tm_read_packet(info->io, data)) return -1;
	if (data[JS_TM_BYTE_ID] != info->mode) return -1;

	for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]];

	switch (info->mode) {

		case JS_TM_MODE_M3DI:

			axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1);
			axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]]       & 1);

			buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06)
				      | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30);

			return 0;

		case JS_TM_MODE_3DRP:
		case JS_TM_MODE_FGP:

			buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0)
				      | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300);

			return 0;

		default:

			buttons[0][0] = 0;

			for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++)
				buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3);

			return 0;

	}

	return -1;
}

/*
 * js_tm_open() is a callback from the file open routine.
 */

static int js_tm_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_tm_close() is a callback from the file release routine.
 */

static int js_tm_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_tm_init_corr() initializes the correction values for
 * ThrustMaster joysticks.
 */

static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
{
	int j = 0;

	for (; j < num_axes; j++) {
		corr[0][j].type = JS_CORR_BROKEN;
		corr[0][j].prec = 0;
		corr[0][j].coef[0] = 127 - 2;
		corr[0][j].coef[1] = 128 + 2;
		corr[0][j].coef[2] = (1 << 29) / (127 - 4);
		corr[0][j].coef[3] = (1 << 29) / (127 - 4);
	}

	switch (mode) {
		case JS_TM_MODE_M3DI: j = 4; break;
		default: break;
	}

	for (; j < num_axes; j++) {
		corr[0][j].type = JS_CORR_BROKEN;
		corr[0][j].prec = 0;
		corr[0][j].coef[0] = 0;
		corr[0][j].coef[1] = 0;
		corr[0][j].coef[2] = (1 << 29);
		corr[0][j].coef[3] = (1 << 29);
	}

}

/*
 * js_tm_probe() probes for ThrustMaster type joysticks.
 */

static struct js_port __init *js_tm_probe(int io, struct js_port *port)
{
	struct js_tm_info info;
	struct js_rm_models {
		unsigned char id;
		char *name;
		char axes;
		char buttons;
	} models[] = {	{   1, "ThrustMaster Millenium 3D Inceptor", 6, 6 },
			{   3, "ThrustMaster Rage 3D Gamepad", 2, 10 },
			{ 163, "Thrustmaster Fusion GamePad", 2, 10 },
			{   0, NULL, 0, 0 }};
	char name[64];
	unsigned char data[JS_TM_MAX_LENGTH];
	unsigned char a, b;
	int i;

	if (check_region(io, 1)) return port;

	if (js_tm_read_packet(io, data)) return port;

	info.io = io;
	info.mode = data[JS_TM_BYTE_ID];

	if (!info.mode) return port;

	for (i = 0; models[i].id && models[i].id != info.mode; i++);

	if (models[i].id != info.mode) {
		a = data[JS_TM_BYTE_DEF] >> 4;
		b = (data[JS_TM_BYTE_DEF] & 0xf) << 3;
		sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode);
	} else {
		sprintf(name, models[i].name);
		a = models[i].axes;
		b = models[i].buttons;
	}

	request_region(io, 1, "joystick (thrustmaster)");
	port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read);
	printk(KERN_INFO "js%d: %s revision %d at %#x\n",
		js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io);
	js_tm_init_corr(a, info.mode, port->axes, port->corr);

	return port;
}

#ifdef MODULE
int init_module(void)
#else
int __init js_tm_init(void)
#endif
{
	int *p;

	for (p = js_tm_port_list; *p; p++) js_tm_port = js_tm_probe(*p, js_tm_port);
	if (js_tm_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-thrustmaster: no joysticks found\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	struct js_tm_info *info;

	while (js_tm_port) {
		js_unregister_device(js_tm_port->devs[0]);
		info = js_tm_port->info;
		release_region(info->io, 1);
		js_tm_port = js_unregister_port(js_tm_port);
	}
}
#endif
joystick-1.2.15/joy-turbografx.c100644    766    144       14470  7020457177  15674 0ustar  vojtechusers/*
 *  joy-turbografx.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * Steffen Schwenke's <schwenke@burg-halle.de> TurboGraFX parallel port
 * interface.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
#include <linux/init.h>


MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_tg, "2-8i");
MODULE_PARM(js_tg_2, "2-8i");
MODULE_PARM(js_tg_3, "2-8i");

#define JS_TG_BUTTON1	0x08
#define JS_TG_UP	0x10
#define JS_TG_DOWN	0x20	
#define JS_TG_LEFT	0x40
#define JS_TG_RIGHT	0x80

#define JS_TG_BUTTON2	0x02
#define JS_TG_BUTTON3	0x04
#define JS_TG_BUTTON4	0x01
#define JS_TG_BUTTON5	0x08

static struct js_port* js_tg_port __initdata = NULL;

static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };

struct js_tg_info {
	struct pardevice *port;	/* parport device */
	int sticks;		/* joysticks connected */
};

/*
 * js_tg_read() reads and analyzes tg joystick data.
 */

static int js_tg_read(void *xinfo, int **axes, int **buttons)
{
	struct js_tg_info *info = xinfo;
	int data1, data2, i;

	for (i = 0; i < 7; i++)
		if ((info->sticks >> i) & 1) {

		JS_PAR_DATA_OUT(~(1 << i), info->port);
		data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
		data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT;

		axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0);
		axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP  ) ? 1 : 0);

		buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0)
			      | ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0)
			      | ((data2 & JS_TG_BUTTON5) ? 0x10 : 0);

	}

	return 0;
}

/*
 * open callback: claim parport.
 */

int js_tg_open(struct js_dev *dev)
{
	struct js_tg_info *info = dev->port->info;

	if (!MOD_IN_USE) {
		if (parport_claim(info->port)) return -EBUSY; 
		JS_PAR_CTRL_OUT(0x04, info->port);
	}
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * close callback: release parport
 */

int js_tg_close(struct js_dev *dev)
{
        struct js_tg_info *info = dev->port->info;

        MOD_DEC_USE_COUNT;
	if (!MOD_IN_USE) {
		JS_PAR_CTRL_OUT(0x00, info->port);
        	parport_release(info->port);
	}
        return 0;
}

#ifdef MODULE
void cleanup_module(void)
{
	struct js_tg_info *info;
	int i;

	while (js_tg_port) {
		for (i = 0; i < js_tg_port->ndevs; i++)
			if (js_tg_port->devs[i])
				js_unregister_device(js_tg_port->devs[i]);
		info = js_tg_port->info;
		parport_unregister_device(info->port);
		js_tg_port = js_unregister_port(js_tg_port);
	}
}
#endif

/*
 * js_tg_init_corr() initializes correction values of
 * tg gamepads.
 */

static void __init js_tg_init_corr(int sticks, struct js_corr **corr)
{
	int i, j;

	for (i = 0; i < 7; i++)
		if ((sticks >> i) & 1)
			for (j = 0; j < 2; j++) {
				corr[i][j].type = JS_CORR_BROKEN;
				corr[i][j].prec = 0;
				corr[i][j].coef[0] = 0;
				corr[i][j].coef[1] = 0;
				corr[i][j].coef[2] = (1 << 29);
				corr[i][j].coef[3] = (1 << 29);
			}
}

/*
 * js_tg_probe() probes for tg gamepads.
 */

static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
{
	struct js_tg_info iniinfo;
	struct js_tg_info *info = &iniinfo;
	struct parport *pp;
	int i;

	if (config[0] < 0) return port;


	if (config[0] > 0x10)
		for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
	else
		for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;

	if (!pp) {
		printk(KERN_ERR "joy-tg: no such parport\n");
		return port;
	}

	info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
	if (!info->port)
		return port;

	port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
	info = port->info;

	info->sticks = 0;

	for (i = 0; i < 7; i++)
		if (config[i+1] > 0 && config[i+1] < 6) {
			printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
				js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
				info->port->port->name);
			info->sticks |= (1 << i);
		}

        if (!info->sticks) {
		parport_unregister_device(info->port);
		return port;
        }
		
	js_tg_init_corr(info->sticks, port->corr);

	return port;
}

#ifndef MODULE
int __init js_tg_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
	return 1;
}
int __init js_tg_setup_2(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
	return 1;
}
int __init js_tg_setup_3(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
	return 1;
}
__setup("js_tg=", js_tg_setup);
__setup("js_tg_2=", js_tg_setup_2);
__setup("js_tg_3=", js_tg_setup_3);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_tg_init(void)
#endif
{
	js_tg_port = js_tg_probe(js_tg, js_tg_port);
	js_tg_port = js_tg_probe(js_tg_2, js_tg_port);
	js_tg_port = js_tg_probe(js_tg_3, js_tg_port);

	if (js_tg_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-tg: no joysticks specified\n");
#endif
	return -ENODEV;
}
joystick-1.2.15/joy-amiga.c100644    766    144        7075  7020453647  14550 0ustar  vojtechusers/*
 *  joy-amiga.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * microswitch based joystick connected to Amiga joystick port.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or
 * (at your option) any later version.
 *
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 *
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 *
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/system.h>
#include <linux/types.h>
#include <linux/errno.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <asm/amigahw.h>
#include <linux/init.h>

static struct js_port* js_am_port __initdata = NULL;

MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_am, "1-2i");

static int __initdata js_am[] = { 0, 0 };

/*
 * js_am_read() reads and Amiga joystick data.
 */

static int js_am_read(void *info, int **axes, int **buttons)
{
	int data = 0;

	switch (*(int*)info) {
		case 0:
			data = ~custom.joy0dat;
			buttons[0][0] = (~ciaa.pra >> 6) & 1;
			break;

		case 1:
			data = ~custom.joy1dat;
			buttons[0][0] = (~ciaa.pra >> 7) & 1;
			break;

		default:
			return -1;
	}

	axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
	data = ~(data ^ (data << 1));
	axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1);

	return 0;
}

/*
 * js_am_open() is a callback from the file open routine.
 */

static int js_am_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_am_close() is a callback from the file release routine.
 */

static int js_am_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_am_init_corr() initializes correction values of
 * Amiga joysticks.
 */

static void __init js_am_init_corr(struct js_corr **corr)
{
	int i;

	for (i = 0; i < 2; i++) {
		corr[0][i].type = JS_CORR_BROKEN;
		corr[0][i].prec = 0;
		corr[0][i].coef[0] = 0;
		corr[0][i].coef[1] = 0;
		corr[0][i].coef[2] = (1 << 29);
		corr[0][i].coef[3] = (1 << 29);
	}
}

#ifndef MODULE
int __init js_am_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(2);
	for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1];
	return 1;
}
__setup("js_am=", js_am_setup);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_am_init(void)
#endif
{
	int i;

	for (i = 0; i < 2; i++)
		if (js_am[i]) {
			js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read);
			printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n",
				js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", js_am_open, js_am_close), i);
			js_am_init_corr(js_am_port->corr);
		}
	if (js_am_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-amiga: no joysticks specified\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	while (js_am_port) {
		if (js_am_port->devs[0])
			js_unregister_device(js_am_port->devs[0]);
		js_am_port = js_unregister_port(js_am_port);
	}
}
#endif
joystick-1.2.15/joy-analog.c100644    766    144       16153  7021273451  14742 0ustar  vojtechusers/*
 *  joy-analog.c  Version 1.2
 *
 *  Copyright (c) 1996-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * up to two analog (or CHF/FCS) joysticks on a single joystick port.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/param.h>
#include <asm/system.h>
#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/sched.h>
#include <linux/string.h>
#include <linux/init.h>

#define JS_AN_MAX_TIME		3000	/* 3 ms */
#define JS_AN_LOOP_TIME		2000	/* 2 t */

static int js_an_port_list[] __initdata = {0x201, 0};
static struct js_port* js_an_port __initdata = NULL;

MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_an, "2-24i");

static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };

#include "joy-analog.h"

struct js_ax_info {
        int io;
	int speed;
	int loop;
	int timeout;
        struct js_an_info an;
};

/*
 * Time macros.
 */

#ifdef __i386__
#ifdef CONFIG_X86_TSC
#define GET_TIME(x)	__asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
#define DELTA(x,y)	((x)-(y))
#define TIME_NAME "TSC"
#else
#define GET_TIME(x)	do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
#define DELTA(x,y)	((y)-(x)+((y)<(x)?1193180L/HZ:0))
#define TIME_NAME "PIT"
#endif
#elif __alpha__
#define GET_TIME(x)	__asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
#define DELTA(x,y)	((x)-(y))
#define TIME_NAME "PCC"
#endif

#ifndef GET_TIME
#define FAKE_TIME
static unsigned long js_an_faketime = 0;
#define GET_TIME(x)     do { x = js_an_faketime++; } while(0)
#define DELTA(x,y)	((x)-(y))
#define TIME_NAME "Unreliable"
#endif

/*
 * js_an_read() reads analog joystick data.
 */

static int js_an_read(void *xinfo, int **axes, int **buttons)
{
	struct js_ax_info *info = xinfo;
	struct js_an_info *an = &info->an;
	int io = info->io;
	unsigned long flags;
	unsigned char buf[4];
	unsigned int time[4];
	unsigned char u, v, w;
	unsigned int p, q, r, s, t;
	int i, j;

	an->buttons = ~inb(io) >> 4;

	i = 0;
	w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS)
	  | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
	p = info->loop;
	q = info->timeout;
	
	__save_flags(flags);
	__cli();
	outb(0xff,io);
	GET_TIME(r);
	__restore_flags(flags);
	t = r;
	v = w;
	do {
		s = t;
		u = v;
		__cli();
		v = inb(io) & w;
		GET_TIME(t);
		__restore_flags(flags);
		if ((u ^ v) && (DELTA(t,s) < p)) {
			time[i] = t;
			buf[i] = u ^ v;
			i++;
		}
	} while (v && (i < 4) && (DELTA(t,r) < q));

	v <<= 4;

	for (--i; i >= 0; i--) {
		v |= buf[i];
		for (j = 0; j < 4; j++)
			if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
	}

	js_an_decode(an, axes, buttons);

	return -(v != w);
}

/*
 * js_an_open() is a callback from the file open routine.
 */

static int js_an_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_an_close() is a callback from the file release routine.
 */

static int js_an_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_an_calibrate_timer() calibrates the timer and computes loop
 * and timeout values for a joystick port.
 */

static void __init js_an_calibrate_timer(struct js_ax_info *info)
{
	unsigned int i, t, tx, t1, t2, t3;
	unsigned long flags;
	int io = info->io;

	save_flags(flags);
	cli();
	GET_TIME(t1);
#ifdef FAKE_TIME
	js_an_faketime += 830;
#endif
	udelay(1000);
	GET_TIME(t2);
	GET_TIME(t3);
	restore_flags(flags);

	info->speed = DELTA(t2, t1) - DELTA(t3, t2);

	tx = 1 << 30;

	for(i = 0; i < 50; i++) {
		save_flags(flags);
		cli();
		GET_TIME(t1);
		for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); }
		GET_TIME(t3);
		restore_flags(flags);
		udelay(i);
		if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
	}

        info->loop = (JS_AN_LOOP_TIME * t) / 50000;
	info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000;
}

/*
 * js_an_probe() probes for analog joysticks.
 */

static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port)
{
	struct js_ax_info info, *ax;
	int i, numdev;
	unsigned char u;

	if (io < 0) return port;

	if (check_region(io, 1)) return port;

	outb(0xff,io);
	u = inb(io);
	udelay(JS_AN_MAX_TIME);
	u = (inb(io) ^ u) & u;

	if (!u) return port;
	if (u & 0xf0) return port;

	if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0)
		return port;

	info.io = io;
	js_an_calibrate_timer(&info);

	request_region(info.io, 1, "joystick (analog)");
	port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read);
	ax = port->info;	

	for (i = 0; i < numdev; i++)
		printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
			js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
				js_an_name(i, &ax->an), js_an_open, js_an_close),
			js_an_name(i, &ax->an),
			ax->io,
			ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
			ax->speed > 10000 ? "M" : "k",
			ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);

	js_an_read(ax, port->axes, port->buttons);
	js_an_init_corr(&ax->an, port->axes, port->corr, 8);

	return port;
}

#ifndef MODULE
int __init js_an_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(24);
	for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1];
	return 1;
}
__setup("js_an=", js_an_setup);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_an_init(void)
#endif
{
	int i;

	if (js_an[0] >= 0) {
		for (i = 0; (js_an[i*3] >= 0) && i < 8; i++)
			js_an_port = js_an_probe(js_an[i*3], js_an[i*3+1], js_an[i*3+2], js_an_port);
	} else {
		for (i = 0; js_an_port_list[i]; i++)
			js_an_port = js_an_probe(js_an_port_list[i], 0, 0, js_an_port);
	}
	if (js_an_port) return 0;

#ifdef MODULE
	printk(KERN_WARNING "joy-analog: no joysticks found\n");
#endif

	return -ENODEV;
}

#ifdef MODULE
void cleanup_module(void)
{
	int i;
	struct js_ax_info *info;

	while (js_an_port) {
		for (i = 0; i < js_an_port->ndevs; i++)
			if (js_an_port->devs[i])
				js_unregister_device(js_an_port->devs[i]);
		info = js_an_port->info;
		release_region(info->io, 1);
		js_an_port = js_unregister_port(js_an_port);
	}

}
#endif
joystick-1.2.15/joy-analog.h100644    766    144       20113  7021273360  14735 0ustar  vojtechusers/*
 *  joy-analog.h  Version 1.2
 *
 *  Copyright (c) 1996-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This file is designed to be included in any joystick driver
 * that communicates with standard analog joysticks. This currently
 * is: joy-analog.c, joy-assassin.c, and joy-lightning.c
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <linux/bitops.h>

#define JS_AN_AXES_STD		0x0f
#define JS_AN_BUTTONS_STD	0xf0

#define JS_AN_BUTTONS_CHF	0x01
#define JS_AN_HAT1_CHF		0x02
#define JS_AN_HAT2_CHF		0x04
#define JS_AN_ANY_CHF		0x07
#define JS_AN_HAT_FCS		0x08
#define JS_AN_HATS_ALL		0x0e
#define JS_AN_BUTTON_PXY_X	0x10
#define JS_AN_BUTTON_PXY_Y	0x20
#define JS_AN_BUTTON_PXY_U	0x40
#define JS_AN_BUTTON_PXY_V	0x80
#define JS_AN_BUTTONS_PXY_XY	0x30
#define JS_AN_BUTTONS_PXY_UV	0xc0
#define JS_AN_BUTTONS_PXY	0xf0

static struct {
	int x;
	int y;
} js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}};

struct js_an_info {
	unsigned char mask[2];
	unsigned int extensions;
	int axes[4];
	int initial[4];
	unsigned char buttons;
};

/*
 * js_an_decode() decodes analog joystick data.
 */

static void js_an_decode(struct js_an_info *info, int **axes, int **buttons)
{
	int i, j, k;
	int hat1, hat2, hat3;

	hat1 = hat2 = hat3 = 0;
	if (info->mask[0] & JS_AN_BUTTONS_STD) buttons[0][0] = 0;
	if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0;

	if (info->extensions & JS_AN_ANY_CHF) {
		switch (info->buttons & 0xf) {
			case 0x1: buttons[0][0] = 0x01; break;
			case 0x2: buttons[0][0] = 0x02; break;
			case 0x4: buttons[0][0] = 0x04; break;
			case 0x8: buttons[0][0] = 0x08; break;
			case 0x5: buttons[0][0] = 0x10; break;
			case 0x9: buttons[0][0] = 0x20; break;
			case 0xf: hat1 = 1; break;
			case 0xb: hat1 = 2; break;
			case 0x7: hat1 = 3; break;
			case 0x3: hat1 = 4; break;
			case 0xe: hat2 = 1; break;
			case 0xa: hat2 = 2; break;
			case 0x6: hat2 = 3; break;
			case 0xc: hat2 = 4; break;
		}
		k = info->extensions & JS_AN_BUTTONS_CHF ? 6 : 4;
	} else {
		for (i = 1; i >= 0; i--)
			for (j = k = 0; j < 4; j++)
				if (info->mask[i] & (0x10 << j))
					buttons[i][0] |= ((info->buttons >> j) & 1) << k++;
	}

	if (info->extensions & JS_AN_BUTTON_PXY_X)
		buttons[0][0] |= (info->axes[2] < (info->initial[2] >> 1)) << k++;
	if (info->extensions & JS_AN_BUTTON_PXY_Y)
		buttons[0][0] |= (info->axes[3] < (info->initial[3] >> 1)) << k++;
	if (info->extensions & JS_AN_BUTTON_PXY_U)
		buttons[0][0] |= (info->axes[2] > (info->initial[2] + (info->initial[2] >> 1))) << k++;
	if (info->extensions & JS_AN_BUTTON_PXY_V)
		buttons[0][0] |= (info->axes[3] > (info->initial[3] + (info->initial[3] >> 1))) << k++;

	if (info->extensions & JS_AN_HAT_FCS)
		for (j = 0; j < 4; j++)
			if (info->axes[3] < ((info->initial[3] * ((j << 1) + 1)) >> 3)) {
				hat3 = j + 1;
				break;
			}

	for (i = 1; i >= 0; i--)
		for (j = k = 0; j < 4; j++)
			if (info->mask[i] & (1 << j))
				axes[i][k++] = info->axes[j];

	if (info->extensions & JS_AN_HAT1_CHF) {
		axes[0][k++] = js_an_hat_to_axis[hat1].x;
		axes[0][k++] = js_an_hat_to_axis[hat1].y;
	}
	if (info->extensions & JS_AN_HAT2_CHF) {
		axes[0][k++] = js_an_hat_to_axis[hat2].x;
		axes[0][k++] = js_an_hat_to_axis[hat2].y;
	}
	if (info->extensions & JS_AN_HAT_FCS) {
		axes[0][k++] = js_an_hat_to_axis[hat3].x;
		axes[0][k++] = js_an_hat_to_axis[hat3].y;
	}
}


/*
 * js_an_init_corr() initializes the correction values for
 * analog joysticks.
 */

static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct js_corr **corr, int prec)
{
	int i, j, t;

	for (i = 0; i < 2; i++)
	for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) {

		if ((j == 2 && (info->mask[i] & 0xb) == 0xb) ||
		    (j == 3 && (info->mask[i] & 0xf) == 0xf)) {
			t = (axes[i][0] + axes[i][1]) >> 1;
		} else {
			t = axes[i][j];
		}

		corr[i][j].type = JS_CORR_BROKEN;
		corr[i][j].prec = prec;
		corr[i][j].coef[0] = t - (t >> 3);
		corr[i][j].coef[1] = t + (t >> 3);
		corr[i][j].coef[2] = (1 << 29) / (t - (t >> 2) + 1);
		corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1);
	}

	i = hweight8(info->mask[0] & 0xf);

	for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
		corr[0][j].type = JS_CORR_BROKEN;
		corr[0][j].prec = 0;
		corr[0][j].coef[0] = 0;
		corr[0][j].coef[1] = 0;
		corr[0][j].coef[2] = (1 << 29);
		corr[0][j].coef[3] = (1 << 29);
	}

	for (i = 0; i < 4; i++)
		info->initial[i] = info->axes[i];
}


/*
 * js_an_probe_devs() probes for analog joysticks.
 */

static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0, int mask1, struct js_port *port)
{
	info->mask[0] = info->mask[1] = info->extensions = 0;

	if (mask0 || mask1) {
		info->mask[0] = mask0 & (exist | 0xf0);
		info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0];
		info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) |
					((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF);

		if (info->extensions & JS_AN_BUTTONS_PXY) {
			info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2);
			info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
			info->mask[1] = 0;
		}
		if (info->extensions & JS_AN_HAT_FCS) {
			info->mask[0] &= ~JS_AN_HAT_FCS;
			info->mask[1] = 0;
			info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V);
		}
		if (info->extensions & JS_AN_ANY_CHF) {
			info->mask[0] |= 0xf0;
			info->mask[1] = 0;
		}
		if (!(info->mask[0] | info->mask[1])) return -1;
	} else {
		switch (exist) {
			case 0x0:
				return -1;
			case 0x3:
				info->mask[0] = 0xf3; /* joystick 0, assuming 4-button */
				break;
			case 0xb:
				info->mask[0] = 0xfb; /* 3-axis, 4-button joystick */
				break;
			case 0xc:
				info->mask[0] = 0xcc; /* joystick 1 */
				break;
			case 0xf:
				info->mask[0] = 0xff; /* 4-axis 4-button joystick */
				break;
			default:
				printk(KERN_WARNING "joy-analog: Unknown joystick device detected "
					"(data=%#x), contact <vojtech@suse.cz>\n", exist);
				return -1;
		}
	}

	return !!info->mask[0] + !!info->mask[1];
}

/*
 * js_an_axes() returns the number of axes for an analog joystick.
 */

static inline int js_an_axes(int i, struct js_an_info *info)
{
	return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2;
}

/*
 * js_an_buttons() returns the number of buttons for an analog joystick.
 */

static inline int js_an_buttons(int i, struct js_an_info *info)
{
	return hweight8(info->mask[i] & 0xf0) +
	       (info->extensions & JS_AN_BUTTONS_CHF) * 2 +
	       hweight8(info->extensions & JS_AN_BUTTONS_PXY);
}

/*
 * js_an_name() constructs a name for an analog joystick.
 */

static char js_an_name_buf[128] __initdata = "";

static char __init *js_an_name(int i, struct js_an_info *info)
{

	sprintf(js_an_name_buf, "Analog %d-axis %d-button",
		hweight8(info->mask[i] & 0x0f),
		js_an_buttons(i, info));

	if (info->extensions & JS_AN_HATS_ALL)
		sprintf(js_an_name_buf, "%s %d-hat",
			js_an_name_buf,
			hweight8(info->extensions & JS_AN_HATS_ALL));

	strcat(js_an_name_buf, " joystick");

	if (info->extensions)
		sprintf(js_an_name_buf, "%s with%s%s%s extensions",
			js_an_name_buf,
			info->extensions & JS_AN_ANY_CHF ? " CHF" : "",
			info->extensions & JS_AN_HAT_FCS ? " FCS" : "",
			info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : "");

	return js_an_name_buf;
}
joystick-1.2.15/joy-lightning.c100644    766    144       21200  7020454233  15447 0ustar  vojtechusers/*
 *  joy-lightning.c  Version 1.2
 *
 *  Copyright (c) 1998-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is a module for the Linux joystick driver, supporting
 * PDPI Lightning 4 gamecards and analog joysticks connected
 * to them.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/ioport.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
#include <linux/init.h>

#define JS_L4_PORT		0x201
#define JS_L4_SELECT_ANALOG	0xa4
#define JS_L4_SELECT_DIGITAL	0xa5
#define JS_L4_SELECT_SECONDARY	0xa6
#define JS_L4_CMD_ID		0x80
#define JS_L4_CMD_GETCAL	0x92
#define JS_L4_CMD_SETCAL	0x93
#define JS_L4_ID		0x04
#define JS_L4_BUSY		0x01
#define JS_L4_TIMEOUT		80	/* 80 us */

static struct js_port* __initdata js_l4_port = NULL;

MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_l4, "2-24i");

static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };

#include "joy-analog.h"

struct js_l4_info {
	int port;
	struct js_an_info an;
};

/*
 * js_l4_wait_ready() waits for the L4 to become ready.
 */

static int js_l4_wait_ready(void)
{
	unsigned int t;
	t = JS_L4_TIMEOUT;
	while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
	return -(t<=0);
}

/*
 * js_l4_read() reads data from the Lightning 4.
 */

static int js_l4_read(void *xinfo, int **axes, int **buttons)
{
	struct js_l4_info *info = xinfo;
	int i;
	unsigned char status;

	outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
	outb(JS_L4_SELECT_DIGITAL + (info->port >> 2), JS_L4_PORT);

	if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
	outb(info->port & 3, JS_L4_PORT);

	if (js_l4_wait_ready()) return -1;
	status = inb(JS_L4_PORT);

	for (i = 0; i < 4; i++)
		if (status & (1 << i)) {
			if (js_l4_wait_ready()) return -1;
			info->an.axes[i] = inb(JS_L4_PORT);
		}

	if (status & 0x10) {
		if (js_l4_wait_ready()) return -1;
		info->an.buttons = inb(JS_L4_PORT);
	}

	js_an_decode(&info->an, axes, buttons);

	return 0;
}

/*
 * js_l4_getcal() reads the L4 with calibration values.
 */

static int js_l4_getcal(int port, int *cal)
{
	int i;
	
	outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
	outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);

	if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
	outb(JS_L4_CMD_GETCAL, JS_L4_PORT);

	if (js_l4_wait_ready()) return -1;
	if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;

	if (js_l4_wait_ready()) return -1;
        outb(port & 3, JS_L4_PORT);

	for (i = 0; i < 4; i++) {
		if (js_l4_wait_ready()) return -1;
		cal[i] = inb(JS_L4_PORT);
	}

	return 0;
}

/*
 * js_l4_setcal() programs the L4 with calibration values.
 */

static int js_l4_setcal(int port, int *cal)
{
	int i;

	outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
	outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);

	if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
	outb(JS_L4_CMD_SETCAL, JS_L4_PORT);

	if (js_l4_wait_ready()) return -1;
	if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;

	if (js_l4_wait_ready()) return -1;
        outb(port & 3, JS_L4_PORT);

	for (i = 0; i < 4; i++) {
		if (js_l4_wait_ready()) return -1;
		outb(cal[i], JS_L4_PORT);
	}

	return 0;
}

/*
 * js_l4_calibrate() calibrates the L4 for the attached device, so
 * that the device's resistance fits into the L4's 8-bit range.
 */

static void js_l4_calibrate(struct js_l4_info *info)
{
	int i;
	int cal[4];
	int axes[4];
	int t;

	js_l4_getcal(info->port, cal);

	for (i = 0; i < 4; i++)
		axes[i] = info->an.axes[i];
	
	if ((info->an.extensions & JS_AN_BUTTON_PXY_X) && !(info->an.extensions & JS_AN_BUTTON_PXY_U))
		axes[2] >>= 1;							/* Pad button X */

	if ((info->an.extensions & JS_AN_BUTTON_PXY_Y) && !(info->an.extensions & JS_AN_BUTTON_PXY_V))
		axes[3] >>= 1;							/* Pad button Y */

	if (info->an.extensions & JS_AN_HAT_FCS) 
		axes[3] >>= 1;							/* FCS hat */

	if (((info->an.mask[0] & 0xb) == 0xb) || ((info->an.mask[1] & 0xb) == 0xb))
		axes[3] = (axes[0] + axes[1]) >> 1;				/* Throttle */

	for (i = 0; i < 4; i++) {
		t = (axes[i] * cal[i]) / 100;
		if (t > 255) t = 255;
		info->an.axes[i] = (info->an.axes[i] * cal[i]) / t;
		cal[i] = t;
	}

	js_l4_setcal(info->port, cal);
}
	
/*
 * js_l4_open() is a callback from the file open routine.
 */

static int js_l4_open(struct js_dev *jd)
{
	MOD_INC_USE_COUNT;
	return 0;
}

/*
 * js_l4_close() is a callback from the file release routine.
 */

static int js_l4_close(struct js_dev *jd)
{
	MOD_DEC_USE_COUNT;
	return 0;
}

/*
 * js_l4_probe() probes for joysticks on the L4 cards.
 */

static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int mask0, int mask1, struct js_port *port)
{
	struct js_l4_info iniinfo;
	struct js_l4_info *info = &iniinfo;
	int cal[4] = {255,255,255,255};
	int i, numdev;
	unsigned char u;

	if (l4port < 0) return port;
	if (!cards[(l4port >> 2)]) return port;

	memset(info, 0, sizeof(struct js_l4_info));
	info->port = l4port;

	if (cards[l4port >> 2] > 0x28) js_l4_setcal(info->port, cal);
	if (js_l4_read(info, NULL, NULL)) return port;

	for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 253) u |= 1 << i;

	if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
		return port;

	port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);

	info = port->info;

	for (i = 0; i < numdev; i++)
		printk(KERN_INFO "js%d: %s on L4 port %d\n",
			js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
				js_an_name(i, &info->an), js_l4_open, js_l4_close),
			js_an_name(i, &info->an), info->port);

	js_l4_calibrate(info);
	js_l4_read(info, port->axes, port->buttons);
	js_an_init_corr(&info->an, port->axes, port->corr, 0);

	return port;
}

/*
 * js_l4_card_probe() probes for presence of the L4 card(s).
 */

static void __init js_l4_card_probe(unsigned char *cards)
{
	int i;
	unsigned char rev = 0;

	if (check_region(JS_L4_PORT, 1)) return;

	for (i = 0; i < 2; i++) {

		outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
		outb(JS_L4_SELECT_DIGITAL + i, JS_L4_PORT);		/* Select card 0-1 */

		if (inb(JS_L4_PORT) & JS_L4_BUSY) continue;
		outb(JS_L4_CMD_ID, JS_L4_PORT);				/* Get card ID & rev */

		if (js_l4_wait_ready()) continue;
		if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + i) continue;

		if (js_l4_wait_ready()) continue;
		if (inb(JS_L4_PORT) != JS_L4_ID) continue;

		if (js_l4_wait_ready()) continue;
		rev = inb(JS_L4_PORT);

		cards[i] = rev; 

		printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n",
			i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT);
	}

}

#ifndef MODULE
int __init js_l4_setup(SETUP_PARAM)
{
	int i;
	SETUP_PARSE(24);
	for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1];
	return 1;
}
__setup("js_l4=", js_l4_setup);
#endif

#ifdef MODULE
int init_module(void)
#else
int __init js_l4_init(void)
#endif
{
	int i;
	unsigned char cards[2] = {0, 0};

	js_l4_card_probe(cards);

	if (js_l4[0] >= 0) {
		for (i = 0; (js_l4[i*3] >= 0) && i < 8; i++)
			js_l4_port = js_l4_probe(cards, js_l4[i*3], js_l4[i*3+1], js_l4[i*3+2], js_l4_port);
	} else {
		for (i = 0; i < 8; i++)
			js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
	}

	if (!js_l4_port) {
#ifdef MODULE
		printk(KERN_WARNING "joy-lightning: no joysticks found\n");
#endif
		return -ENODEV;
	}

	request_region(JS_L4_PORT, 1, "joystick (lightning)");

	return 0;
}

#ifdef MODULE
void cleanup_module(void)
{
	int i;
	int cal[4] = {59, 59, 59, 59};
	struct js_l4_info *info;

	while (js_l4_port) {
		for (i = 0; i < js_l4_port->ndevs; i++)
			if (js_l4_port->devs[i])
				js_unregister_device(js_l4_port->devs[i]);
		info = js_l4_port->info;
		js_l4_setcal(info->port, cal);
		js_l4_port = js_unregister_port(js_l4_port);
	}
	outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
	release_region(JS_L4_PORT, 1);
}
#endif
joystick-1.2.15/joystick-api.txt100644    766    144       22630  6773501742  15714 0ustar  vojtechusers		      Joystick API Documentation                -*-Text-*-

		       Ragnar Hojland Espinosa
		     <ragnar@lightside.dhis.org>

			      7 Aug 1998


1. Initialization
~~~~~~~~~~~~~~~~~

Open the joystick device following the usual semantics (that is, with open).
Since the driver now reports events instead of polling for changes,
immediately after the open it will issue a series of synthetic events
(JS_EVENT_INIT) that you can read to check the initial state of the
joystick.

By default, the device is opened in blocking mode.

	int fd = open ("/dev/js0", O_RDONLY);


2. Event Reading
~~~~~~~~~~~~~~~~

	struct js_event e;
	read (fd, &e, sizeof(struct js_event));

where js_event is defined as

	struct js_event {
		__u32 time;     /* event timestamp in miliseconds */
		__s16 value;    /* value */
		__u8 type;      /* event type */
		__u8 number;    /* axis/button number */
	};

If the read is successfull, it will return sizeof(struct js_event), unless
you wanted to read more than one event per read as described in section 3.1.


2.1 js_event.type
~~~~~~~~~~~~~~~~~

The possible values of ``type'' are

	#define JS_EVENT_BUTTON         0x01    /* button pressed/released */
	#define JS_EVENT_AXIS           0x02    /* joystick moved */
	#define JS_EVENT_INIT           0x80    /* initial state of device */

As mentioned above, the driver will issue synthetic JS_EVENT_INIT ORed
events on open. That is, if it's issuing a INIT BUTTON event, the
current type value will be

	int type = JS_EVENT_BUTTON | JS_EVENT_INIT;	/* 0x81 */

If you choose not to differentiate between synthetic or real events
you can turn off the JS_EVENT_INIT bits

	type &= ~JS_EVENT_INIT;				/* 0x01 */


2.2 js_event.number
~~~~~~~~~~~~~~~~~~~

The values of ``number'' correspond to the axis or button that
generated the event. Note that they carry separate numeration (that
is, you have both an axis 0 and a button 0). Generally,

			number
	1st Axis X	0
	1st Axis Y	1
	2nd Axis X	2
	2nd Axis Y	3
	...and so on

Hats vary from one joystick type to another. Some can be moved in 8
directions, some only in 4, The driver, however, always reports a hat as two
independent axis, even if the hardware doesn't allow independent movement.


2.3 js_event.value
~~~~~~~~~~~~~~~~~~

For an axis, ``value'' is a signed integer between -32767 and +32767
representing the position of the joystick along that axis. If you
don't read a 0 when the joystick is `dead', or if it doesn't span the
full range, you should recalibrate it (with, for example, jscal).

For a button, ``value'' for a press button event is 1 and for a release
button event is 0.

Though this

	if (js_event.type == JS_EVENT_BUTTON) {
		buttons_state ^= (1 << js_event.number);
	}

may work well if you handle JS_EVENT_INIT events separately,

	if ((js_event.type & ~JS_EVENT_INIT) == JS_EVENT_BUTTON) {
		if (js_event.value)
	        	buttons_state |= (1 << js_event.number);
	   	else
	      		buttons_state &= ~(1 << js_event.number);
	}

is much safer since it can't lose sync with the driver. As you would
have to write a separate handler for JS_EVENT_INIT events in the first
snippet, this ends up being shorter.


2.4 js_event.time
~~~~~~~~~~~~~~~~~

The time an event was generated is stored in ``js_event.time''. It's a time
in miliseconds since ... well, since sometime in the past.  This eases the
task of detecting double clicks, figuring out if movement of axis and button
presses happened at the same time, and similar.


3. Reading
~~~~~~~~~~

If you open the device in blocking mode, a read will block (that is,
wait) forever until an event is generated and effectively read. There
are two alternatives if you can't afford to wait forever (which is,
admittedly, a long time;)

	a) use select to wait until there's data to be read on fd, or
	   until it timeouts. There's a good example on the select(2)
	   man page.

	b) open the device in non-blocking mode (O_NONBLOCK)


3.1 O_NONBLOCK
~~~~~~~~~~~~~~

If read returns -1 when reading in O_NONBLOCK mode, this isn't
necessarily a "real" error (check errno(3)); it can just mean there
are no events pending to be read on the driver queue. You should read
all events on the queue (that is, until you get a -1).

For example,

	while (1) {
		while (read (fd, &e, sizeof(struct js_event)) > 0) {
	        	process_event (e);
	   	}
	   	/* EAGAIN is returned when the queue is empty */
	   	if (errno != EAGAIN) {
	      		/* error */
	   	}
	   	/* do something interesting with processed events */
	}

One reason for emptying the queue is that if it gets full you'll start
missing events since the queue is finite, and older events will get
overwritten.

The other reason is that you want to know all what happened, and not
delay the processing till later.

Why can get the queue full? Because you don't empty the queue as
mentioned, or because too much time elapses from one read to another
and too many events to store in the queue get generated. Note that
high system load may contribute to space those reads even more.

If time between reads is enough to fill the queue and loose an event,
the driver will switch to startup mode and next time you read it,
synthetic events (JS_EVENT_INIT) will be generated to inform you of
the actual state of the joystick.

[As for version 1.2.8, the queue is circular and able to hold 64
 events. You can increment this size bumping up JS_BUFF_SIZE in
 joystick.h and recompiling the driver.]


In the above code, you might as well want to read more than one event
at a time using the typical read(2) functionality. For that, you would
replace the read above with something like

	struct js_event mybuffer[0xff];
	int i = read (fd, mybuffer, sizeof(struct mybuffer));

In this case, read would return -1 if the queue was empty, or some
other value in which the number of events read would be i /
sizeof(js_event)  Again, if the buffer was full, it's a good idea to
process the events and keep reading it until you empty the driver queue.


4. IOCTLs
~~~~~~~~~

The joystick driver defines the following ioctl(2) operations.

				/* function			3rd arg  */
	#define JSIOCGAXES	/* get number of axes		char	 */
	#define JSIOCGBUTTONS	/* get number of buttons	char	 */
	#define JSIOCGVERSION	/* get driver version		int	 */
	#define JSIOCGNAME(len) /* get identifier string	char	 */
	#define JSIOCSCORR	/* set correction values	&js_corr */
	#define JSIOCGCORR	/* get correction values	&js_corr */

For example, to read the number of axes

	char number_of_axes;
	ioctl (fd, JSIOCGAXES, &number_of_axes);


4.1 JSIOGCVERSION
~~~~~~~~~~~~~~~~~

JSIOGCVERSION is a good way to check in run-time whether the running
driver is 1.0+ and supports the event interface. If it is not, the
IOCTL will fail. For a compile-time decision, you can test the
JS_VERSION symbol

	#ifdef JS_VERSION
	#if JS_VERSION > 0xsomething


4.2 JSIOCGNAME
~~~~~~~~~~~~~~

JSIOCGNAME(len) allows you to get the name string of the joystick - the same
as is being printed at boot time. The 'len' argument is the lenght of the
buffer provided by the application asking for the name. It is used to avoid
possible overrun should the name be too long.

	char name[128];
	if (ioctl(fd, JSIOCGNAME(sizeof(name)), name) < 0)
		strncpy(name, "Unknown", sizeof(name));
	printf("Name: %s\n", name);


4.3 JSIOC[SG]CORR
~~~~~~~~~~~~~~~~~

For usage on JSIOC[SG]CORR I suggest you to look into jscal.c  They are
not needed in a normal program, only in joystick calibration software
such as jscal or kcmjoy. These IOCTLs and data types aren't considered
to be in the stable part of the API, and therefore may change without
warning in following releases of the driver.

Both JSIOCSCORR and JSIOCGCORR expect &js_corr to be able to hold
information for all axis. That is, struct js_corr corr[MAX_AXIS];

struct js_corr is defined as

	struct js_corr {
		__s32 coef[8];
		__u16 prec;
		__u16 type;
	};

and ``type''

	#define JS_CORR_NONE            0x00    /* returns raw values */
	#define JS_CORR_BROKEN          0x01    /* broken line */


5. Backward compatibility
~~~~~~~~~~~~~~~~~~~~~~~~~

The 0.x joystick driver API is quite limited and its usage is deprecated.
The driver offers backward compatibility, though. Here's a quick summary:

	struct JS_DATA_TYPE js;
	while (1) {
		if (read (fd, &js, JS_RETURN) != JS_RETURN) {
	      		/* error */
	   	}
	   	usleep (1000);
	}

As you can figure out from the example, the read returns immediately,
with the actual state of the joystick.

	struct JS_DATA_TYPE {
		int buttons;    /* immediate button state */
		int x;          /* immediate x axis value */
		int y;          /* immediate y axis value */
	};

and JS_RETURN is defined as

	#define JS_RETURN       sizeof(struct JS_DATA_TYPE)

To test the state of the buttons,

	first_button_state  = js.buttons & 1;
	second_button_state = js.buttons & 2;

The axis values do not have a defined range in the original 0.x driver,
except for that the values are non-negative. The 1.2.8+ drivers use a
fixed range for reporting the values, 1 being the minimum, 128 the
center, and 255 maximum value.

The v0.8.0.2 driver also had an interface for 'digital joysticks', (now
called Multisystem joysticks in this driver), under /dev/djsX. This driver
doesn't try to be compatible with that interface.


6. Final Notes
~~~~~~~~~~~~~~

____/|	Comments, additions, and specially corrections are welcome.
\ o.O|	Documentation valid for at least version 1.2.8 of the joystick
 =(_)=	driver and as usual, the ultimate source for documentation is
   U	to "Use The Source Luke" or, at your convenience, Vojtech ;)

					- Ragnar
EOF
joystick-1.2.15/joystick-parport.txt100644    766    144       47767  7020322243  16633 0ustar  vojtechusers		  Linux Joystick parport drivers v1.2 BETA
	       (c) 1998-1999 Vojtech Pavlik <vojtech@suse.cz>
	       (c) 1998 Andree Borrmann <a.borrmann@tu-bs.de>
			     Sponsored by SuSE
----------------------------------------------------------------------------

0. Disclaimer
~~~~~~~~~~~~~
  Any information in this file is provided as-is, without any guarantee that
it will be true. So, use it at your own risk. The possible damages that can
happen include burning your parallel port, and/or the sticks and joystick
and maybe even more. Like when a lightning kills you it is not our problem.

1. Intro
~~~~~~~~
  The joystick parport drivers are used for joysticks and gamepads not
originally designed for PCs and other computers Linux runs on. Because of
that, PCs usually lack the right ports to connect these devices to. Parallel
port, because of its ability to change single bits at will, and providing
both output and input bits is the most suitable port on the PC for
connecting such devices.

2. Devices supported
~~~~~~~~~~~~~~~~~~~~
  Many console and 8-bit coputer gamepads and joysticks are supported. The
following subsections discuss usage of each.

2.1 NES and SNES
~~~~~~~~~~~~~~~~
  The Nintendo Entertainment System and Super Nintendo Entertainment System
gamepads are widely available, and easy to get. Also, they are quite easy to
connect to a PC, and don't need much processing speed (108 us for NES and
165 us for SNES, compared to about 1000 us for PC gamepads) to communicate
with them.

  All NES and SNES use the same synchronous serial protocol, clocked from
the computer's side (and thus timing insensitive). To allow up to 5 NES
and/or SNES gamepads connected to the parallel port at once, the output
lines of the parallel port are shared, while one of 5 available input lines
is assigned to each gamepad.

  This protocol is handled by the joy-console.c driver, so that's the one
you'll use for NES and SNES gamepads.

  The main problem with PC parallel ports is that they don't have +5V power
source on any of their pins. So, if you want a reliable source of power
for your pads, use either keyboard or joystick port, and make a pass-through
cable. You can also pull the power directly from the power supply (the red
wire is +5V).

  If you want to use the parallel port only, you can take the power is from
some data pin. For most gamepad and parport implementations only one pin is
needed, and I'd recommend pin 9 for that, the highest data bit. On the other
hand, if you are not planning to use anything else than NES / SNES on the
port, anything between and including pin 4 and pin 9 will work.

(pin 9) -----> Power

  Unfortunately, there are pads that need a lot more of power, and parallel
ports that can't give much current through the data pins. If this is your
case, you'll need to use diodes (as a prevention of destroying your parallel
port), and combine the currents of two or more data bits together.

	   Diodes
(pin 9) ----|>|-------+------> Power
		      |
(pin 8) ----|>|-------+
		      |
(pin 7) ----|>|-------+
		      |
 <and so on>          :
		      |
(pin 4) ----|>|-------+

  Ground is quite easy. On PC's parallel port the ground is on any of the
pins from pin 18 to pin 25. So use any pin of these you like for the ground.

(pin 18) -----> Ground

  NES and SNES pads have two input bits, Clock and Latch, which drive the
serial transfer. These are connected to pins 2 and 3 of the parallel port,
respectively.

(pin 2) -----> Clock
(pin 3) -----> Latch

  And the last thing is the NES / SNES data wire. Only that isn't shared and
each pad needs its own data pin. The parallel port pins are:

(pin 10) -----> Pad 1 data
(pin 11) -----> Pad 2 data
(pin 12) -----> Pad 3 data
(pin 13) -----> Pad 4 data
(pin 15) -----> Pad 5 data

  Note that pin 14 is not used, since it is not an input pin on the parallel
port.

  This is everything you need on the PC's side of the connection, now on to
the gamepads side. The NES and SNES have different connectors. Also, there
are quite a lot of NES clones, and because Nintendo used proprietary
connectors for their machines, the cloners couldn't and used standard D-Cannon
connectors. Anyway, if you've got a gamepad, and it has buttons A, B, Turbo
A, Turbo B, Select and Start, and is connected through 5 wires, then it is
either a NES or NES clone and will work with this connection. SNES gamepads
also use 5 wires, but have more buttons. They will work as well, of course.

Pinout for NES gamepads                 Pinout for SNES gamepads

	   +----> Power                   +-----------------------\
	   |                            7 | o  o  o  o |  x  x  o  | 1
 5 +---------+  7                         +-----------------------/
   | x  x  o   \                            |  |  |  |          |
   | o  o  o  o |                           |  |  |  |          +-> Ground
 4 +------------+ 1                         |  |  |  +------------> Data
     |  |  |  |                             |  |  +---------------> Latch
     |  |  |  +-> Ground                    |  +------------------> Clock
     |  |  +----> Clock                     +---------------------> Power
     |  +-------> Latch
     +----------> Data

Pinout for NES clone (db9) gamepads     Pinout for NES clone (db15) gamepads

	+---------> Clock                    +-----------------> Data
	| +-------> Latch                    |             +---> Ground
	| | +-----> Data                     |             |
	| | |                              ___________________
    _____________                        8 \ o x x x x x x o / 1
  5 \ x o o o x / 1                         \ o x x o x x o /
     \ x o x o /                          15 `~~~~~~~~~~~~~' 9
    9 `~~~~~~~' 6                             |     |     |
	 |   |                                |     |     +----> Clock
	 |   +----> Power                     |     +----------> Latch
	 +--------> Ground                    +----------------> Power

2.2 Multisystem joysticks
~~~~~~~~~~~~~~~~~~~~~~~~~
  In the era of 8-bit machines, there was something like de-facto standard
for joystick ports. They were all digital, and all used D-Cannon 9 pin
connectors (db9). Because of that, a single joystick could be used without
hassle on Atari (130, 800XE, 800XL, 2600, 7200), Amiga, Commodore C64,
Amstrad CPC, Sinclair ZX Spectrum and many other machines. That's why these
joysticks are called "Multisystem".

  Now their pinout:

      +---------> Right
      | +-------> Left
      | | +-----> Down
      | | | +---> Up
      | | | |
  _____________
5 \ x o o o o / 1
   \ x o x o /
  9 `~~~~~~~' 6
       |   |
       |   +----> Button
       +--------> Ground

  However, as time passed, extension to this standard developed, and these
were not compatible with each other:


  Atari 130, 800(XL/XE)                    MSX

					 +-----------> Power
      +---------> Right                  | +---------> Right
      | +-------> Left                   | | +-------> Left
      | | +-----> Down                   | | | +-----> Down
      | | | +---> Up                     | | | | +---> Up
      | | | |                            | | | | |
  _____________                        _____________
5 \ x o o o o / 1                    5 \ o o o o o / 1
   \ x o o o /                          \ o o o o /
  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
       | | |                              | | | |
       | | +----> Button                  | | | +----> Button 1
       | +------> Power                   | | +------> Button 2
       +--------> Ground                  | +--------> Output 3
					  +----------> Ground

       Amstrad CPC                         Commodore C64

					 +-----------> Analog Y
      +---------> Right                  | +---------> Right
      | +-------> Left                   | | +-------> Left
      | | +-----> Down                   | | | +-----> Down
      | | | +---> Up                     | | | | +---> Up
      | | | |                            | | | | |
  _____________                        _____________
5 \ x o o o o / 1                    5 \ o o o o o / 1
   \ x o o o /                          \ o o o o /
  9 `~~~~~~~' 6                        9 `~~~~~~~' 6
       | | |                              | | | |
       | | +----> Button 1                | | | +----> Button
       | +------> Button 2                | | +------> Power
       +--------> Ground                  | +--------> Ground
					  +----------> Analog X

  And there were many others.

2.2.1 Multisystem joysticks using joy-db9.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  For the Multisystem joysticks, and their derivatives, the joy-db9.c driver
was written. It allows only one joystick / gamepad per parallel port, but
the interface is easy to build and works with almost anything.

  For the basic 1-button Multisystem joystick you connect its wires to the
parallel port like this:

(pin  1) -----> Power
(pin 18) -----> Ground

(pin  2) -----> Up
(pin  3) -----> Down
(pin  4) -----> Left
(pin  5) -----> Right
(pin  6) -----> Button 1

  However, if the joystick is switch based (eg. clicks when you move it),
you might or might not, depending on your parallel port, need 10 kOhm pullup
resistors on each of the direction and button signals, like this:

(pin 2) ------------+------> Up
	  Resistor  |
(pin 1) --[10kOhm]--+

  Try without, and if it doesn't work, add them. For TTL based joysticks /
gamepads the pullups are not needed.

  For joysticks with two buttons you connect the second button to pin 7 on
the parallel port.

(pin 7) -----> Button 2

  And that's it.

  On a side note, if you have already built a different adapter for use with
the digital joystick driver 0.8.0.2, this is also supported by the joy-db9.c
driver, as device type 8. (See section 3.2)

2.2.2 Multisystem joysticks using joy-console.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  For some people just one joystick per parallel port is not enough, and/or
want to use them on one parallel port together with NES/SNES/PSX pads. This
is possible using the joy-console.c. It supports up to 5 devices of the
above types, including 1 and 2 buttons Multisystem joysticks.

  However, there is nothing for free. To allow more sticks to be used at
once, you need the sticks to be purely switch based (that is non-TTL), and
not to need power. Just a plain simple six switches inside. If your
joystick can do more (eg. turbofire) you'll need to disable it totally first
if you want to use joy-console.c.

  Also, the connection is a bit more complex. You'll need a bunch of diodes,
and one pullup resistor. First, you connect the Directions and the button
the same as for joy-db9, however with the diodes inbetween.

	    Diodes
(pin 2) -----|<|----> Up
(pin 3) -----|<|----> Down
(pin 4) -----|<|----> Left
(pin 5) -----|<|----> Right
(pin 6) -----|<|----> Button 1

  For two button sticks you also connect the other button.

(pin 7) -----|<|----> Button 2

  And finally, you connect the Ground wire of the joystick, like done in
this little schematic to Power and Data on the parallel port, as described
for the NES / SNES pads in section 2.1 of this file - that is, one data pin
for each joystick. The power source is shared.

Data    ------------+-----> Ground
	  Resistor  |
Power   --[10kOhm]--+

  And that's all, here we go!

2.2.3 Multisystem joysticks using joy-turbografx.c
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  The TurboGraFX interface, designed by

	Steffen Schwenke <schwenke@burg-halle.de>

  allows up to 7 Multisystem joysticks connected to the parallel port. In
Steffen's version, there is support for up to 5 buttons per joystick.
However, since this doesn't work reliably on all parallel ports, the
joy-turbografx.c driver supports only one button per joystick. For more
information on how to build the interface, see

	http://www2.burg-halle.de/~schwenke/parport.html

2.3 Sony Playstation
~~~~~~~~~~~~~~~~~~~~

  WARNING: PSX support is experimental, and at the moment doesn't seem to
work for most people. If you like adventure, you can try yourself.

  The PSX controller is supported by the joy-console.c.

Pinout of the PSX controller (compatible with DirectPadPro):

  +---------+---------+---------+
9 | o  o  o | o  o  o | o  o  o | 1               parallel
   \________|_________|________/                  port pins
    |  |      |  |  |   |
    |  |      |  |  |   +-------->  Clock    ---  (4)
    |  |      |  |  +------------>  Select   ---  (3)
    |  |      |  +--------------->  Power    ---  (5-9)
    |  |      +------------------>  Ground   ---  (18-25)
    |  +------------------------->  Command  ---  (2)
    +---------------------------->  Data     ---  (10,11,12,13,15) one only...

  You may have to add pull up/down resistors. Maybe your pad also won't like
the 5V (PSX uses 3.7V).

  Currently the driver supports only one psx pad per parallel port, and these
controllers:

 * Standard PSX Pad
 * NegCon PSX Pad
 * Analog PSX Pad (red mode)
 * Analog PSX Pad (green mode)

2.4 Sega
~~~~~~~~
  All the Sega controllers are more or less based on the standard 2-button
Multisystem joystick. However, since they don't use switches and use TTL
logic, the only driver useable with them is the joy-db9.c driver.

2.4.1 Sega Master System
~~~~~~~~~~~~~~~~~~~~~~~~
  The SMS gamepads are almost exactly the same as normal 2-button
Multisystem joysticks. Set the driver to Multi2 mode, use the corresponding
parallel port pins, and the following schematic:

    +-----------> Power
    | +---------> Right
    | | +-------> Left
    | | | +-----> Down
    | | | | +---> Up
    | | | | |
  _____________
5 \ o o o o o / 1
   \ o o x o /
  9 `~~~~~~~' 6
     | |   |
     | |   +----> Button 1
     | +--------> Ground
     +----------> Button 2

2.4.2 Sega Genesis aka MegaDrive
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  The Sega Genesis (in Europe sold as Sega MegaDrive) pads are an extension
to the Sega Master System pads. They use more buttons (3+1, 5+1, 6+1).  Use
the following schematic:

    +-----------> Power
    | +---------> Right
    | | +-------> Left
    | | | +-----> Down
    | | | | +---> Up
    | | | | |
  _____________
5 \ o o o o o / 1
   \ o o o o /
  9 `~~~~~~~' 6
     | | | |
     | | | +----> Button 1
     | | +------> Select
     | +--------> Ground
     +----------> Button 2

  The Select pin goes to pin 14 on the parallel port.

(pin 14) -----> Select

  The rest is the same as for Multi2 joysticks using joy-db9.c

2.4.3 Sega Saturn
~~~~~~~~~~~~~~~~~
  Sega Saturn has eight buttons, and to transfer that, without hacks like
Genesis 6 pads use, it needs one more select pin. Anyway, it is still
handled by the joy-db9.c driver. Its pinout is very different from anything
else.  Use this schematic:

    +-----------> Select 1
    | +---------> Power
    | | +-------> Up
    | | | +-----> Down
    | | | | +---> Ground
    | | | | |
  _____________
5 \ o o o o o / 1
   \ o o o o /
  9 `~~~~~~~' 6
     | | | |
     | | | +----> Select 2
     | | +------> Right
     | +--------> Left
     +----------> Power

  Select 1 is pin 14 on the parallel port, Select 2 is pin 16 on the
parallel port.

(pin 14) -----> Select 1
(pin 16) -----> Select 2

  The other pins (Up, Down, Right, Left, Power, Ground) are the same as for
Multi joysticks using joy-db9.c

3. The drivers
~~~~~~~~~~~~~~
  There are three drivers for the parallel port interfaces. Each, as
described above, allows to connect a different group of joysticks and pads.
Here are described their command lines:

3.1 joy-console.c
~~~~~~~~~~~~~~~~~
  Using joy-console.c you can connect up to five devices to one parallel
port. It uses the following kernel/module command line:

	js_console=port,pad1,pad2,pad3,pad4,pad5

  Where 'port' is either the address of the parallel port the joystick/pad
is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
Linux kernels, the number of the parport interface (eg. 0 for parport0).

  And 'pad1' to 'pad5' are pad types connected to different data input pins
(10,11,12,13,15), as described in section 2.1 of this file.

  The types are:

	Type | Joystick/Pad
	--------------------
	  0  | None
	  1  | SNES pad
	  2  | NES pad
	  4  | Multisystem 1-button joystick
	  5  | Multisystem 2-button joystick
	  6  | Sony PSX controller
	  7  | N64 pad
	  8  | N64 pad with direction pad as buttons (DirectPadPro style)

  The exact type of the PSX controller type is autoprobed, so you must have
your controller plugged in before initializing.

  Should you want to use more than one of parallel ports at once, you can
use js_console_2 and js_console_3 as additional command line parameters for
two more parallel ports.

  Changes:
    v0.1  : First version (SNES only)
    v0.2  : X/Y directions were exchanged...
    v0.3  : Adaptation for kernel 2.1
    v0.4  : Adaptation for joystick-1.2.6
	    - added open/close callbacks
    v0.5  : Renamed to "joy-console" because I have added
	    PSX controller support.
    v0.6  : NES support
    v0.7V : Added "multi system" support
    v0.8  : Bugfixed PSX driver...
    v0.9V : Changed multi system support
	    Added Multi2 support
	    Fixed parport handling
	    Cleaned up
    v0.10 : Fixed PSX buttons 8 and 9
    v0.11V: Switched to EXCL mode
	    Removed wakeup
    v0.12V: Added N64 support
    v0.13V: Updated N64 support
    v0.14V: Fixed N64 axis/button counts

3.2 joy-db9.c
~~~~~~~~~~~~~
  Apart from making an interface, there is nothing difficult on using the
joy-db9.c driver. It uses the following kernel/module command line:

	js_db9=port,type

  Where 'port' is either the address of the parallel port the joystick/pad
is connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
Linux kernels, the number of the parport interface (eg. 0 for parport0).

  Caveat here: This driver only works on bidirectional parallel ports. If
your parallel port is recent enough, you should have no trouble with this.
Old parallel ports may not have this feature.

  'Type' is the type of joystick or pad attached:

	Type | Joystick/Pad
	--------------------
	  0  | None
	  1  | Multisystem 1-button joystick
	  2  | Multisystem 2-button joystick
	  3  | Genesis pad (3+1 buttons)
	  5  | Genesis pad (5+1 buttons)
	  6  | Genesis pad (6+2 buttons)
	  7  | Saturn pad (8 buttons)
	  8  | Multisystem 1-button joystick (v0.8.0.2 pin-out)
	  9  | Two Multiststem 1-button joysticks (v0.8.0.2 pin-out) 

  Should you want to use more than one of these joysticks/pads at once, you
can use js_db9_2 and js_db9_3 as additional command line parameters for two
more joysticks/pads.

  Changes:
    v0.1 : First version
    v0.2 : Changed kernel parameter format
    v0.3V: Added Sega Saturn support
	   Fixed parport and PS/2 mode handling
	   Cleaned up
    v0.4V: Switched to EXCL mode
           Removed wakeup
    v0.5V: Added 0.8.0.2 HW compatibility for Multi sticks
    v0.6V: Better timing for Genesis 6
    v0.7V: Added 0.8.0.2 second joystick support

3.3 joy-turbografx.c
~~~~~~~~~~~~~~~~~~~~
  The joy-turbografx.c driver uses a very simple kernel/module command line:

	js_tg=port,js1,js2,js3,js4,js5,js6,js7

  Where 'port' is either the address of the parallel port the interface is
connected to (eg. 0x378), or, if you are using the parport driver of 2.1+
Linux kernels, the number of the parport interface (eg. 0 for parport0).

  'jsX' is the number of buttons the Multisystem joysticks connected to the
interface ports 1-7 have. For a standard multisystem joystick, this is 1.

  Should you want to use more than one of these interfaces at once, you can
use js_tg_2 and js_tg_3 as additional command line parameters for two more
interfaces.

3.4 PC parallel port pinout
~~~~~~~~~~~~~~~~~~~~~~~~~~~
		  .----------------------------------------.
   At the PC:     \ 13 12 11 10  9  8  7  6  5  4  3  2  1 /
                   \  25 24 23 22 21 20 19 18 17 16 15 14 /
                     ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

	  Pin | Name    | Description
	~~~~~~|~~~~~~~~~|~~~~~~~~~~
	    1 | /STROBE | Strobe
	  2-9 | D0-D7   | Data Bit 0-7
	   10 | /ACK    | Acknowledge
	   11 | BUSY    | Busy
	   12 | PE      | Paper End
	   13 | SELIN   | Select In
	   14 | /AUTOFD | Autofeed
	   15 | /ERROR  | Error
	   16 | /INIT   | Initialize
	   17 | /SEL    | Select
	18-25 | GND     | Signal Ground

3.5 End
~~~~~~~
  That's all, folks! Have fun!
joystick-1.2.15/joystick.c100644    766    144       47556  7020451576  14561 0ustar  vojtechusers/*
 *  joystick.c  Version 1.2
 *
 *  Copyright (c) 1996-1999 Vojtech Pavlik
 *
 *  Sponsored by SuSE
 */

/*
 * This is the main joystick driver for Linux. It doesn't support any
 * devices directly, rather is lets you use sub-modules to do that job. See
 * Documentation/joystick.txt for more info.
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/joystick.h>
#include <linux/kernel.h>
#include <linux/major.h>
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/module.h>
#include <linux/poll.h>
#include <linux/config.h>
#include <linux/init.h>

/*
 * Configurable parameters.
 */

#define JS_REFRESH_TIME		HZ/50	/* Time between two reads of joysticks (20ms) */

/*
 * Exported symbols.
 */

EXPORT_SYMBOL(js_register_port);
EXPORT_SYMBOL(js_unregister_port);
EXPORT_SYMBOL(js_register_device);
EXPORT_SYMBOL(js_unregister_device);

/*
 * Buffer macros.
 */

#define ROT(A,B,C)	((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C)))))
#define GOF(X)		(((X)==JS_BUFF_SIZE-1)?0:(X)+1)
#define GOB(X)		((X)?(X)-1:JS_BUFF_SIZE-1)
#define DIFF(X,Y)	((X)>(Y)?(X)-(Y):(Y)-(X))

/*
 * Global variables.
 */

static struct JS_DATA_SAVE_TYPE js_comp_glue;
static struct js_port  *js_port  = NULL;
static struct js_dev   *js_dev   = NULL;
static struct timer_list js_timer;
spinlock_t js_lock = SPIN_LOCK_UNLOCKED;
static int js_use_count = 0;

/*
 * Module info.
 */

MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_SUPPORTED_DEVICE("js");

/*
 * js_correct() performs correction of raw joystick data.
 */

static int js_correct(int value, struct js_corr *corr)
{
	switch (corr->type) {
		case JS_CORR_NONE:
			break;
		case JS_CORR_BROKEN:
			value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
				((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
				((corr->coef[2] * (value - corr->coef[0])) >> 14);
			break;

		default:
			return 0;
	}

	if (value < -32767) return -32767;
	if (value >  32767) return  32767;

	return value;
}

/*
 * js_button() returns value of button number i.
 */

static inline int js_button(int *buttons, int i)
{
	return (buttons[i >> 5] >> (i & 0x1f)) & 1;
}

/*
 * js_add_event() adds an event to the buffer. This requires additional
 * queue post-processing done by js_sync_buff.
 */

static void js_add_event(struct js_dev *jd, __u32 time, __u8 type, __u8 number, __s16 value)
{
	jd->buff[jd->ahead].time = time;
	jd->buff[jd->ahead].type = type;
	jd->buff[jd->ahead].number = number;
	jd->buff[jd->ahead].value = value;
	if (++jd->ahead == JS_BUFF_SIZE) jd->ahead = 0;
}

/*
 * js_flush_data() does the same as js_process_data, except for that it doesn't
 * generate any events - it just copies the data from new to cur.
 */

static void js_flush_data(struct js_dev *jd)
{
	int i;

	for (i = 0; i < ((jd->num_buttons - 1) >> 5) + 1; i++)
		jd->cur.buttons[i] = jd->new.buttons[i];
	for (i = 0; i < jd->num_axes; i++)
		jd->cur.axes[i] = jd->new.axes[i];
}

/*
 * js_process_data() finds changes in button states and axis positions and adds
 * them as events to the buffer.
 */

static void js_process_data(struct js_dev *jd)
{
	int i, t;

	for (i = 0; i < jd->num_buttons; i++)
	if ((t = js_button(jd->new.buttons, i)) != js_button(jd->cur.buttons, i)) {
		js_add_event(jd, jiffies, JS_EVENT_BUTTON, i, t);
		jd->cur.buttons[i >> 5] ^= (1 << (i & 0x1f));
	}

	for (i = 0; i < jd->num_axes; i++) {
		t = js_correct(jd->new.axes[i], &jd->corr[i]);
		if (((jd->corr[i].prec == -1) && t) ||
			((DIFF(jd->new.axes[i], jd->cur.axes[i]) > jd->corr[i].prec) &&
			(t != js_correct(jd->cur.axes[i], &jd->corr[i])))) {
			js_add_event(jd, jiffies, JS_EVENT_AXIS, i, t);
			jd->cur.axes[i] = jd->new.axes[i];
		}
	}
}

/*
 * js_sync_buff() checks for all overflows caused by recent additions to the buffer.
 * These happen only if some process is reading the data too slowly. It
 * wakes up any process waiting for data.
 */

static void js_sync_buff(struct js_dev *jd)
{
	struct js_list *curl = jd->list;

	if (jd->bhead != jd->ahead) {
		if(ROT(jd->bhead, jd->tail, jd->ahead) || (jd->tail == jd->bhead)) {
			while (curl) {
				if (ROT(jd->bhead, curl->tail, jd->ahead) || (curl->tail == jd->bhead)) {
					curl->tail = jd->ahead;
					curl->startup = 0;
				}
				curl = curl->next;
			}
			jd->tail = jd->ahead;
		}
		jd->bhead = jd->ahead;
		wake_up_interruptible(&jd->wait);
	}
}

/*
 * js_do_timer() acts as an interrupt replacement. It reads the data
 * from all ports and then generates events for all devices.
 */

static void js_do_timer(unsigned long data)
{
	struct js_port *curp = js_port;
	struct js_dev *curd = js_dev;
	unsigned long flags;

	while (curp) {
		if (curp->read) 
			if (curp->read(curp->info, curp->axes, curp->buttons))
				curp->fail++;
		curp->total++;
		curp = curp->next;
	}

	spin_lock_irqsave(&js_lock, flags);

	while (curd) {
		if (data) {
			js_process_data(curd);
			js_sync_buff(curd);
		} else {
			js_flush_data(curd);
		}
		curd = curd->next;
	}

	spin_unlock_irqrestore(&js_lock, flags);

	js_timer.expires = jiffies + JS_REFRESH_TIME;
	add_timer(&js_timer);
}

/*
 * js_read() copies one or more entries from jsd[].buff to user
 * space.
 */

static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
{
	DECLARE_WAITQUEUE(wait, current);
	struct js_event *buff = (void *) buf;
	struct js_list *curl;
	struct js_dev *jd;
	unsigned long blocks = count / sizeof(struct js_event);
	int written = 0;
	int new_tail, orig_tail;
	int retval = 0;
	unsigned long flags;

	curl = file->private_data;
	jd = curl->dev;
	orig_tail = curl->tail;

/*
 * Check user data.
 */

	if (!blocks)
		return -EINVAL;

/*
 * Lock it.
 */

	spin_lock_irqsave(&js_lock, flags);

/*
 * Handle (non)blocking i/o.
 */
	if (count != sizeof(struct JS_DATA_TYPE)) {

		if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) {

			__set_current_state(TASK_INTERRUPTIBLE);
			add_wait_queue(&jd->wait, &wait);

			while (GOF(curl->tail) == jd->bhead) {

				if (file->f_flags & O_NONBLOCK) {
					retval = -EAGAIN;
					break;
				}
				if (signal_pending(current)) {
					retval = -ERESTARTSYS;
					break;
				}

				spin_unlock_irqrestore(&js_lock, flags);
				schedule();
				spin_lock_irqsave(&js_lock, flags);

			}

			current->state = TASK_RUNNING;
			remove_wait_queue(&jd->wait, &wait);
		}

		if (retval) {
			spin_unlock_irqrestore(&js_lock, flags);
			return retval;
		}

/*
 * Initial state.
 */

		while (curl->startup < jd->num_axes + jd->num_buttons && written < blocks && !retval) {

			struct js_event tmpevent;

			if (curl->startup < jd->num_buttons) {
				tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
				tmpevent.value = js_button(jd->cur.buttons, curl->startup);
				tmpevent.number = curl->startup;
			} else {
				tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT;
				tmpevent.value = js_correct(jd->cur.axes[curl->startup - jd->num_buttons],
								&jd->corr[curl->startup - jd->num_buttons]);
				tmpevent.number = curl->startup - jd->num_buttons;
			}

			tmpevent.time = jiffies * (1000/HZ);

			if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event)))
				retval = -EFAULT;

			curl->startup++;
			written++;
		}

/*
 * Buffer data.
 */

		while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) {

			if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event)))
				retval = -EFAULT;
			if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time))
				retval = -EFAULT;

			curl->tail = new_tail;
			written++;
		}
	}

	else

/*
 * Handle version 0.x compatibility.
 */

	{
		struct JS_DATA_TYPE data;

		data.buttons = jd->new.buttons[0];
		data.x = jd->num_axes < 1 ? 0 :
			((js_correct(jd->new.axes[0], &jd->corr[0]) / 256) + 128) >> js_comp_glue.JS_CORR.x;
		data.y = jd->num_axes < 2 ? 0 :
			((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y;

		retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;

		curl->startup = jd->num_axes + jd->num_buttons;
		curl->tail = GOB(jd->bhead);
		if (!retval) retval = sizeof(struct JS_DATA_TYPE);
	}

/*
 * Check main tail and move it.
 */

	if (orig_tail == jd->tail) {
		new_tail = curl->tail;
		curl = jd->list;
		while (curl && curl->tail != jd->tail) {
			if (ROT(jd->bhead, new_tail, curl->tail) ||
				(jd->bhead == curl->tail)) new_tail = curl->tail;
			curl = curl->next;
		}
		if (!curl) jd->tail = new_tail;
	}

	spin_unlock_irqrestore(&js_lock, flags);

	return retval ? retval : written * sizeof(struct js_event);
}

/*
 * js_poll() does select() support.
 */

static unsigned int js_poll(struct file *file, poll_table *wait)
{
	struct js_list *curl = file->private_data;
	unsigned long flags;
	int retval = 0;
	poll_wait(file, &curl->dev->wait, wait);
	spin_lock_irqsave(&js_lock, flags);	
	if (GOF(curl->tail) != curl->dev->bhead ||
		curl->startup < curl->dev->num_axes + curl->dev->num_buttons) retval = POLLIN | POLLRDNORM;
	spin_unlock_irqrestore(&js_lock, flags);
	return retval;
}

/*
 * js_ioctl handles misc ioctl calls.
 */

static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
{
	struct js_list *curl;
	struct js_dev *jd;
	int len;

	curl = file->private_data;
	jd = curl->dev;

	switch (cmd) {

/*
 * 0.x compatibility
 */

		case JS_SET_CAL:
			return copy_from_user(&js_comp_glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
		case JS_GET_CAL:
			return copy_to_user((struct JS_DATA_TYPE *) arg, &js_comp_glue.JS_CORR,
				sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
		case JS_SET_TIMEOUT:
			return get_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
		case JS_GET_TIMEOUT:
			return put_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
		case JS_SET_TIMELIMIT:
			return get_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
		case JS_GET_TIMELIMIT:
			return put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
		case JS_SET_ALL:
			return copy_from_user(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg,
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
		case JS_GET_ALL:
			return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue,
						sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;

/*
 * 1.x ioctl calls
 */

		case JSIOCGVERSION:
			return put_user(JS_VERSION, (__u32 *) arg);
		case JSIOCGAXES:
			return put_user(jd->num_axes, (__u8 *) arg);
		case JSIOCGBUTTONS:
			return put_user(jd->num_buttons, (__u8 *) arg);
		case JSIOCSCORR:
			return copy_from_user(jd->corr, (struct js_corr *) arg,
						sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
		case JSIOCGCORR:
			return copy_to_user((struct js_corr *) arg, jd->corr,
						sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
		default:
			if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
				len = strlen(jd->name) + 1;
				if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
				if (copy_to_user((char *) arg, jd->name, len)) return -EFAULT;
				return len;
			}
	}

	return -EINVAL;
}

/*
 * js_open() performs necessary initialization and adds
 * an entry to the linked list.
 */

static int js_open(struct inode *inode, struct file *file)
{
	struct js_list *curl, *new;
	struct js_dev *jd = js_dev;
	int i = MINOR(inode->i_rdev);
	unsigned long flags;
	int result; 

	if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
		return -EINVAL;

	spin_lock_irqsave(&js_lock, flags);

	while (i > 0 && jd) {
		jd = jd->next;
		i--;
	}

	spin_unlock_irqrestore(&js_lock, flags);

	if (!jd) return -ENODEV;

	if ((result = jd->open(jd))) return result;

	if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {

		MOD_INC_USE_COUNT;

		spin_lock_irqsave(&js_lock, flags);

		curl = jd->list;

		jd->list = new;
		jd->list->next = curl;
		jd->list->dev = jd;
		jd->list->startup = 0;
		jd->list->tail = GOB(jd->bhead);
		file->private_data = jd->list;

		spin_unlock_irqrestore(&js_lock, flags);

		if (!js_use_count++) js_do_timer(0);

	} else {
		result = -ENOMEM;
	}

	return result;
}

/*
 * js_release() removes an entry from list and deallocates memory
 * used by it.
 */

static int js_release(struct inode *inode, struct file *file)
{
	struct js_list *curl = file->private_data;
	struct js_dev *jd = curl->dev;
	struct js_list **curp = &jd->list;
	int new_tail;
	unsigned long flags;

	spin_lock_irqsave(&js_lock, flags);

	while (*curp && (*curp != curl)) curp = &((*curp)->next);
	*curp = (*curp)->next;

	if (jd->list)
	if (curl->tail == jd->tail) {
		curl = jd->list;
		new_tail = curl->tail;
		while (curl && curl->tail != jd->tail) {
			if (ROT(jd->bhead, new_tail, curl->tail) ||
			       (jd->bhead == curl->tail)) new_tail = curl->tail;
			curl = curl->next;
		}
		if (!curl) jd->tail = new_tail;
	}

	spin_unlock_irqrestore(&js_lock, flags);

	kfree(file->private_data);

	if (!--js_use_count) del_timer(&js_timer);
	MOD_DEC_USE_COUNT;

	jd->close(jd);

	return 0;
}

/*
 * js_dump_mem() dumps all data structures in memory.
 * It's used for debugging only.
 */

#if 0
static void js_dump_mem(void)
{

	struct js_port *curp = js_port;
	struct js_dev *curd = js_dev;
	int i;

	printk(",--- Dumping Devices:\n");
	printk("| js_dev = %x\n", (int) js_dev);

	while (curd) {
		printk("|  %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
			curd->next ? "|":"`",
			(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
		curd = curd->next;
	}

	printk(">--- Dumping ports:\n");
	printk("| js_port = %x\n", (int) js_port);

	while (curp) {
		printk("|  %s-port %x, next %x, io %#x, devices %d\n",
			curp->next ? "|":"`",
			(int) curp, (int) curp->next, curp->io, curp->ndevs);
		for (i = 0; i < curp->ndevs; i++) {
			curd = curp->devs[i];
			if (curd)
			printk("|  %s %s-device %x, next %x axes %d, buttons %d, port %x\n",
				curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`",
				(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port);
			else
			printk("|  %s %s-device %x, not there\n",
				curp->next ? "|":" ", (i < curp->ndevs-1) ? "|":"`", (int) curd);

		}
		curp = curp->next;
	}

	printk("`--- Done\n");
}
#endif


struct js_port *js_register_port(struct js_port *port,
				void *info, int devs, int infos, js_read_func read)
{
	struct js_port **ptrp = &js_port;
	struct js_port *curp;
	void *all;
	int i;
	unsigned long flags;

	if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)))
		return NULL;

	curp = all;

	curp->next = NULL;
	curp->prev = port;
	curp->read = read;
	curp->ndevs = devs;
	curp->fail = 0;
	curp->total = 0;

	curp->devs = all += sizeof(struct js_port);
	for (i = 0; i < devs; i++) curp->devs[i] = NULL;

	curp->axes = all += devs * sizeof(void*);
	curp->buttons = (void*) all += devs * sizeof(void*);
	curp->corr = all += devs * sizeof(void*);

	if (infos) {
		curp->info = all += devs * sizeof(void*); 
		memcpy(curp->info, info, infos);
	} else {
		curp->info = NULL;
	}

	spin_lock_irqsave(&js_lock, flags);

	while (*ptrp) ptrp=&((*ptrp)->next);
	*ptrp = curp;

	spin_unlock_irqrestore(&js_lock, flags);

	return curp;
}

struct js_port *js_unregister_port(struct js_port *port)
{
	struct js_port **curp = &js_port;
	struct js_port *prev;
	unsigned long flags;

	spin_lock_irqsave(&js_lock, flags);

	printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total);

	while (*curp && (*curp != port)) curp = &((*curp)->next);
	*curp = (*curp)->next;

	spin_unlock_irqrestore(&js_lock, flags);

	prev = port->prev;
	kfree(port);

	return prev;
}

int js_register_device(struct js_port *port, int number, int axes, int buttons, char *name,
					js_ops_func open, js_ops_func close)
{
	struct js_dev **ptrd = &js_dev;
	struct js_dev *curd;
	void *all;
	int i = 0;
	unsigned long flags;

	if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
			2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
			axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)))
		return -1;

	curd = all;

	curd->next = NULL;
	curd->list = NULL;
	curd->port = port;
	curd->open = open;
	curd->close = close;

	init_waitqueue_head(&curd->wait);

	curd->ahead = 0;
	curd->bhead = 0;
	curd->tail = JS_BUFF_SIZE - 1;
	curd->num_axes = axes;
	curd->num_buttons = buttons;

	curd->cur.axes = all += sizeof(struct js_dev);
	curd->cur.buttons = all += axes * sizeof(int);
	curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int);
	curd->new.buttons = all += axes * sizeof(int);
	curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int);

	curd->name = all += axes * sizeof(struct js_corr);
	strcpy(curd->name, name);

	port->devs[number] = curd;
	port->axes[number] = curd->new.axes;
	port->buttons[number] = curd->new.buttons;
	port->corr[number] = curd->corr;

	spin_lock_irqsave(&js_lock, flags);

	while (*ptrd) { ptrd=&(*ptrd)->next; i++; }
	*ptrd = curd;

	spin_unlock_irqrestore(&js_lock, flags);	

	return i;
}

void js_unregister_device(struct js_dev *dev)
{
	struct js_dev **curd = &js_dev;
	unsigned long flags;

	spin_lock_irqsave(&js_lock, flags);

	while (*curd && (*curd != dev)) curd = &((*curd)->next);
	*curd = (*curd)->next;

	spin_unlock_irqrestore(&js_lock, flags);	

	kfree(dev);
}

/*
 * The operations structure.
 */

static struct file_operations js_fops =
{
	read:		js_read,
	poll:		js_poll,
	ioctl:		js_ioctl,
	open:		js_open,
	release:	js_release,
};

/*
 * js_init() registers the driver and calls the probe function.
 * also initializes some crucial variables.
 */

#ifdef MODULE
int init_module(void)
#else
int __init js_init(void)
#endif
{

	if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
		printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
		return -EBUSY;
	}

	printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
		JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);

	spin_lock_init(&js_lock);

	init_timer(&js_timer);
	js_timer.function = js_do_timer;
	js_timer.data = 1;

	memset(&js_comp_glue, 0, sizeof(struct JS_DATA_SAVE_TYPE));
	js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT;
	js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT;

#ifndef MODULE
#ifdef CONFIG_JOY_PCI
	js_pci_init();
#endif
#ifdef CONFIG_JOY_LIGHTNING
	js_l4_init();
#endif
#ifdef CONFIG_JOY_SIDEWINDER
	js_sw_init();
#endif
#ifdef CONFIG_JOY_ASSASSIN
	js_as_init();
#endif
#ifdef CONFIG_JOY_LOGITECH
	js_lt_init();
#endif
#ifdef CONFIG_JOY_THRUSTMASTER
	js_tm_init();
#endif
#ifdef CONFIG_JOY_GRAVIS
	js_gr_init();
#endif
#ifdef CONFIG_JOY_CREATIVE
	js_cr_init();
#endif
#ifdef CONFIG_JOY_ANALOG
	js_an_init();
#endif
#ifdef CONFIG_JOY_CONSOLE
	js_console_init();
#endif
#ifdef CONFIG_JOY_DB9
	js_db9_init();
#endif
#ifdef CONFIG_JOY_TURBOGRAFX
	js_tg_init();
#endif
#ifdef CONFIG_JOY_AMIGA
	js_am_init();
#endif
#ifdef CONFIG_JOY_MAGELLAN
	js_mag_init();
#endif
#ifdef CONFIG_JOY_WARRIOR
	js_war_init();
#endif
#ifdef CONFIG_JOY_SPACEORB
	js_orb_init();
#endif
#ifdef CONFIG_JOY_SPACEBALL
	js_sball_init();
#endif
#endif

	return 0;
}

/*
 * cleanup_module() handles module removal.
 */

#ifdef MODULE
void cleanup_module(void)
{
	del_timer(&js_timer);
	if (unregister_chrdev(JOYSTICK_MAJOR, "js"))
		printk(KERN_ERR "js: can't unregister device\n");
}
#endif

joystick-1.2.15/joystick.h100644    766    144       15303  7022027216  14537 0ustar  vojtechusers#ifndef _LINUX_JOYSTICK_H
#define _LINUX_JOYSTICK_H

/*
 * /usr/include/linux/joystick.h  Version 1.2
 *
 * Copyright (C) 1996-1999 Vojtech Pavlik
 *
 * Sponsored by SuSE
 */

/*
 * This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License as published by
 * the Free Software Foundation; either version 2 of the License, or 
 * (at your option) any later version.
 * 
 * This program is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 * GNU General Public License for more details.
 * 
 * You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software
 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 * 
 * Should you need to contact me, the author, you can do so either by
 * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
 * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
 */

#include <asm/types.h>
#include <linux/module.h>

/*
 * Version
 */

#define JS_VERSION		0x01020f

/*
 * Types and constants for reading from /dev/js
 */

#define JS_EVENT_BUTTON		0x01	/* button pressed/released */
#define JS_EVENT_AXIS		0x02	/* joystick moved */
#define JS_EVENT_INIT		0x80	/* initial state of device */

struct js_event {
	__u32 time;	/* event timestamp in miliseconds */
	__s16 value;	/* value */
	__u8 type;	/* event type */
	__u8 number;	/* axis/button number */
};

/*
 * IOCTL commands for joystick driver
 */

#define JSIOCGVERSION		_IOR('j', 0x01, __u32)			/* get driver version */

#define JSIOCGAXES		_IOR('j', 0x11, __u8)			/* get number of axes */
#define JSIOCGBUTTONS		_IOR('j', 0x12, __u8)			/* get number of buttons */
#define JSIOCGNAME(len)		_IOC(_IOC_READ, 'j', 0x13, len)         /* get identifier string */

#define JSIOCSCORR		_IOW('j', 0x21, struct js_corr)		/* set correction values */
#define JSIOCGCORR		_IOR('j', 0x22, struct js_corr)		/* get correction values */

/*
 * Types and constants for get/set correction
 */

#define JS_CORR_NONE		0x00	/* returns raw values */
#define JS_CORR_BROKEN		0x01	/* broken line */

struct js_corr {
	__s32 coef[8];
	__s16 prec;
	__u16 type;
};

/*
 * v0.x compatibility definitions
 */

#define JS_RETURN		sizeof(struct JS_DATA_TYPE)
#define JS_TRUE			1
#define JS_FALSE		0
#define JS_X_0			0x01
#define JS_Y_0			0x02
#define JS_X_1			0x04
#define JS_Y_1			0x08
#define JS_MAX			2

#define JS_DEF_TIMEOUT		0x1300
#define JS_DEF_CORR		0
#define JS_DEF_TIMELIMIT	10L

#define JS_SET_CAL		1
#define JS_GET_CAL		2
#define JS_SET_TIMEOUT		3
#define JS_GET_TIMEOUT		4
#define JS_SET_TIMELIMIT	5
#define JS_GET_TIMELIMIT	6
#define JS_GET_ALL		7
#define JS_SET_ALL		8

struct JS_DATA_TYPE {
	int buttons;
	int x;
	int y;
};

struct JS_DATA_SAVE_TYPE {
	int JS_TIMEOUT;
	int BUSY;
	long JS_EXPIRETIME;
	long JS_TIMELIMIT;
	struct JS_DATA_TYPE JS_SAVE;
	struct JS_DATA_TYPE JS_CORR;
};

/*
 * Internal definitions
 */

#ifdef __KERNEL__

#define JS_BUFF_SIZE		64		/* output buffer size */

#include <linux/version.h>

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,2,0)
#error "You need to use at least v2.2 Linux kernel."
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#include <asm/spinlock.h>
typedef struct wait_queue *wait_queue_head_t;
#define __setup(a,b)
#define BASE_ADDRESS(x,i)	((x)->base_address[i])
#define DECLARE_WAITQUEUE(x,y)	struct wait_queue x = { y, NULL }
#define init_waitqueue_head(x)	do { *(x) = NULL; } while (0)
#define __set_current_state(x)	current->state = x
#define SETUP_PARAM		char *str, int *ints
#define SETUP_PARSE(x)		do {} while (0)
#else
#include <linux/spinlock.h>
#define BASE_ADDRESS(x,i)	((x)->resource[i].start)
#define SETUP_PARAM		char *str
#define SETUP_PARSE(x)		int ints[x]; get_options(str, x, ints)
#endif

#define PCI_VENDOR_ID_AUREAL	0x12eb

/*
 * Parport stuff
 */

#include <linux/parport.h>

#define JS_PAR_STATUS_INVERT	(0x80)
#define JS_PAR_CTRL_INVERT	(0x04)
#define JS_PAR_DATA_IN(y)	parport_read_data(y->port)
#define JS_PAR_DATA_OUT(x,y)	parport_write_data(y->port, x)
#define JS_PAR_STATUS(y)	parport_read_status(y->port)

#ifndef PARPORT_NEED_GENERIC_OPS
#define JS_PAR_CTRL_IN(y)	parport_read_control(y->port)
#else
#define JS_PAR_CTRL_IN(y)	inb(y->port->base+2) 
#endif

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,3,0)
#define JS_PAR_CTRL_OUT(x,y)	parport_write_control(y->port, x)
#define JS_PAR_ECTRL_OUT(x,y)	parport_write_econtrol(y->port, x)
#else
#define JS_PAR_CTRL_OUT(x,y)					\
	do {							\
		if ((x) & 0x20) parport_data_reverse(y->port);	\
		else parport_data_forward(y->port);		\
		parport_write_control(y->port, (x) & ~0x20);	\
	} while (0)
#define JS_PAR_ECTRL_OUT(x,y)	/*parport sets PS/2 mode on ECR chips */
#define PARPORT_MODE_PCPS2	PARPORT_MODE_TRISTATE
#define PARPORT_MODE_PCECPPS2	PARPORT_MODE_TRISTATE
#endif

/*
 * Internal types
 */

struct js_dev;

typedef int (*js_read_func)(void *info, int **axes, int **buttons);
typedef int (*js_ops_func)(struct js_dev *dev);

struct js_data {
	int *axes;
	int *buttons;
};

struct js_dev {
	struct js_dev *next;
	struct js_list *list;
	struct js_port *port;
	wait_queue_head_t wait;
	struct js_data cur;
	struct js_data new;
	struct js_corr *corr;
	struct js_event buff[JS_BUFF_SIZE];
	js_ops_func open;
	js_ops_func close;
	int ahead;
	int bhead;
	int tail;
	int num_axes;
	int num_buttons;
	char *name;
};

struct js_list {
	struct js_list *next;
	struct js_dev *dev;
	int tail;
	int startup;
};

struct js_port {
	struct js_port *next;
	struct js_port *prev;
	js_read_func read;
	struct js_dev **devs;
	int **axes;
	int **buttons;
	struct js_corr **corr;
	void *info;
	int ndevs;
	int fail;
	int total;
};

/*
 * Sub-module interface
 */

extern struct js_port *js_register_port(struct js_port *port, void *info,
	int devs, int infos, js_read_func read);
extern struct js_port *js_unregister_port(struct js_port *port);

extern int js_register_device(struct js_port *port, int number, int axes,
	int buttons, char *name, js_ops_func open, js_ops_func close);
extern void js_unregister_device(struct js_dev *dev);

/*
 * Kernel interface
 */

extern int js_init(void);
extern int js_am_init(void);
extern int js_an_init(void);
extern int js_as_init(void);
extern int js_console_init(void);
extern int js_cr_init(void);
extern int js_db9_init(void);
extern int js_gr_init(void);
extern int js_l4_init(void);
extern int js_lt_init(void);
extern int js_mag_init(void);
extern int js_pci_init(void);
extern int js_sw_init(void);
extern int js_sball_init(void);
extern int js_orb_init(void);
extern int js_tm_init(void);
extern int js_tg_init(void);
extern int js_war_init(void);

#endif /* __KERNEL__ */

#endif /* _LINUX_JOYSTICK_H */
joystick-1.2.15/joystick.txt100644    766    144       71542  7023211046  15133 0ustar  vojtechusers		       Linux Joystick driver v1.2.15
	       (c) 1996-1999 Vojtech Pavlik <vojtech@suse.cz>
			     Sponsored by SuSE
----------------------------------------------------------------------------

0. Disclaimer
~~~~~~~~~~~~~
  This program is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by the Free
Software Foundation; either version 2 of the License, or (at your option)
any later version.

  This program is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
more details.

  You should have received a copy of the GNU General Public License along
with this program; if not, write to the Free Software Foundation, Inc., 59
Temple Place, Suite 330, Boston, MA 02111-1307 USA

  Should you need to contact me, the author, you can do so either by e-mail
- mail your message to <vojtech@suse.cz>, or by paper mail: Vojtech Pavlik,
Ucitelska 1576, Prague 8, 182 00 Czech Republic

  For your convenience, the GNU General Public License version 2 is included
in the package: See the file COPYING.

1. Intro
~~~~~~~~
  The joystick driver for Linux provides support for a variety of joysticks
and similar devices.

  These currently include various analog joysticks and gamepads (both
variable resistor based and microswitch+resistor based), following IBM PC
joystick standard, with extensions like additional hats and buttons
compatible with CH Flightstick Pro, ThrustMaster FCS or 6 and 8 button
gamepads.

  In addition to these it also supports some of the new PC joysticks that
use proprietary digital protocols to communicate over the gameport,
currently by FPGaming, Gravis, Logitech, MadCatz, Microsoft, Creative and
ThrustMaster. Saitek protocol support is still to be done.

  The driver also includes support for many gamepads and joysticks that were
used by various non-PC computers and game consoles. These include Multi
system joysticks (Atari, Amiga, Commodore, Amstrad), Sega gamepads (Master
System, Genesis, Saturn), Nintendo gamepads (NES, SNES, N64), Sony gamepads
(PSX).  Support for Atari Jaguar, Atari 2600, NES FourScore, SNES MultiTap
and others might be added later.

  Last, but not least there is also native Amiga joystick support for the
Amiga Linux port.

  Should you encounter any problems while using the driver, or joysticks
this driver can't make complete use of, I'm very interested in hearing about
them. Bug reports and success stories are also welcome.

  The joystick package is available at the following FTP sites:

	ftp://ftp.suse.cz/pub/development/joystick/
	ftp://atrey.karlin.mff.cuni.cz/pub/linux/joystick/
	ftp://ftp.gts.cz/pub/linux/joystick/

  And a homepage of the driver is at:

	http://www.suse.cz/development/joystick/
	http://atrey.karlin.mff.cuni.cz/~vojtech/joystick/
	http://www.trylinux.com/projects/joystick/
	http://www.linuxgames.com/joystick/

  There is also a mailing list for the driver at:

	listproc@atrey.karlin.mff.cuni.cz

send "subscribe linux-joystick Your Name" to subscribe to it.

2. Usage
~~~~~~~~
  You could have obtained this driver in two different ways - either in the
joystick package or in the kernel. Because, for successful usage of the
joysticks, the utilities in the package are useful, maybe necessary, and
definitely recommended, I suggest you getting the package at some of the
above mentioned locations. The rest of this file assumes you have it.

2.1 Compiling the driver package
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  To compile the utilities in the joystick package, and the driver itself,
as a standalone module, you first unpack the package, and then edit the
Makefile to meet your needs (namely whether are you using versioned
modules). You will also need an unpacked and configured

	make config

kernel in
	
	/usr/src/linux

Furthermore, if you're using versioned modules, you'll also need

	make dep

done on the kernel, to create some needed files.

After that, you compile the joystick driver

	make

  And after that you install it

	make install

  In case you have not used the driver before, you'll need to create the
joystick device files in /dev so that applications can use them:

	make devs

  For manual creation of the joystick devices, check the
Documentation/devices.txt file in the Linux source tree.

  Should you not want to mess with the kernel, and just use the driver
standalone, as modules, skip the next two sections, proceeding right to 2.4,
because all you need is already done.

2.2 Patching the kernel
~~~~~~~~~~~~~~~~~~~~~~~
  If you already have the most recent joystick driver in your kernel, skip
this section. If not, you need to patch the kernel, so that it contains the
current driver version.  You do that with a command: 

	patch -Esp1 < /usr/src/joystick-1.2.x/kernel-2.x.y.diff

in

	/usr/src/linux

2.3 Compiling the kernel
~~~~~~~~~~~~~~~~~~~~~~~~
  To compile joystick support into the kernel, use the kernel configuration
scripts, and answer 'Y' to Joystick support and also to at least one of the
hardware specific options. After doing something like

	make bzlilo

  you are done with the driver installation. Just reboot and the driver
should find all the connected joysticks. Read the notes about the hardware
specific drivers later in this file, though.

  You can also compile the driver as modules, answering 'M' to all joystick
support you want to have modules for. It is possible to have the main
joystick driver compiled into the kernel and the hardware dependent drivers
as modules. After you compile the modules 

	make modules

  And install them

	make modules_install

 you're set, and can proceed to the next step.

2.4 Inserting the modules into the kernel
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  After installing the modules you'll first need to insert the generic
joystick driver module into the kernel

	insmod joystick

  and then one or more of the hardware specific modules

	insmod joy-something

  where 'something' is the type of your joystick. See below for more precise
explanation.

  Alternately you can add the lines

	alias char-major-15 joy-something
	options joy-something js_xx=x,x,x,x,...

  to the /etc/conf.modules file, so that the joystick module will be loaded
automatically when the /dev/js devices are accessed.

2.5 Verifying that it works
~~~~~~~~~~~~~~~~~~~~~~~~~~~
  For testing the joystick driver functionality, there is the jstest
program. You run it by typing:

	jstest /dev/js0

  And it should show a line with the joystick values, which update as you
move the stick, and press its buttons. The axes should all be zero when the
joystick is in the center position. They should not jitter by themselves to
other close values, and they also should be steady in any other position of
the stick. They should have the full range from -32767 to 32767. If all this
is met, then it's all fine, and you can play the games. :)

  If it's not, then there might be a problem. Try to calibrate the joystick,
and if it still doesn't work, read the drivers section of this file, the
troubleshooting section, and the FAQ.

2.6. Calibration
~~~~~~~~~~~~~~~~
  For most joysticks you won't need any manual calibration, since the
joystick should be autocalibrated by the driver automagically. However, with
some analog joysticks, that either do not use linear resistors, or if you
want better precision, you can use the jscal program

	jscal -c /dev/js0

 included in the joystick package to set better correction coefficients than
what the driver would choose itself.

  After calibrating the joystick you can verify if you like the new
calibration using the jstest command, and if you do, you then can save the
correction coefficients into a file

	jscal -p /dev/js0 > /etc/joystick.cal

  And add a line to your rc script executing that file

	source /etc/joystick.cal

  This way, after the next reboot your joystick will remain calibrated. You
can also add the jscal -p line to your shutdown script.


3. HW specific driver information
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
In this section each of the separate hardware specific drivers is described.

3.1 Analog joysticks
~~~~~~~~~~~~~~~~~~~~
  The joy-analog.c uses the standard analog inputs of the gameport, and thus
supports all standard joysticks and gamepads. It also supports extensions
like additional hats and buttons compatible with CH Flightstick Pro,
ThrustMaster FCS or 6 and 8 button gamepads. 

  However the only types that can be autodetected are:

* 2-axis, 4-button joystick
* 3-axis, 4-button joystick
* 4-axis, 4-button joystick

  For other joystick types (more/less axes, hats, and buttons) support
you'll need to specify the types either on the kernel command line or on the
module command line, when inserting joy-analog.o into the kernel. The
parameters are:

	js_an=p0,m0,n0,p1,m1,n1 ...

  Where 'p' is the port number, eg. 0x201, which is the standard address.
'm' and 'n' are joystick 0 and joystick 1 bitmasks for the specified
joystick port. The bits in the bitmasks mean:

	Bit |   2^n | Meaning
	----------------------------------
	 0  |     1 | Axis X1
	 1  |     2 | Axis Y1
	 2  |     4 | Axis X2
	 3  |     8 | Axis Y2
	 4  |    16 | Button A
	 5  |    32 | Button B
	 6  |    64 | Button C
	 7  |   128 | Button D
	 8  |   256 | CHF Buttons X and Y
	 9  |   512 | CHF Hat 1
	10  |  1024 | CHF Hat 2
	11  |  2048 | FCS Hat
	12  |  4096 | Pad Button X
	13  |  8192 | Pad Button Y
	14  | 16384 | Pad Button U
	15  | 32768 | Pad Button V

(CHF = CH Flightstick Pro, FCS = ThrustMaster FCS)

  Following is a table of joysticks for which the 'm' values are known. If
you have any additions/corrections to it, e-mail me.

	Joystick				| 'm' value
	----------------------------------------------------
	Simple 2-button 2-axis joystick		| 0x0033
	Second simple joystick on Y-cable	| 0x00cc
	Genius Flight2000 F-12			| 0x00f3
	Genius Flight2000 F-21			| 0x08f7
	Genius Flight2000 F-22			| 0x02ff
	Genius GameHunter G-06			| 0xf0f3
	Genius MaxFire G-07			| 0xf0f3   
	Genius PowerStation			| 0xf0f3
	Laing #1 PC SuperPad			| 0xf0f3
	Logitech Wingman			| 0x003b
	Microsoft SideWinder Standard		| 0x003b
	QuickShot QS-201 SuperWarrior		| 0x00fb
	Saitek Megapad XII			| 0x30f3
	PC Powerpad Pro				| 0x30f3

  In case you have one of the joystick in the table below, and it doesn't
work with a specific driver in digital mode for some reason, you can use
them in analog mode with the joy-analog driver as well. However, digital
operation is always better.

	Joystick				| 'm' value
	----------------------------------------------------
	Gravis GamePad Pro - analog mode	| 0x00f3
	Genius Flight2000 F-23			| 0x02ff
	Microsoft SideWinder 3D Pro - CHF mode	| 0x02ff
	Microsoft SideWinder 3D Pro - FCS mode	| 0x08f7

  An example that would configure the driver to use two two axis, two button
joysticks connected to port 0x201, a single four button four axis joystick
connected to port 0x202, a four axis, six button and two hat CHF compatible
joystick on 0x203, and a two axis four button FCS compatible joystick with a
single hat on 0x207:

	js_an=0x201,0x33,0xcc,0x202,0xff,0,0x203,0x7ff,0,0x207,0x8f3,0

  If you can't sum bits into hex numbers in your head easily, you can simply
sum the values in the 2^n column decimally and use that number instead.
Using this method you'd get a command line:

	js_an=0x201,51,204,0x202,255,0,0x203,2047,0,0x207,2291,0

  And it would do the same as the above explained command line. Use
whichever way you like best.

3.2 Microsoft SideWinder joysticks
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  Microsoft 'Digital Overdrive' protocol is supported by the
joy-sidewinder.c module. All currently supported joysticks:

* SideWinder 3D Pro
* SideWinder Force Feedback Pro
* SideWinder Force Feedback Wheel
* SideWinder FreeStyle Pro
* SideWinder GamePad (up to four, chained together)
* SideWinder Precision Pro 

  are autodetected, and thus no module parameters are needed.

  There is one caveat with the 3D Pro. There are 9 buttons reported,
although the joystick has only 8. The 9th button is the mode switch on the
rear side of the joystick. However, moving it, you'll reset the joystick,
and make it unresponsive for about a one third of a second. Furthermore, the
joystick will also re-center itself, taking the position it was in during
this time as a new center position. Use it if you want, but think first.

  The SideWinder Standard is not a digital joystick, and thus is supported
by the analog driver described above. 

3.3 Logitech ADI devices
~~~~~~~~~~~~~~~~~~~~~~~~
  Logitech ADI protocol is supported by the joy-logitech.c module. It should
support any Logitech device using this protocol. This includes, but is not
limited to:

* Logitech CyberMan 2
* Logitech ThunderPad Digital
* Logitech WingMan Extreme Digital
* Logitech WingMan Formula
* Logitech WingMan Interceptor
* Logitech WingMan GamePad
* Logitech WingMan GamePad USB
* Logitech WingMan GamePad Extreme
* Logitech WingMan Extreme Digital 3D

  ADI devices are autodetected, and the driver supports up to two (any
combination of) devices on a single gameport, using an Y-cable or chained
together.

  Logitech WingMan Joystick, Logitech WingMan Attack, Logitech WingMan
Extreme and Logitech WingMan ThunderPad are not digital joysticks and are
handled by the analog driver described above. Logitech WingMan Warrior and
Logitech Magellan are supported by serial drivers described below. Logitech
CyberMan, Logitech WingMan Force and Logitech WingMan Formula Force are not
supported yet.

3.4 Gravis GrIP
~~~~~~~~~~~~~~~
  Gravis GrIP protocol is supported by the joy-gravis.c module. It
currently supports:

* Gravis GamePad Pro
* Gravis Xterminator
* Gravis BlackHawk Digital

  All these devices are autodetected, and you can even use any combination
of up to two of these pads either chained together or using an Y-cable on a
single gameport.

GrIP MultiPort and Gravis Xterminator DualControl aren't supported yet.
Gravis Stinger is a serial device and hopefully will be supported in the
future. Other Gravis joysticks are supported by the joy-analog driver.

3.5 FPGaming A3D and MadCatz A3D
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  The Assassin 3D protocol created by FPGaming, is used both by FPGaming
themselves and is licensed to MadCatz. A3D devices are supported by the
joy-assassin.c module. It currently supports:

* FPGaming Assassin 3D
* MadCatz Panther
* MadCatz Panther XL

  All these devices are autodetected. Because the Assassin 3D and the Panther
allow connecting analog joysticks to them, these are supported in this
driver, too. The driver uses the js_as parameter for the analog joysticks,
which has the same syntax as js_an for the analog driver.

  The trackball support is far from perfect at this stage of development,
but should be well usable.

3.6 ThrustMaster DirectConnect (BSP)
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
  The TM DirectConnect (BSP) protocol is supported by the joy-thrustmaster.c
module. This includes, but is not limited to:

* ThrustMaster Millenium 3D Inceptor
* ThrustMaster 3D Rage Pad
* ThrustMaster Fusion Digital Game Pad

  Devices not directly supported, but hopefully working are:

* ThrustMaster FragMaster
* ThrustMaster Attack Throttle

  If you have one of these, contact me.

  BSP devices are autodetected, and thus no parameters to the module
are needed.

3.7 Creative Labs Blaster
~~~~~~~~~~~~~~~~~~~~~~~~~
  The Blaster
Results 1 - 1
Help - FTP Sites List - Software Dir.
Searching half a billion files worldwide
© 1997-2009 MARUHN Internet Solutions