DRIVERS-$(CONFIG_TC) += drivers/tc/tc.a
DRIVERS-$(CONFIG_USB) += drivers/usb/usbdrv.o
DRIVERS-$(CONFIG_INPUT) += drivers/input/inputdrv.o
+DRIVERS-$(CONFIG_GAMEPORT) += drivers/input/gameport/gamedrv.o
+DRIVERS-$(CONFIG_SERIO) += drivers/input/serio/seriodrv.o
DRIVERS-$(CONFIG_I2O) += drivers/message/i2o/i2o.o
DRIVERS-$(CONFIG_IRDA) += drivers/net/irda/irda.o
DRIVERS-$(CONFIG_I2C) += drivers/i2c/i2c.o
mod-subdirs := dio mtd sbus video macintosh usb input telephony sgi ide \
message/i2o message/fusion scsi md ieee1394 pnp isdn atm \
- fc4 net/hamradio i2c acpi bluetooth
+ fc4 net/hamradio i2c acpi bluetooth input/serio input/gameport
subdir-y := base parport char block net sound misc media cdrom hotplug
subdir-m := $(subdir-y)
subdir-$(CONFIG_ALL_PPC) += macintosh
subdir-$(CONFIG_USB) += usb
subdir-$(CONFIG_INPUT) += input
+subdir-$(CONFIG_SERIO) += input/serio
+subdir-$(CONFIG_GAMEPORT) += input/gameport
subdir-$(CONFIG_PHONE) += telephony
subdir-$(CONFIG_SGI) += sgi
subdir-$(CONFIG_IDE) += ide
fi
endmenu
-source drivers/char/joystick/Config.in
-
tristate 'QIC-02 tape support' CONFIG_QIC02_TAPE
if [ "$CONFIG_QIC02_TAPE" != "n" ]; then
bool ' Do you want runtime configuration for QIC-02' CONFIG_QIC02_DYNCONF
misc.o pty.o random.o selection.o serial.o \
sonypi.o tty_io.o tty_ioctl.o generic_serial.o
-mod-subdirs := joystick ftape drm pcmcia
+mod-subdirs := ftape drm pcmcia
list-multi :=
obj-$(CONFIG_SERIAL_TX3912) += generic_serial.o serial_tx3912.o
subdir-$(CONFIG_RIO) += rio
-subdir-$(CONFIG_INPUT) += joystick
obj-$(CONFIG_ATIXL_BUSMOUSE) += atixlmouse.o
obj-$(CONFIG_LOGIBUSMOUSE) += logibusmouse.o
obj-$(CONFIG_PRINTER) += lp.o
-ifeq ($(CONFIG_INPUT),y)
-obj-y += joystick/js.o
-endif
-
obj-$(CONFIG_BUSMOUSE) += busmouse.o
obj-$(CONFIG_DTLK) += dtlk.o
obj-$(CONFIG_R3964) += n_r3964.o
+++ /dev/null
-CONFIG_INPUT_GAMEPORT
- Gameport support is for the standard 15-pin PC gameport. If you
- have a joystick, gamepad, gameport card, a soundcard with a gameport
- or anything else that uses the gameport, say Y or M here and also to
- at least one of the hardware specific drivers.
- Please read the file <file:Documentation/input/joystick.txt> which
- contains more information and the location of the joystick package
- that you'll need if you use the gameport with a joystick.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called gameport.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_NS558
- Say Y here if you have an ISA or PnP gameport.
- For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called ns558.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_LIGHTNING
- Say Y here if you have a PDPI Lightning 4 gamecard. For more
- information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called lightning.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_CS461X
- Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
- PCI audio accelerator. A product page for the CS4614 is at
- <http://www.cirrus.com/design/products/overview/index.cfm?ProductID=40>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called cs461x.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_PCIGAME
- Say Y here if you have a Trident 4DWave DX/NX or Aureal Vortex 1/2
- card. For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called pcigame.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_EMU10K1
- Say Y here if you have a SoundBlaster Live! card and want to use
- its gameport. For more information on how to use the driver
- please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called emu10k1-gp.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_ANALOG
- Say Y here if you have a controller that connects to the PC
- gameport. This supports many different types, including joysticks
- with throttle control, with rudders, or with extensions like
- additional hats and buttons compatible with CH Flightstick Pro,
- ThrustMaster FCS, 6 and 8 button gamepads, or Saitek Cyborg
- joysticks. For more information on how to use the driver please
- read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called analog.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_A3D
- Say Y here if you have an FPGaming or MadCatz controller using the
- A3D protocol over the PC gameport. For more information on how to
- use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called a3d.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_ADI
- Say Y here if you have a Logitech controller using the ADI
- protocol over the PC gameport. For more information on how to use
- the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called adi.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_COBRA
- Say Y here if you have a Creative Labs Blaster Cobra gamepad.
- For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called cobra.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GF2K
- Say Y here if you have a Genius Flight2000 or MaxFighter digitally
- communicating joystick or gamepad. For more information on how to
- use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called gf2k.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GRIP
- Say Y here if you have a Gravis controller using the GrIP protocol
- over the PC gameport. For more information on how to use the driver
- please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called grip.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_INTERACT
- Say Y hereif you have an InterAct gameport or joystick
- communicating digitally over the gameport. For more information on
- how to use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called interact.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_TMDC
- Say Y here if you have a ThrustMaster controller using the
- DirectConnect (BSP) protocol over the PC gameport. For more
- information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called tmdc.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SIDEWINDER
- Say Y here if you have a Microsoft controller using the Digital
- Overdrive protocol over PC gameport. For more information on how to
- use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called sidewinder.o. If you want to compile it
- as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SERIO
- Say Y here and to the Serial port input line discipline option if
- you plan to use a joystick that communicates over the serial (COM)
- port. For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called sidewinder.o. If you want to compile it
- as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SERPORT
- Say Y here if you plan to use a joystick that communicates over the
- serial (COM) port. For more information on how to use the driver
- please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called serport.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_WARRIOR
- Say Y here if you have a Logitech WingMan Warrior joystick connected
- to your computer's serial port. For more information on how to use
- the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called warrior.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_MAGELLAN
- Say Y here if you have a Magellan or Space Mouse 6DOF controller
- connected to your computer's serial port. For more information on
- how to use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called magellan.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SPACEORB
- Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
- controller connected to your computer's serial port. For more
- information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called spaceorb.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_SPACEBALL
- Say Y here if you have a SpaceTec SpaceBall 4000 FLX controller
- connected to your computer's serial port. For more information on
- how to use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called spaceball.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_STINGER
- Say Y here if you have a Gravis Stinger connected to one of your
- serial ports. For more information on how to use the driver please
- read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called stinger.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_IFORCE_232
- Say Y here if you have an I-Force joystick or steering wheel
- connected to your serial (COM) port. For more information on how
- to use the driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called iforce.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_IFORCE_USB
- Say Y here if you have an I-Force joystick or steering wheel
- connected to your USB port. For more information on how to use the
- driver please read <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called iforce.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_DB9
- Say Y here if you have a Sega Master System gamepad, Sega Genesis
- gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
- Commodore, Amstrad CPC joystick connected to your parallel port.
- For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt> and
- <file:Documentation/input/joystick-parport.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called db9.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_GAMECON
- Say Y here if you have a Nintendo Entertainment System gamepad,
- Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
- Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
- Commodore, Amstrad CPC joystick connected to your parallel port.
- For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt> and
- <file:Documentation/input/joystick-parport.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called gamecon.o. If you want to compile it as a
- module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_TURBOGRAFX
- Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
- and want to use it with Multisystem -- Atari, Amiga, Commodore,
- Amstrad CPC joystick. For more information on how to use the driver
- please read <file:Documentation/input/joystick.txt> and
- <file:Documentation/input/joystick-parport.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called turbografx.o. If you want to compile it
- as a module, say M here and read <file:Documentation/modules.txt>.
-
-CONFIG_INPUT_AMIJOY
- Say Y here if you have an Amiga with a digital joystick connected
- to it. For more information on how to use the driver please read
- <file:Documentation/input/joystick.txt>.
-
- This driver is also available as a module ( = code which can be
- inserted in and removed from the running kernel whenever you want).
- The module will be called joy-amiga.o. If you want to compile it as
- a module, say M here and read <file:Documentation/modules.txt>.
-
+++ /dev/null
-#
-# Joystick driver configuration
-#
-
-mainmenu_option next_comment
-comment 'Joysticks'
-
-if [ "$CONFIG_INPUT" != "n" ]; then
- dep_tristate 'Game port support' CONFIG_INPUT_GAMEPORT $CONFIG_INPUT
- dep_tristate ' Classic ISA/PnP gameports' CONFIG_INPUT_NS558 $CONFIG_INPUT_GAMEPORT
- dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Crystal SoundFusion gameports' CONFIG_INPUT_CS461X $CONFIG_INPUT_GAMEPORT
- dep_tristate ' SoundBlaster Live! gameports' CONFIG_INPUT_EMU10K1 $CONFIG_INPUT_GAMEPORT
- tristate 'Serial port device support' CONFIG_INPUT_SERIO
- dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_INPUT_SERIO
-else
- # Must explicitly set to n for drivers/sound/Config.in
- define_tristate CONFIG_INPUT_GAMEPORT n
- comment 'Input core support is needed for gameports'
-fi
-
-if [ "$CONFIG_INPUT" != "n" ]; then
- comment 'Joysticks'
-
- dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_GAMEPORT
- dep_tristate ' I-Force USB joysticks and wheels' CONFIG_INPUT_IFORCE_USB $CONFIG_INPUT $CONFIG_USB
- dep_tristate ' I-Force Serial joysticks and wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' Gravis Stinger gamepad' CONFIG_INPUT_STINGER $CONFIG_INPUT $CONFIG_INPUT_SERIO
- dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_INPUT $CONFIG_PARPORT
- dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_INPUT $CONFIG_PARPORT
- dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_INPUT $CONFIG_PARPORT
-
- if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_INPUT
- fi
-else
- comment 'Input core support is needed for joysticks'
-fi
-
-endmenu
+++ /dev/null
-#
-# Makefile for the joystick drivers.
-#
-
-O_TARGET := js.o
-
-# Objects that export symbols.
-
-export-objs := serio.o gameport.o
-
-# I-Force may need both USB and RS-232
-
-ifeq ($(CONFIG_INPUT_IFORCE_232),m)
- ifeq ($(CONFIG_INPUT_IFORCE_USB),y)
- CONFIG_INPUT_IFORCE_USB := m
- endif
-endif
-ifeq ($(CONFIG_INPUT_IFORCE_USB),m)
- ifeq ($(CONFIG_INPUT_IFORCE_232),y)
- CONFIG_INPUT_IFORCE_232 := m
- endif
-endif
-
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
-# Each configuration option enables a list of files.
-
-obj-$(CONFIG_INPUT_GAMEPORT) += gameport.o
-obj-$(CONFIG_INPUT_SERIO) += serio.o
-
-obj-$(CONFIG_INPUT_SERPORT) += serport.o
-
-obj-$(CONFIG_INPUT_NS558) += ns558.o
-obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o
-obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o
-obj-$(CONFIG_INPUT_CS461X) += cs461x.o
-obj-$(CONFIG_INPUT_EMU10K1) += emu10k1-gp.o
-
-obj-$(CONFIG_INPUT_WARRIOR) += warrior.o
-obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o
-obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o
-obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o
-obj-$(CONFIG_INPUT_STINGER) += stinger.o
-obj-$(CONFIG_INPUT_IFORCE_232) += iforce.o
-obj-$(CONFIG_INPUT_IFORCE_USB) += iforce.o
-
-obj-$(CONFIG_INPUT_ANALOG) += analog.o
-obj-$(CONFIG_INPUT_A3D) += a3d.o
-obj-$(CONFIG_INPUT_ADI) += adi.o
-obj-$(CONFIG_INPUT_COBRA) += cobra.o
-obj-$(CONFIG_INPUT_GF2K) += gf2k.o
-obj-$(CONFIG_INPUT_GRIP) += grip.o
-obj-$(CONFIG_INPUT_INTERACT) += interact.o
-obj-$(CONFIG_INPUT_TMDC) += tmdc.o
-obj-$(CONFIG_INPUT_SIDEWINDER) += sidewinder.o
-
-obj-$(CONFIG_INPUT_DB9) += db9.o
-obj-$(CONFIG_INPUT_GAMECON) += gamecon.o
-obj-$(CONFIG_INPUT_TURBOGRAFX) += turbografx.o
-
-obj-$(CONFIG_INPUT_AMIJOY) += amijoy.o
-
-# The global Rules.make.
-
-include $(TOPDIR)/Rules.make
+++ /dev/null
-/*
- * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
- *
- * Copyright (c) 1998-2001 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * FP-Gaming Assasin 3D joystick driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define A3D_MAX_START 400 /* 400 us */
-#define A3D_MAX_STROBE 60 /* 40 us */
-#define A3D_DELAY_READ 3 /* 3 ms */
-#define A3D_MAX_LENGTH 40 /* 40*3 bits */
-#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
-
-#define A3D_MODE_A3D 1 /* Assassin 3D */
-#define A3D_MODE_PAN 2 /* Panther */
-#define A3D_MODE_OEM 3 /* Panther OEM version */
-#define A3D_MODE_PXL 4 /* Panther XL */
-
-char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
- "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
-
-struct a3d {
- struct gameport *gameport;
- struct gameport adc;
- struct input_dev dev;
- struct timer_list timer;
- int axes[4];
- int buttons;
- int mode;
- int length;
- int used;
- int reads;
- int bads;
-};
-
-/*
- * a3d_read_packet() reads an Assassin 3D packet.
- */
-
-static int a3d_read_packet(struct gameport *gameport, int length, char *data)
-{
- unsigned long flags;
- unsigned char u, v;
- unsigned int t, s;
- int i;
-
- i = 0;
- t = gameport_time(gameport, A3D_MAX_START);
- s = gameport_time(gameport, A3D_MAX_STROBE);
-
- __save_flags(flags);
- __cli();
- gameport_trigger(gameport);
- v = gameport_read(gameport);
-
- while (t > 0 && i < length) {
- t--;
- u = v; v = gameport_read(gameport);
- if (~v & u & 0x10) {
- data[i++] = v >> 5;
- t = s;
- }
- }
-
- __restore_flags(flags);
-
- return i;
-}
-
-/*
- * a3d_csum() computes checksum of triplet packet
- */
-
-static int a3d_csum(char *data, int count)
-{
- int i, csum = 0;
- for (i = 0; i < count - 2; i++) csum += data[i];
- return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
-}
-
-static void a3d_read(struct a3d *a3d, unsigned char *data)
-{
- struct input_dev *dev = &a3d->dev;
-
- switch (a3d->mode) {
-
- case A3D_MODE_A3D:
- case A3D_MODE_OEM:
- case A3D_MODE_PAN:
-
- input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
- input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
-
- input_report_key(dev, BTN_RIGHT, data[2] & 1);
- input_report_key(dev, BTN_LEFT, data[3] & 2);
- input_report_key(dev, BTN_MIDDLE, data[3] & 4);
-
- a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
- a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
- a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
- a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
-
- a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
-
- return;
-
- case A3D_MODE_PXL:
-
- input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
- input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
-
- input_report_key(dev, BTN_RIGHT, data[2] & 1);
- input_report_key(dev, BTN_LEFT, data[3] & 2);
- input_report_key(dev, BTN_MIDDLE, data[3] & 4);
- input_report_key(dev, BTN_SIDE, data[7] & 2);
- input_report_key(dev, BTN_EXTRA, data[7] & 4);
-
- input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
- input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
- input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
- input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
-
- input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
- input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
- input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
- input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
-
- input_report_key(dev, BTN_TRIGGER, data[8] & 1);
- input_report_key(dev, BTN_THUMB, data[8] & 2);
- input_report_key(dev, BTN_TOP, data[8] & 4);
- input_report_key(dev, BTN_PINKIE, data[7] & 1);
-
- return;
- }
-}
-
-
-/*
- * a3d_timer() reads and analyzes A3D joystick data.
- */
-
-static void a3d_timer(unsigned long private)
-{
- struct a3d *a3d = (void *) private;
- unsigned char data[A3D_MAX_LENGTH];
- a3d->reads++;
- if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
- || data[0] != a3d->mode || a3d_csum(data, a3d->length))
- a3d->bads++; else a3d_read(a3d, data);
- mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
-}
-
-/*
- * a3d_adc_cooked_read() copies the acis and button data to the
- * callers arrays. It could do the read itself, but the caller could
- * call this more than 50 times a second, which would use too much CPU.
- */
-
-int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct a3d *a3d = gameport->private;
- int i;
- for (i = 0; i < 4; i++)
- axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
- *buttons = a3d->buttons;
- return 0;
-}
-
-/*
- * a3d_adc_open() is the gameport open routine. It refuses to serve
- * any but cooked data.
- */
-
-int a3d_adc_open(struct gameport *gameport, int mode)
-{
- struct a3d *a3d = gameport->private;
- if (mode != GAMEPORT_MODE_COOKED)
- return -1;
- if (!a3d->used++)
- mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
- return 0;
-}
-
-/*
- * a3d_adc_close() is a callback from the input close routine.
- */
-
-static void a3d_adc_close(struct gameport *gameport)
-{
- struct a3d *a3d = gameport->private;
- if (!--a3d->used)
- del_timer(&a3d->timer);
-}
-
-/*
- * a3d_open() is a callback from the input open routine.
- */
-
-static int a3d_open(struct input_dev *dev)
-{
- struct a3d *a3d = dev->private;
- if (!a3d->used++)
- mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
- return 0;
-}
-
-/*
- * a3d_close() is a callback from the input close routine.
- */
-
-static void a3d_close(struct input_dev *dev)
-{
- struct a3d *a3d = dev->private;
- if (!--a3d->used)
- del_timer(&a3d->timer);
-}
-
-/*
- * a3d_connect() probes for A3D joysticks.
- */
-
-static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct a3d *a3d;
- unsigned char data[A3D_MAX_LENGTH];
- int i;
-
- if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
- return;
- memset(a3d, 0, sizeof(struct a3d));
-
- gameport->private = a3d;
-
- a3d->gameport = gameport;
- init_timer(&a3d->timer);
- a3d->timer.data = (long) a3d;
- a3d->timer.function = a3d_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
-
- if (!i || a3d_csum(data, i))
- goto fail2;
-
- a3d->mode = data[0];
-
- if (!a3d->mode || a3d->mode > 5) {
- printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
- "(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
- goto fail2;
- }
-
-
- if (a3d->mode == A3D_MODE_PXL) {
-
- int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
-
- a3d->length = 33;
-
- a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
- a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
- a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
- | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
-
- a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
- | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
-
- a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
-
- a3d_read(a3d, data);
-
- for (i = 0; i < 4; i++) {
- if (i < 2) {
- a3d->dev.absmin[axes[i]] = 48;
- a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
- a3d->dev.absflat[axes[i]] = 8;
- } else {
- a3d->dev.absmin[axes[i]] = 2;
- a3d->dev.absmax[axes[i]] = 253;
- }
- a3d->dev.absmin[ABS_HAT0X + i] = -1;
- a3d->dev.absmax[ABS_HAT0X + i] = 1;
- }
-
- } else {
- a3d->length = 29;
-
- a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
- a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
- a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
-
- a3d->adc.private = a3d;
- a3d->adc.open = a3d_adc_open;
- a3d->adc.close = a3d_adc_close;
- a3d->adc.cooked_read = a3d_adc_cooked_read;
- a3d->adc.fuzz = 1;
-
- a3d_read(a3d, data);
-
- gameport_register_port(&a3d->adc);
- printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
- a3d->adc.number, a3d_names[a3d->mode], gameport->number);
- }
-
- a3d->dev.private = a3d;
- a3d->dev.open = a3d_open;
- a3d->dev.close = a3d_close;
-
- a3d->dev.name = a3d_names[a3d->mode];
- a3d->dev.idbus = BUS_GAMEPORT;
- a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
- a3d->dev.idproduct = a3d->mode;
- a3d->dev.idversion = 0x0100;
-
- input_register_device(&a3d->dev);
- printk(KERN_INFO "input%d: %s on gameport%d.0\n",
- a3d->dev.number, a3d_names[a3d->mode], gameport->number);
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(a3d);
-}
-
-static void a3d_disconnect(struct gameport *gameport)
-{
-
- struct a3d *a3d = gameport->private;
- input_unregister_device(&a3d->dev);
- if (a3d->mode < A3D_MODE_PXL)
- gameport_unregister_port(&a3d->adc);
- gameport_close(gameport);
- kfree(a3d);
-}
-
-static struct gameport_dev a3d_dev = {
- connect: a3d_connect,
- disconnect: a3d_disconnect,
-};
-
-int __init a3d_init(void)
-{
- gameport_register_device(&a3d_dev);
- return 0;
-}
-
-void __exit a3d_exit(void)
-{
- gameport_unregister_device(&a3d_dev);
-}
-
-module_init(a3d_init);
-module_exit(a3d_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Logitech ADI joystick family driver for Linux
- */
-
-/*
- * 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/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-#include <linux/init.h>
-
-/*
- * Times, array sizes, flags, ids.
- */
-
-#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
-#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
-#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
-#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
-#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
-
-#define ADI_MAX_LENGTH 256
-#define ADI_MIN_LENGTH 8
-#define ADI_MIN_LEN_LENGTH 10
-#define ADI_MIN_ID_LENGTH 66
-#define ADI_MAX_NAME_LENGTH 48
-#define ADI_MAX_CNAME_LENGTH 16
-
-#define ADI_FLAG_HAT 0x04
-#define ADI_FLAG_10BIT 0x08
-
-#define ADI_ID_TPD 0x01
-#define ADI_ID_WGP 0x06
-#define ADI_ID_WGPE 0x08
-#define ADI_ID_MAX 0x0a
-
-/*
- * Names, buttons, axes ...
- */
-
-static char *adi_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" };
-
-static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
-static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
-static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
-static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-
-static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
-static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
-static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
-static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
-
-static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
- adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
-
-static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
- adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
-
-/*
- * Hat to axis conversion arrays.
- */
-
-static struct {
- int x;
- int y;
-} adi_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 adi {
- struct input_dev dev;
- int length;
- int ret;
- int idx;
- unsigned char id;
- char buttons;
- char axes10;
- char axes8;
- signed char pad;
- char hats;
- char *abs;
- short *key;
- char name[ADI_MAX_NAME_LENGTH];
- char cname[ADI_MAX_CNAME_LENGTH];
- unsigned char data[ADI_MAX_LENGTH];
-};
-
-struct adi_port {
- struct gameport *gameport;
- struct timer_list timer;
- struct adi adi[2];
- int bad;
- int reads;
- int used;
-};
-
-/*
- * adi_read_packet() reads a Logitech ADI packet.
- */
-
-static void adi_read_packet(struct adi_port *port)
-{
- struct adi *adi = port->adi;
- struct gameport *gameport = port->gameport;
- unsigned char u, v, w, x, z;
- int t[2], s[2], i;
- unsigned long flags;
-
- for (i = 0; i < 2; i++) {
- adi[i].ret = -1;
- t[i] = gameport_time(gameport, ADI_MAX_START);
- s[i] = 0;
- }
-
- __save_flags(flags);
- __cli();
-
- gameport_trigger(gameport);
- v = z = gameport_read(gameport);
-
- do {
- u = v;
- w = u ^ (v = x = gameport_read(gameport));
- for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
- t[i]--;
- if ((w & 0x30) && s[i]) {
- if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
- adi[i].data[++adi[i].ret] = w;
- t[i] = gameport_time(gameport, ADI_MAX_STROBE);
- } else t[i] = 0;
- } else if (!(x & 0x30)) s[i] = 1;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
- return;
-}
-
-/*
- * adi_move_bits() detects a possible 2-stream mode, and moves
- * the bits accordingly.
- */
-
-static void adi_move_bits(struct adi_port *port, int length)
-{
- int i;
- struct adi *adi = port->adi;
-
- adi[0].idx = adi[1].idx = 0;
-
- if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
- if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
-
- for (i = 1; i <= adi[1].ret; i++)
- adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
-
- adi[0].ret += adi[1].ret;
- adi[1].ret = -1;
-}
-
-/*
- * adi_get_bits() gathers bits from the data packet.
- */
-
-static inline int adi_get_bits(struct adi *adi, int count)
-{
- int bits = 0;
- int i;
- if ((adi->idx += count) > adi->ret) return 0;
- for (i = 0; i < count; i++)
- bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
- return bits;
-}
-
-/*
- * adi_decode() decodes Logitech joystick data into input events.
- */
-
-static int adi_decode(struct adi *adi)
-{
- struct input_dev *dev = &adi->dev;
- char *abs = adi->abs;
- short *key = adi->key;
- int i, t;
-
- if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
- return -1;
-
- for (i = 0; i < adi->axes10; i++)
- input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
-
- for (i = 0; i < adi->axes8; i++)
- input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
-
- for (i = 0; i < adi->buttons && i < 63; i++) {
- if (i == adi->pad) {
- t = adi_get_bits(adi, 4);
- input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1));
- input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
- }
- input_report_key(dev, *key++, adi_get_bits(adi, 1));
- }
-
- for (i = 0; i < adi->hats; i++) {
- if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
- input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
- input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
- }
-
- for (i = 63; i < adi->buttons; i++)
- input_report_key(dev, *key++, adi_get_bits(adi, 1));
-
- return 0;
-}
-
-/*
- * adi_read() reads the data packet and decodes it.
- */
-
-static int adi_read(struct adi_port *port)
-{
- int i;
- int result = 0;
-
- adi_read_packet(port);
- adi_move_bits(port, port->adi[0].length);
-
- for (i = 0; i < 2; i++)
- if (port->adi[i].length)
- result |= adi_decode(port->adi + i);
-
- return result;
-}
-
-/*
- * adi_timer() repeatedly polls the Logitech joysticks.
- */
-
-static void adi_timer(unsigned long data)
-{
- struct adi_port *port = (void *) data;
- port->bad -= adi_read(port);
- port->reads++;
- mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
-}
-
-/*
- * adi_open() is a callback from the input open routine.
- */
-
-static int adi_open(struct input_dev *dev)
-{
- struct adi_port *port = dev->private;
- if (!port->used++)
- mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
- return 0;
-}
-
-/*
- * adi_close() is a callback from the input close routine.
- */
-
-static void adi_close(struct input_dev *dev)
-{
- struct adi_port *port = dev->private;
- if (!--port->used)
- del_timer(&port->timer);
-}
-
-/*
- * adi_init_digital() sends a trigger & delay sequence
- * to reset and initialize a Logitech joystick into digital mode.
- */
-
-static void adi_init_digital(struct gameport *gameport)
-{
- int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
- int i;
-
- for (i = 0; seq[i]; i++) {
- gameport_trigger(gameport);
- if (seq[i] > 0) wait_ms(seq[i]);
- if (seq[i] < 0) mdelay(-seq[i]);
- }
-}
-
-static void adi_id_decode(struct adi *adi, struct adi_port *port)
-{
- int i, t;
-
- if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
- return;
-
- if (adi->ret < (t = adi_get_bits(adi, 10))) {
- printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
- return;
- }
-
- adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
-
- if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
-
- adi->length = adi_get_bits(adi, 10);
-
- if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
- printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
- adi->length = 0;
- return;
- }
-
- adi->axes8 = adi_get_bits(adi, 4);
- adi->buttons = adi_get_bits(adi, 6);
-
- if (adi_get_bits(adi, 6) != 8 && adi->hats) {
- printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
- adi->length = 0;
- return;
- }
-
- adi->buttons += adi_get_bits(adi, 6);
- adi->hats += adi_get_bits(adi, 4);
-
- i = adi_get_bits(adi, 4);
-
- if (t & ADI_FLAG_10BIT) {
- adi->axes10 = adi->axes8 - i;
- adi->axes8 = i;
- }
-
- t = adi_get_bits(adi, 4);
-
- for (i = 0; i < t; i++)
- adi->cname[i] = adi_get_bits(adi, 8);
- adi->cname[i] = 0;
-
- t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
- if (adi->length != t && adi->length != t + (t & 1)) {
- printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
- adi->length = 0;
- return;
- }
-
- switch (adi->id) {
- case ADI_ID_TPD:
- adi->pad = 4;
- adi->buttons -= 4;
- break;
- case ADI_ID_WGP:
- adi->pad = 0;
- adi->buttons -= 4;
- break;
- default:
- adi->pad = -1;
- break;
- }
-}
-
-static void adi_init_input(struct adi *adi, struct adi_port *port)
-{
- int i, t;
- char buf[ADI_MAX_NAME_LENGTH];
-
- if (!adi->length) return;
-
- t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
-
- sprintf(buf, adi_names[t], adi->id);
- sprintf(adi->name, "Logitech %s", buf);
-
- adi->abs = adi_abs[t];
- adi->key = adi_key[t];
-
- adi->dev.open = adi_open;
- adi->dev.close = adi_close;
-
- adi->dev.name = adi->name;
- adi->dev.idbus = BUS_GAMEPORT;
- adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
- adi->dev.idproduct = adi->id;
- adi->dev.idversion = 0x0100;
-
- adi->dev.private = port;
- adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
- set_bit(adi->abs[i], &adi->dev.absbit);
-
- for (i = 0; i < adi->buttons; i++)
- set_bit(adi->key[i], &adi->dev.keybit);
-}
-
-static void adi_init_center(struct adi *adi)
-{
- int i, t, x;
-
- if (!adi->length) return;
-
- for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
-
- t = adi->abs[i];
- x = adi->dev.abs[t];
-
- if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
- if (i < adi->axes10) x = 512; else x = 128;
- }
-
- if (i < adi->axes10) {
- adi->dev.absmax[t] = x * 2 - 64;
- adi->dev.absmin[t] = 64;
- adi->dev.absfuzz[t] = 2;
- adi->dev.absflat[t] = 16;
- continue;
- }
-
- if (i < adi->axes10 + adi->axes8) {
- adi->dev.absmax[t] = x * 2 - 48;
- adi->dev.absmin[t] = 48;
- adi->dev.absfuzz[t] = 1;
- adi->dev.absflat[t] = 16;
- continue;
- }
-
- adi->dev.absmax[t] = 1;
- adi->dev.absmin[t] = -1;
- }
-}
-
-/*
- * adi_connect() probes for Logitech ADI joysticks.
- */
-
-static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct adi_port *port;
- int i;
-
- if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
- return;
- memset(port, 0, sizeof(struct adi_port));
-
- gameport->private = port;
-
- port->gameport = gameport;
- init_timer(&port->timer);
- port->timer.data = (long) port;
- port->timer.function = adi_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
- kfree(port);
- return;
- }
-
- adi_init_digital(gameport);
- adi_read_packet(port);
-
- if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
- adi_move_bits(port, adi_get_bits(port->adi, 10));
-
- for (i = 0; i < 2; i++) {
- adi_id_decode(port->adi + i, port);
- adi_init_input(port->adi + i, port);
- }
-
- if (!port->adi[0].length && !port->adi[1].length) {
- gameport_close(gameport);
- kfree(port);
- return;
- }
-
- wait_ms(ADI_INIT_DELAY);
- if (adi_read(port)) {
- wait_ms(ADI_DATA_DELAY);
- adi_read(port);
- }
-
- for (i = 0; i < 2; i++)
- if (port->adi[i].length > 0) {
- adi_init_center(port->adi + i);
- input_register_device(&port->adi[i].dev);
- printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
- port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
- }
-}
-
-static void adi_disconnect(struct gameport *gameport)
-{
- int i;
-
- struct adi_port *port = gameport->private;
- for (i = 0; i < 2; i++)
- if (port->adi[i].length > 0)
- input_unregister_device(&port->adi[i].dev);
- gameport_close(gameport);
- kfree(port);
-}
-
-/*
- * The gameport device structure.
- */
-
-static struct gameport_dev adi_dev = {
- connect: adi_connect,
- disconnect: adi_disconnect,
-};
-
-int __init adi_init(void)
-{
- gameport_register_device(&adi_dev);
- return 0;
-}
-
-void __exit adi_exit(void)
-{
- gameport_unregister_device(&adi_dev);
-}
-
-module_init(adi_init);
-module_exit(adi_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Driver for Amiga joysticks for Linux/m68k
- */
-
-/*
- * 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/types.h>
-#include <linux/errno.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-
-#include <asm/system.h>
-#include <asm/amigahw.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(amijoy, "1-2i");
-MODULE_LICENSE("GPL");
-
-static int amijoy[2] = { 0, 1 };
-static int amijoy_used[2] = { 0, 0 };
-static struct input_dev amijoy_dev[2];
-
-static char *amijoy_name = "Amiga joystick";
-
-static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
-{
- int i, data = 0, button = 0;
-
- for (i = 0; i < 2; i++)
- if (amijoy[i]) {
-
- switch (i) {
- case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
- case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
- }
-
- input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
-
- input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
- data = ~(data ^ (data << 1));
- input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
- }
-}
-
-static int amijoy_open(struct input_dev *dev)
-{
- int *used = dev->private;
-
- if ((*used)++)
- return 0;
-
- if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
- (*used)--;
- printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
- return -EBUSY;
- }
-
- return 0;
-}
-
-static void amijoy_close(struct input_dev *dev)
-{
- int *used = dev->private;
-
- if (!--(*used))
- free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
-}
-
-static int __init amijoy_setup(char *str)
-{
- int i;
- int ints[4]
- str = get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
- return 1;
-}
-__setup("amijoy=", amijoy_setup);
-
-static int __init amijoy_init(void)
-{
- int i, j;
-
- init_timer(amijoy_timer);
- port->timer.function = amijoy_timer;
-
- for (i = 0; i < 2; i++)
- if (amijoy[i]) {
- if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
- "amijoy [Denise]")) {
- if (i == 1 && amijoy[0]) {
- input_unregister_device(amijoy_dev);
- release_mem_region(CUSTOM_PHYSADDR+10, 2);
- }
- return -EBUSY;
- }
-
- amijoy_dev[i].open = amijoy_open;
- amijoy_dev[i].close = amijoy_close;
- amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
- amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
- for (j = 0; j < 2; j++) {
- amijoy_dev[i].absmin[ABS_X + j] = -1;
- amijoy_dev[i].absmax[ABS_X + j] = 1;
- }
-
- amijoy->dev[i].name = amijoy_name;
- amijoy->dev[i].idbus = BUS_AMIGA;
- amijoy->dev[i].idvendor = 0x0001;
- amijoy->dev[i].idproduct = 0x0003;
- amijoy->dev[i].version = 0x0100;
-
- amijoy_dev[i].private = amijoy_used + i;
-
- input_register_device(amijoy_dev + i);
- printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
- }
- return 0;
-}
-
-static void _exit amijoy_exit(void)
-{
- int i;
-
- for (i = 0; i < 2; i++)
- if (amijoy[i]) {
- input_unregister_device(amijoy_dev + i);
- release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
- }
-}
-
-module_init(amijoy_init);
-module_exit(amijoy_exit);
+++ /dev/null
-/*
- * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
- *
- * Copyright (c) 1996-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Analog joystick and gamepad driver for Linux
- */
-
-/*
- * 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/config.h>
-#include <linux/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/bitops.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-#include <asm/timex.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
-MODULE_LICENSE("GPL");
-
-/*
- * Option parsing.
- */
-
-#define ANALOG_PORTS 16
-
-static char *js[ANALOG_PORTS];
-static int analog_options[ANALOG_PORTS];
-MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
-MODULE_PARM_DESC(js, "Analog joystick options");
-
-/*
- * Times, feature definitions.
- */
-
-#define ANALOG_RUDDER 0x00004
-#define ANALOG_THROTTLE 0x00008
-#define ANALOG_AXES_STD 0x0000f
-#define ANALOG_BTNS_STD 0x000f0
-
-#define ANALOG_BTNS_CHF 0x00100
-#define ANALOG_HAT1_CHF 0x00200
-#define ANALOG_HAT2_CHF 0x00400
-#define ANALOG_HAT_FCS 0x00800
-#define ANALOG_HATS_ALL 0x00e00
-#define ANALOG_BTN_TL 0x01000
-#define ANALOG_BTN_TR 0x02000
-#define ANALOG_BTN_TL2 0x04000
-#define ANALOG_BTN_TR2 0x08000
-#define ANALOG_BTNS_TLR 0x03000
-#define ANALOG_BTNS_TLR2 0x0c000
-#define ANALOG_BTNS_GAMEPAD 0x0f000
-
-#define ANALOG_HBTN_CHF 0x10000
-#define ANALOG_ANY_CHF 0x10700
-#define ANALOG_SAITEK 0x20000
-#define ANALOG_EXTENSIONS 0x7ff00
-#define ANALOG_GAMEPAD 0x80000
-
-#define ANALOG_MAX_TIME 3 /* 3 ms */
-#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
-#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
-#define ANALOG_SAITEK_DELAY 200 /* 200 us */
-#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
-#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
-#define ANALOG_INIT_RETRIES 8 /* 8 times */
-#define ANALOG_FUZZ_BITS 2 /* 2 bit more */
-#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */
-
-#define ANALOG_MAX_NAME_LENGTH 128
-
-static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
-static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
-static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
-static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
-static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
-static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
- BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
-
-static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
-
-struct analog {
- struct input_dev dev;
- int mask;
- short *buttons;
- char name[ANALOG_MAX_NAME_LENGTH];
-};
-
-struct analog_port {
- struct gameport *gameport;
- struct timer_list timer;
- struct analog analog[2];
- unsigned char mask;
- char saitek;
- char cooked;
- int bads;
- int reads;
- int speed;
- int loop;
- int fuzz;
- int axes[4];
- int buttons;
- int initial[4];
- int used;
- int axtime;
-};
-
-/*
- * Time macros.
- */
-
-#ifdef __i386__
-#define TSC_PRESENT (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
-#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
-#define DELTA(x,y) (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
-#define TIME_NAME (TSC_PRESENT?"TSC":"PIT")
-#elif __x86_64__
-#define GET_TIME(x) rdtscl(x)
-#define DELTA(x,y) ((y)-(x))
-#define TIME_NAME "TSC"
-#elif __alpha__
-#define GET_TIME(x) ((x) = get_cycles())
-#define DELTA(x,y) ((y)-(x))
-#define TIME_NAME "PCC"
-#else
-#define FAKE_TIME
-static unsigned long analog_faketime = 0;
-#define GET_TIME(x) do { x = analog_faketime++; } while(0)
-#define DELTA(x,y) ((y)-(x))
-#define TIME_NAME "Unreliable"
-#warning Precise timer not defined for this architecture.
-#endif
-
-/*
- * analog_decode() decodes analog joystick data and reports input events.
- */
-
-static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
-{
- struct input_dev *dev = &analog->dev;
- int i, j;
-
- if (analog->mask & ANALOG_HAT_FCS)
- for (i = 0; i < 4; i++)
- if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
- buttons |= 1 << (i + 14);
- break;
- }
-
- for (i = j = 0; i < 6; i++)
- if (analog->mask & (0x10 << i))
- input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
-
- if (analog->mask & ANALOG_HBTN_CHF)
- for (i = 0; i < 4; i++)
- input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
-
- if (analog->mask & ANALOG_BTN_TL)
- input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
- if (analog->mask & ANALOG_BTN_TR)
- input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
- if (analog->mask & ANALOG_BTN_TL2)
- input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
- if (analog->mask & ANALOG_BTN_TR2)
- input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
-
- for (i = j = 0; i < 4; i++)
- if (analog->mask & (1 << i))
- input_report_abs(dev, analog_axes[j++], axes[i]);
-
- for (i = j = 0; i < 3; i++)
- if (analog->mask & analog_exts[i]) {
- input_report_abs(dev, analog_hats[j++],
- ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
- input_report_abs(dev, analog_hats[j++],
- ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
- }
-}
-
-/*
- * analog_cooked_read() reads analog joystick data.
- */
-
-static int analog_cooked_read(struct analog_port *port)
-{
- struct gameport *gameport = port->gameport;
- unsigned int time[4], start, loop, now, loopout, timeout;
- unsigned char data[4], this, last;
- unsigned long flags;
- int i, j;
-
- loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
- timeout = ANALOG_MAX_TIME * port->speed;
-
- __save_flags(flags);
- __cli();
- gameport_trigger(gameport);
- GET_TIME(now);
- __restore_flags(flags);
-
- start = now;
- this = port->mask;
- i = 0;
-
- do {
- loop = now;
- last = this;
-
- __cli();
- this = gameport_read(gameport) & port->mask;
- GET_TIME(now);
- __restore_flags(flags);
-
- if ((last ^ this) && (DELTA(loop, now) < loopout)) {
- data[i] = last ^ this;
- time[i] = now;
- i++;
- }
-
- } while (this && (i < 4) && (DELTA(start, now) < timeout));
-
- this <<= 4;
-
- for (--i; i >= 0; i--) {
- this |= data[i];
- for (j = 0; j < 4; j++)
- if (data[i] & (1 << j))
- port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
- }
-
- return -(this != port->mask);
-}
-
-static int analog_button_read(struct analog_port *port, char saitek, char chf)
-{
- unsigned char u;
- int t = 1, i = 0;
- int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
-
- u = gameport_read(port->gameport);
-
- if (!chf) {
- port->buttons = (~u >> 4) & 0xf;
- return 0;
- }
-
- port->buttons = 0;
-
- while ((~u & 0xf0) && (i < 16) && t) {
- port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
- if (!saitek) return 0;
- udelay(ANALOG_SAITEK_DELAY);
- t = strobe;
- gameport_trigger(port->gameport);
- while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
- i++;
- }
-
- return -(!t || (i == 16));
-}
-
-/*
- * analog_timer() repeatedly polls the Analog joysticks.
- */
-
-static void analog_timer(unsigned long data)
-{
- struct analog_port *port = (void *) data;
- int i;
-
- char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
- char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
-
- if (port->cooked) {
- port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
- if (chf)
- port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
- port->reads++;
- } else {
- if (!port->axtime--) {
- port->bads -= analog_cooked_read(port);
- port->bads -= analog_button_read(port, saitek, chf);
- port->reads++;
- port->axtime = ANALOG_AXIS_TIME - 1;
- } else {
- if (!saitek)
- analog_button_read(port, saitek, chf);
- }
- }
-
- for (i = 0; i < 2; i++)
- if (port->analog[i].mask)
- analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
-
- mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
-}
-
-/*
- * analog_open() is a callback from the input open routine.
- */
-
-static int analog_open(struct input_dev *dev)
-{
- struct analog_port *port = dev->private;
- if (!port->used++)
- mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
- return 0;
-}
-
-/*
- * analog_close() is a callback from the input close routine.
- */
-
-static void analog_close(struct input_dev *dev)
-{
- struct analog_port *port = dev->private;
- if (!--port->used)
- del_timer(&port->timer);
-}
-
-/*
- * analog_calibrate_timer() calibrates the timer and computes loop
- * and timeout values for a joystick port.
- */
-
-static void analog_calibrate_timer(struct analog_port *port)
-{
- struct gameport *gameport = port->gameport;
- unsigned int i, t, tx, t1, t2, t3;
- unsigned long flags;
-
- save_flags(flags);
- cli();
- GET_TIME(t1);
-#ifdef FAKE_TIME
- analog_faketime += 830;
-#endif
- udelay(1000);
- GET_TIME(t2);
- GET_TIME(t3);
- restore_flags(flags);
-
- port->speed = DELTA(t1, t2) - DELTA(t2, t3);
-
- tx = ~0;
-
- for (i = 0; i < 50; i++) {
- save_flags(flags);
- cli();
- GET_TIME(t1);
- for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
- GET_TIME(t3);
- restore_flags(flags);
- udelay(i);
- t = DELTA(t1, t2) - DELTA(t2, t3);
- if (t < tx) tx = t;
- }
-
- port->loop = tx / 50;
-}
-
-/*
- * analog_name() constructs a name for an analog joystick.
- */
-
-static void analog_name(struct analog *analog)
-{
- sprintf(analog->name, "Analog %d-axis %d-button",
- hweight8(analog->mask & ANALOG_AXES_STD),
- hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
- hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
-
- if (analog->mask & ANALOG_HATS_ALL)
- sprintf(analog->name, "%s %d-hat",
- analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
-
- if (analog->mask & ANALOG_HAT_FCS)
- strcat(analog->name, " FCS");
- if (analog->mask & ANALOG_ANY_CHF)
- strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
-
- strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
-}
-
-/*
- * analog_init_device()
- */
-
-static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
-{
- int i, j, t, v, w, x, y, z;
-
- analog_name(analog);
-
- analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
-
- analog->dev.name = analog->name;
- analog->dev.idbus = BUS_GAMEPORT;
- analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
- analog->dev.idproduct = analog->mask >> 4;
- analog->dev.idversion = 0x0100;
-
- analog->dev.open = analog_open;
- analog->dev.close = analog_close;
- analog->dev.private = port;
- analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = j = 0; i < 4; i++)
- if (analog->mask & (1 << i)) {
-
- t = analog_axes[j];
- x = port->axes[i];
- y = (port->axes[0] + port->axes[1]) >> 1;
- z = y - port->axes[i];
- z = z > 0 ? z : -z;
- v = (x >> 3);
- w = (x >> 3);
-
- set_bit(t, analog->dev.absbit);
-
- if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
- x = y;
-
- if (analog->mask & ANALOG_SAITEK) {
- if (i == 2) x = port->axes[i];
- v = x - (x >> 2);
- w = (x >> 4);
- }
-
- analog->dev.absmax[t] = (x << 1) - v;
- analog->dev.absmin[t] = v;
- analog->dev.absfuzz[t] = port->fuzz;
- analog->dev.absflat[t] = w;
-
- j++;
- }
-
- for (i = j = 0; i < 3; i++)
- if (analog->mask & analog_exts[i])
- for (x = 0; x < 2; x++) {
- t = analog_hats[j++];
- set_bit(t, analog->dev.absbit);
- analog->dev.absmax[t] = 1;
- analog->dev.absmin[t] = -1;
- }
-
- for (i = j = 0; i < 4; i++)
- if (analog->mask & (0x10 << i))
- set_bit(analog->buttons[j++], analog->dev.keybit);
-
- if (analog->mask & ANALOG_BTNS_CHF)
- for (i = 0; i < 2; i++)
- set_bit(analog->buttons[j++], analog->dev.keybit);
-
- if (analog->mask & ANALOG_HBTN_CHF)
- for (i = 0; i < 4; i++)
- set_bit(analog->buttons[j++], analog->dev.keybit);
-
- for (i = 0; i < 4; i++)
- if (analog->mask & (ANALOG_BTN_TL << i))
- set_bit(analog_pads[i], analog->dev.keybit);
-
- analog_decode(analog, port->axes, port->initial, port->buttons);
-
- input_register_device(&analog->dev);
-
- printk(KERN_INFO "input%d: %s at gameport%d.%d",
- analog->dev.number, analog->name, port->gameport->number, index);
-
- if (port->cooked)
- printk(" [ADC port]\n");
- else
- printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
- port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
- port->speed > 10000 ? "M" : "k",
- port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
- : (port->loop * 1000000) / port->speed);
-}
-
-/*
- * analog_init_devices() sets up device-specific values and registers the input devices.
- */
-
-static int analog_init_masks(struct analog_port *port)
-{
- int i;
- struct analog *analog = port->analog;
- int max[4];
-
- if (!port->mask)
- return -1;
-
- if ((port->mask & 3) != 3 && port->mask != 0xc) {
- printk(KERN_WARNING "analog.c: Unknown joystick device found "
- "(data=%#x, gameport%d), probably not analog joystick.\n",
- port->mask, port->gameport->number);
- return -1;
- }
-
- i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
-
- analog[0].mask = i & 0xfffff;
-
- analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
- | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
- | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
-
- analog[0].mask &= ~(ANALOG_HAT2_CHF)
- | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
-
- analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
- | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
- | ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
- | ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
-
- analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
- | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
- & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
-
- analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
-
- analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
- : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
-
- if (port->cooked) {
-
- for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
-
- if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
- if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
- if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
- if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
- if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
-
- gameport_calibrate(port->gameport, port->axes, max);
- }
-
- for (i = 0; i < 4; i++)
- port->initial[i] = port->axes[i];
-
- return -!(analog[0].mask || analog[1].mask);
-}
-
-static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
-{
- int i, t, u, v;
-
- gameport->private = port;
- port->gameport = gameport;
- init_timer(&port->timer);
- port->timer.data = (long) port;
- port->timer.function = analog_timer;
-
- if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
-
- analog_calibrate_timer(port);
-
- gameport_trigger(gameport);
- t = gameport_read(gameport);
- wait_ms(ANALOG_MAX_TIME);
- port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
- port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
-
- for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
- if (!analog_cooked_read(port)) break;
- wait_ms(ANALOG_MAX_TIME);
- }
-
- u = v = 0;
-
- wait_ms(ANALOG_MAX_TIME);
- t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
- gameport_trigger(gameport);
- while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
- udelay(ANALOG_SAITEK_DELAY);
- t = gameport_time(gameport, ANALOG_SAITEK_TIME);
- gameport_trigger(gameport);
- while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
-
- if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
- analog_options[port->gameport->number] |=
- ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
- return 0;
- }
-
- gameport_close(gameport);
- }
-
- if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
-
- for (i = 0; i < ANALOG_INIT_RETRIES; i++)
- if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
- break;
- for (i = 0; i < 4; i++)
- if (port->axes[i] != -1) port->mask |= 1 << i;
-
- port->fuzz = gameport->fuzz;
- port->cooked = 1;
- return 0;
- }
-
- if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- return 0;
-
- return -1;
-}
-
-static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct analog_port *port;
- int i;
-
- if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
- return;
- memset(port, 0, sizeof(struct analog_port));
-
- if (analog_init_port(gameport, dev, port)) {
- kfree(port);
- return;
- }
-
- if (analog_init_masks(port)) {
- gameport_close(gameport);
- kfree(port);
- return;
- }
-
- for (i = 0; i < 2; i++)
- if (port->analog[i].mask)
- analog_init_device(port, port->analog + i, i);
-}
-
-static void analog_disconnect(struct gameport *gameport)
-{
- int i;
-
- struct analog_port *port = gameport->private;
- for (i = 0; i < 2; i++)
- if (port->analog[i].mask)
- input_unregister_device(&port->analog[i].dev);
- gameport_close(gameport);
- printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
- port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
- port->gameport->number);
- kfree(port);
-}
-
-struct analog_types {
- char *name;
- int value;
-};
-
-struct analog_types analog_types[] = {
- { "none", 0x00000000 },
- { "auto", 0x000000ff },
- { "2btn", 0x0000003f },
- { "y-joy", 0x0cc00033 },
- { "y-pad", 0x8cc80033 },
- { "fcs", 0x000008f7 },
- { "chf", 0x000002ff },
- { "fullchf", 0x000007ff },
- { "gamepad", 0x000830f3 },
- { "gamepad8", 0x0008f0f3 },
- { NULL, 0 }
-};
-
-static void analog_parse_options(void)
-{
- int i, j;
- char *end;
-
- for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
-
- for (j = 0; analog_types[j].name; j++)
- if (!strcmp(analog_types[j].name, js[i])) {
- analog_options[i] = analog_types[j].value;
- break;
- }
- if (analog_types[j].name) continue;
-
- analog_options[i] = simple_strtoul(js[i], &end, 0);
- if (end != js[i]) continue;
-
- analog_options[i] = 0xff;
- if (!strlen(js[i])) continue;
-
- printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
- }
-
- for (; i < ANALOG_PORTS; i++)
- analog_options[i] = 0xff;
-}
-
-/*
- * The gameport device structure.
- */
-
-static struct gameport_dev analog_dev = {
- connect: analog_connect,
- disconnect: analog_disconnect,
-};
-
-#ifndef MODULE
-static int __init analog_setup(char *str)
-{
- char *s = str;
- int i = 0;
-
- if (!str || !*str) return 0;
-
- while ((str = s) && (i < ANALOG_PORTS)) {
- if ((s = strchr(str,','))) *s++ = 0;
- js[i++] = str;
- }
-
- return 1;
-}
-__setup("js=", analog_setup);
-#endif
-
-int __init analog_init(void)
-{
- analog_parse_options();
- gameport_register_device(&analog_dev);
- return 0;
-}
-
-void __exit analog_exit(void)
-{
- gameport_unregister_device(&analog_dev);
-}
-
-module_init(analog_init);
-module_exit(analog_exit);
+++ /dev/null
-/*
- * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Creative Labd Blaster GamePad Cobra driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
-#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
-#define COBRA_LENGTH 36
-
-static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
-
-static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
-
-struct cobra {
- struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev[2];
- int used;
- int reads;
- int bads;
- unsigned char exists;
-};
-
-static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v, w;
- __u64 buf[2];
- int r[2], t[2];
- int i, j, ret;
-
- int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
-
- for (i = 0; i < 2; i++) {
- r[i] = buf[i] = 0;
- t[i] = COBRA_MAX_STROBE;
- }
-
- __save_flags(flags);
- __cli();
-
- u = gameport_read(gameport);
-
- do {
- t[0]--; t[1]--;
- v = gameport_read(gameport);
- for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
- if (w & 0x30) {
- if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
- buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
- t[i] = strobe;
- u = v;
- } else t[i] = 0;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
- ret = 0;
-
- for (i = 0; i < 2; i++) {
-
- if (r[i] != COBRA_LENGTH) continue;
-
- for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
- buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
-
- if (j < COBRA_LENGTH) ret |= (1 << i);
-
- data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
- | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
- | ((buf[i] >> 11) & 0x1f00000);
-
- }
-
- return ret;
-}
-
-static void cobra_timer(unsigned long private)
-{
- struct cobra *cobra = (void *) private;
- struct input_dev *dev;
- unsigned int data[2];
- int i, j, r;
-
- cobra->reads++;
-
- if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
- cobra->bads++;
-
- for (i = 0; i < 2; i++)
- if (cobra->exists & r & (1 << i)) {
-
- dev = cobra->dev + i;
-
- input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
- input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
-
- for (j = 0; cobra_btn[j]; j++)
- input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
-
- }
-
- mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
-}
-
-static int cobra_open(struct input_dev *dev)
-{
- struct cobra *cobra = dev->private;
- if (!cobra->used++)
- mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
- return 0;
-}
-
-static void cobra_close(struct input_dev *dev)
-{
- struct cobra *cobra = dev->private;
- if (!--cobra->used)
- del_timer(&cobra->timer);
-}
-
-static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct cobra *cobra;
- unsigned int data[2];
- int i, j;
-
- if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
- return;
- memset(cobra, 0, sizeof(struct cobra));
-
- gameport->private = cobra;
-
- cobra->gameport = gameport;
- init_timer(&cobra->timer);
- cobra->timer.data = (long) cobra;
- cobra->timer.function = cobra_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- cobra->exists = cobra_read_packet(gameport, data);
-
- for (i = 0; i < 2; i++)
- if ((cobra->exists >> i) & data[i] & 1) {
- printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
- " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
- cobra->exists &= ~(1 << i);
- }
-
- if (!cobra->exists)
- goto fail2;
-
- for (i = 0; i < 2; i++)
- if ((cobra->exists >> i) & 1) {
-
- cobra->dev[i].private = cobra;
- cobra->dev[i].open = cobra_open;
- cobra->dev[i].close = cobra_close;
-
- cobra->dev[i].name = cobra_name;
- cobra->dev[i].idbus = BUS_GAMEPORT;
- cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
- cobra->dev[i].idproduct = 0x0008;
- cobra->dev[i].idversion = 0x0100;
-
- cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
- for (j = 0; cobra_btn[j]; j++)
- set_bit(cobra_btn[j], cobra->dev[i].keybit);
-
- cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
- cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
-
- input_register_device(cobra->dev + i);
- printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
- cobra->dev[i].number, cobra_name, gameport->number, i);
- }
-
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(cobra);
-}
-
-static void cobra_disconnect(struct gameport *gameport)
-{
- int i;
-
- struct cobra *cobra = gameport->private;
- for (i = 0; i < 2; i++)
- if ((cobra->exists >> i) & 1)
- input_unregister_device(cobra->dev + i);
- gameport_close(gameport);
- kfree(cobra);
-}
-
-static struct gameport_dev cobra_dev = {
- connect: cobra_connect,
- disconnect: cobra_disconnect,
-};
-
-int __init cobra_init(void)
-{
- gameport_register_device(&cobra_dev);
- return 0;
-}
-
-void __exit cobra_exit(void)
-{
- gameport_unregister_device(&cobra_dev);
-}
-
-module_init(cobra_init);
-module_exit(cobra_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- The all defines and part of code (such as cs461x_*) are
- contributed from ALSA 0.5.8 sources.
- See http://www.alsa-project.org/ for sources
-
- Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
-*/
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
-MODULE_LICENSE("GPL");
-
-/*
- These options are experimental
-
-#define CS461X_FULL_MAP
-*/
-
-#define COOKED_MODE
-
-
-#ifndef PCI_VENDOR_ID_CIRRUS
-#define PCI_VENDOR_ID_CIRRUS 0x1013
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4610
-#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4612
-#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
-#endif
-#ifndef PCI_DEVICE_ID_CIRRUS_4615
-#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
-#endif
-
-/* Registers */
-
-#define BA0_JSPT 0x00000480
-#define BA0_JSCTL 0x00000484
-#define BA0_JSC1 0x00000488
-#define BA0_JSC2 0x0000048C
-#define BA0_JSIO 0x000004A0
-
-/* Bits for JSPT */
-
-#define JSPT_CAX 0x00000001
-#define JSPT_CAY 0x00000002
-#define JSPT_CBX 0x00000004
-#define JSPT_CBY 0x00000008
-#define JSPT_BA1 0x00000010
-#define JSPT_BA2 0x00000020
-#define JSPT_BB1 0x00000040
-#define JSPT_BB2 0x00000080
-
-/* Bits for JSCTL */
-
-#define JSCTL_SP_MASK 0x00000003
-#define JSCTL_SP_SLOW 0x00000000
-#define JSCTL_SP_MEDIUM_SLOW 0x00000001
-#define JSCTL_SP_MEDIUM_FAST 0x00000002
-#define JSCTL_SP_FAST 0x00000003
-#define JSCTL_ARE 0x00000004
-
-/* Data register pairs masks */
-
-#define JSC1_Y1V_MASK 0x0000FFFF
-#define JSC1_X1V_MASK 0xFFFF0000
-#define JSC1_Y1V_SHIFT 0
-#define JSC1_X1V_SHIFT 16
-#define JSC2_Y2V_MASK 0x0000FFFF
-#define JSC2_X2V_MASK 0xFFFF0000
-#define JSC2_Y2V_SHIFT 0
-#define JSC2_X2V_SHIFT 16
-
-/* JS GPIO */
-
-#define JSIO_DAX 0x00000001
-#define JSIO_DAY 0x00000002
-#define JSIO_DBX 0x00000004
-#define JSIO_DBY 0x00000008
-#define JSIO_AXOE 0x00000010
-#define JSIO_AYOE 0x00000020
-#define JSIO_BXOE 0x00000040
-#define JSIO_BYOE 0x00000080
-
-/*
- The card initialization code is obfuscated; the module cs461x
- need to be loaded after ALSA modules initialized and something
- played on the CS 4610 chip (see sources for details of CS4610
- initialization code from ALSA)
-*/
-
-/* Card specific definitions */
-
-#define CS461X_BA0_SIZE 0x2000
-#define CS461X_BA1_DATA0_SIZE 0x3000
-#define CS461X_BA1_DATA1_SIZE 0x3800
-#define CS461X_BA1_PRG_SIZE 0x7000
-#define CS461X_BA1_REG_SIZE 0x0100
-
-#define BA1_SP_DMEM0 0x00000000
-#define BA1_SP_DMEM1 0x00010000
-#define BA1_SP_PMEM 0x00020000
-#define BA1_SP_REG 0x00030000
-
-#define BA1_DWORD_SIZE (13 * 1024 + 512)
-#define BA1_MEMORY_COUNT 3
-
-/*
- Only one CS461x card is still suppoted; the code requires
- redesign to avoid this limitatuion.
-*/
-
-static unsigned long ba0_addr;
-static unsigned int *ba0;
-
-#ifdef CS461X_FULL_MAP
-static unsigned long ba1_addr;
-static union ba1_t {
- struct {
- unsigned int *data0;
- unsigned int *data1;
- unsigned int *pmem;
- unsigned int *reg;
- } name;
- unsigned int *idx[4];
-} ba1;
-
-static void cs461x_poke(unsigned long reg, unsigned int val)
-{
- ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
-}
-
-static unsigned int cs461x_peek(unsigned long reg)
-{
- return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
-}
-
-#endif
-
-static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
-{
- ba0[reg >> 2] = val;
-}
-
-static unsigned int cs461x_peekBA0(unsigned long reg)
-{
- return ba0[reg >> 2];
-}
-
-static int cs461x_free(struct pci_dev *pdev)
-{
- struct gameport *port = pci_get_drvdata(pdev);
- if(port){
- gameport_unregister_port(port);
- kfree(port);
- }
- if (ba0) iounmap(ba0);
-#ifdef CS461X_FULL_MAP
- if (ba1.name.data0) iounmap(ba1.name.data0);
- if (ba1.name.data1) iounmap(ba1.name.data1);
- if (ba1.name.pmem) iounmap(ba1.name.pmem);
- if (ba1.name.reg) iounmap(ba1.name.reg);
-#endif
- return 0;
-}
-
-static void cs461x_gameport_trigger(struct gameport *gameport)
-{
- cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
-}
-
-static unsigned char cs461x_gameport_read(struct gameport *gameport)
-{
- return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
-}
-
-static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- unsigned js1, js2, jst;
-
- js1 = cs461x_peekBA0(BA0_JSC1);
- js2 = cs461x_peekBA0(BA0_JSC2);
- jst = cs461x_peekBA0(BA0_JSPT);
-
- *buttons = (~jst >> 4) & 0x0F;
-
- axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
- axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
- axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
- axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
-
- for(jst=0;jst<4;++jst)
- if(axes[jst]==0xFFFF) axes[jst] = -1;
- return 0;
-}
-
-static int cs461x_gameport_open(struct gameport *gameport, int mode)
-{
- switch (mode) {
-#ifdef COOKED_MODE
- case GAMEPORT_MODE_COOKED:
- return 0;
-#endif
- case GAMEPORT_MODE_RAW:
- return 0;
- default:
- return -1;
- }
- return 0;
-}
-
-static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
- { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
- { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
- { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
- { 0, }
-};
-MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
-
-static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int rc;
- struct gameport* port;
-
- rc = pci_enable_device(pdev);
- if (rc) {
- printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
- pdev->bus->number, pdev->devfn, rc);
- return rc;
- }
-
- ba0_addr = pci_resource_start(pdev, 0);
-#ifdef CS461X_FULL_MAP
- ba1_addr = pci_resource_start(pdev, 1);
-#endif
- if (ba0_addr == 0 || ba0_addr == ~0
-#ifdef CS461X_FULL_MAP
- || ba1_addr == 0 || ba1_addr == ~0
-#endif
- ) {
- printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
-#ifdef CS461X_FULL_MAP
- printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
-#endif
- cs461x_free(pdev);
- return -ENOMEM;
- }
-
- ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
-#ifdef CS461X_FULL_MAP
- ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
- ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
- ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
- ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
-
- if (ba0 == NULL || ba1.name.data0 == NULL ||
- ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
- ba1.name.reg == NULL) {
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#else
- if (ba0 == NULL){
- cs461x_free(pdev);
- return -ENOMEM;
- }
-#endif
- printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
- ba0_addr, CS461X_BA0_SIZE);
-
- if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
- printk(KERN_ERR "Memory allocation failed.\n");
- cs461x_free(pdev);
- return -ENOMEM;
- }
- memset(port, 0, sizeof(struct gameport));
-
- pci_set_drvdata(pdev, port);
-
- port->open = cs461x_gameport_open;
- port->read = cs461x_gameport_read;
- port->trigger = cs461x_gameport_trigger;
-#ifdef COOKED_MODE
- port->cooked_read = cs461x_gameport_cooked_read;
-#endif
-
- cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
- cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
-
- gameport_register_port(port);
-
- printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
- port->number, port->speed);
-
- return 0;
-}
-
-static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
-{
- cs461x_free(pdev);
-}
-
-static struct pci_driver cs461x_pci_driver = {
- name: "PCI Gameport",
- id_table: cs461x_pci_tbl,
- probe: cs461x_pci_probe,
- remove: cs461x_pci_remove,
-};
-
-int __init js_cs461x_init(void)
-{
- return pci_module_init(&cs461x_pci_driver);
-}
-
-void __exit js_cs461x_exit(void)
-{
- pci_unregister_driver(&cs461x_pci_driver);
-}
-
-module_init(js_cs461x_init);
-module_exit(js_cs461x_exit);
-
+++ /dev/null
-/*
- * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $
- *
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Based on the work of:
- * Andree Borrmann Mats Sjövall
- *
- * Sponsored by SuSE
- */
-
-/*
- * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(db9, "2i");
-MODULE_PARM(db9_2, "2i");
-MODULE_PARM(db9_3, "2i");
-
-#define DB9_MULTI_STICK 0x01
-#define DB9_MULTI2_STICK 0x02
-#define DB9_GENESIS_PAD 0x03
-#define DB9_GENESIS5_PAD 0x05
-#define DB9_GENESIS6_PAD 0x06
-#define DB9_SATURN_PAD 0x07
-#define DB9_MULTI_0802 0x08
-#define DB9_MULTI_0802_2 0x09
-#define DB9_CD32_PAD 0x0A
-#define DB9_MAX_PAD 0x0B
-
-#define DB9_UP 0x01
-#define DB9_DOWN 0x02
-#define DB9_LEFT 0x04
-#define DB9_RIGHT 0x08
-#define DB9_FIRE1 0x10
-#define DB9_FIRE2 0x20
-#define DB9_FIRE3 0x40
-#define DB9_FIRE4 0x80
-
-#define DB9_NORMAL 0x0a
-#define DB9_NOSELECT 0x08
-
-#define DB9_SATURN0 0x00
-#define DB9_SATURN1 0x02
-#define DB9_SATURN2 0x04
-#define DB9_SATURN3 0x06
-
-#define DB9_GENESIS6_DELAY 14
-#define DB9_REFRESH_TIME HZ/100
-
-static int db9[] __initdata = { -1, 0 };
-static int db9_2[] __initdata = { -1, 0 };
-static int db9_3[] __initdata = { -1, 0 };
-
-struct db9 {
- struct input_dev dev[2];
- struct timer_list timer;
- struct pardevice *pd;
- int mode;
- int used;
-};
-
-static struct db9 *db9_base[3];
-
-static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
-static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
-static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
-
-static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
-static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
- db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
-static char *db9_name[DB9_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", "Amiga CD-32 pad" };
-
-static void db9_timer(unsigned long private)
-{
- struct db9 *db9 = (void *) private;
- struct parport *port = db9->pd->port;
- struct input_dev *dev = db9->dev;
- int data, i;
-
- switch(db9->mode) {
- case DB9_MULTI_0802_2:
-
- data = parport_read_data(port) >> 3;
-
- input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
-
- case DB9_MULTI_0802:
-
- data = parport_read_status(port) >> 3;
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
- break;
-
- case DB9_MULTI_STICK:
-
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
- break;
-
- case DB9_MULTI2_STICK:
-
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2);
- break;
-
- case DB9_GENESIS_PAD:
-
- parport_write_control(port, DB9_NOSELECT);
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
- parport_write_control(port, DB9_NORMAL);
- data=parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
- break;
-
- case DB9_GENESIS5_PAD:
-
- parport_write_control(port, DB9_NOSELECT);
- data=parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
- parport_write_control(port, DB9_NORMAL);
- data=parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
- break;
-
- case DB9_GENESIS6_PAD:
-
- parport_write_control(port, DB9_NOSELECT); /* 1 */
- udelay(DB9_GENESIS6_DELAY);
- data=parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
- input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
-
- parport_write_control(port, DB9_NORMAL);
- udelay(DB9_GENESIS6_DELAY);
- data=parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
- input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
-
- parport_write_control(port, DB9_NOSELECT); /* 2 */
- udelay(DB9_GENESIS6_DELAY);
- parport_write_control(port, DB9_NORMAL);
- udelay(DB9_GENESIS6_DELAY);
- parport_write_control(port, DB9_NOSELECT); /* 3 */
- udelay(DB9_GENESIS6_DELAY);
- data=parport_read_data(port);
-
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
- input_report_key(dev, BTN_MODE, ~data & DB9_UP);
- input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
-
- parport_write_control(port, DB9_NORMAL);
- udelay(DB9_GENESIS6_DELAY);
- parport_write_control(port, DB9_NOSELECT); /* 4 */
- udelay(DB9_GENESIS6_DELAY);
- parport_write_control(port, DB9_NORMAL);
- break;
-
- case DB9_SATURN_PAD:
-
- parport_write_control(port, DB9_SATURN0);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
- input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
- input_report_key(dev, BTN_TL, ~data & DB9_UP);
- input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
-
- parport_write_control(port, DB9_SATURN2);
- data = parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
-
- parport_write_control(port, DB9_NORMAL);
- data = parport_read_data(port);
-
- input_report_key(dev, BTN_A, ~data & DB9_LEFT);
- input_report_key(dev, BTN_B, ~data & DB9_UP);
- input_report_key(dev, BTN_C, ~data & DB9_DOWN);
- input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
- break;
-
- case DB9_CD32_PAD:
-
- data=parport_read_data(port);
-
- input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
- input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
-
- parport_write_control(port, 0x0a);
-
- for (i = 0; i < 7; i++) {
- data = parport_read_data(port);
- parport_write_control(port, 0x02);
- parport_write_control(port, 0x0a);
- input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
- }
-
- parport_write_control(port, 0x00);
- break;
- }
-
- mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
-}
-
-static int db9_open(struct input_dev *dev)
-{
- struct db9 *db9 = dev->private;
- struct parport *port = db9->pd->port;
-
- if (!db9->used++) {
- parport_claim(db9->pd);
- parport_write_data(port, 0xff);
- parport_data_reverse(port);
- parport_write_control(port, DB9_NORMAL);
- mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
- }
-
- return 0;
-}
-
-static void db9_close(struct input_dev *dev)
-{
- struct db9 *db9 = dev->private;
- struct parport *port = db9->pd->port;
-
- if (!--db9->used) {
- del_timer(&db9->timer);
- parport_write_control(port, 0x00);
- parport_data_forward(port);
- parport_release(db9->pd);
- }
-}
-
-static struct db9 __init *db9_probe(int *config)
-{
- struct db9 *db9;
- struct parport *pp;
- int i, j;
-
- if (config[0] < 0)
- return NULL;
- if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
- printk(KERN_ERR "db9.c: bad config\n");
- return NULL;
- }
-
- for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
- config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "db9.c: no such parport\n");
- return NULL;
- }
-
- if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
- printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
- return NULL;
- }
-
- if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
- return NULL;
- memset(db9, 0, sizeof(struct db9));
-
- db9->mode = config[1];
- init_timer(&db9->timer);
- db9->timer.data = (long) db9;
- db9->timer.function = db9_timer;
-
- db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
- if (!db9->pd) {
- printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
- kfree(db9);
- return NULL;
- }
-
- for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
-
- db9->dev[i].private = db9;
- db9->dev[i].open = db9_open;
- db9->dev[i].close = db9_close;
-
- db9->dev[i].name = db9_name[db9->mode];
- db9->dev[i].idbus = BUS_PARPORT;
- db9->dev[i].idvendor = 0x0002;
- db9->dev[i].idproduct = config[1];
- db9->dev[i].idversion = 0x0100;
-
- db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
- for (j = 0; j < db9_buttons[db9->mode]; j++)
- set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
-
- db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
- db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
-
- input_register_device(db9->dev + i);
- printk(KERN_INFO "input%d: %s on %s\n",
- db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
- }
-
- return db9;
-}
-
-#ifndef MODULE
-int __init db9_setup(char *str)
-{
- int i, ints[3];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
- return 1;
-}
-int __init db9_setup_2(char *str)
-{
- int i, ints[3];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
- return 1;
-}
-int __init db9_setup_3(char *str)
-{
- int i, ints[3];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
- return 1;
-}
-__setup("db9=", db9_setup);
-__setup("db9_2=", db9_setup_2);
-__setup("db9_3=", db9_setup_3);
-#endif
-
-int __init db9_init(void)
-{
- db9_base[0] = db9_probe(db9);
- db9_base[1] = db9_probe(db9_2);
- db9_base[2] = db9_probe(db9_3);
-
- if (db9_base[0] || db9_base[1] || db9_base[2])
- return 0;
-
- return -ENODEV;
-}
-
-void __exit db9_exit(void)
-{
- int i, j;
-
- for (i = 0; i < 3; i++)
- if (db9_base[i]) {
- for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
- input_unregister_device(db9_base[i]->dev + j);
- parport_unregister_device(db9_base[i]->pd);
- }
-}
-
-module_init(db9_init);
-module_exit(db9_exit);
+++ /dev/null
-/*
- * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
- *
- * Copyright (c) 2001 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * EMU10k1 - SB Live! - gameport driver for Linux
- */
-
-/*
- * 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/pci.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-struct emu {
- struct pci_dev *dev;
- struct emu *next;
- struct gameport gameport;
- int size;
-};
-
-static struct pci_device_id emu_tbl[] __devinitdata = {
- { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
- { 0, }
-};
-
-MODULE_DEVICE_TABLE(pci, emu_tbl);
-
-static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
-{
- int ioport, iolen;
- int rc;
- struct emu *port;
-
- rc = pci_enable_device(pdev);
- if (rc) {
- printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
- pdev->bus->number, pdev->devfn, rc);
- return rc;
- }
-
- ioport = pci_resource_start(pdev, 0);
- iolen = pci_resource_len(pdev, 0);
-
- if (!request_region(ioport, iolen, "emu10k1-gp"))
- return -EBUSY;
-
- if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
- printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
- release_region(ioport, iolen);
- return -ENOMEM;
- }
- memset(port, 0, sizeof(struct emu));
-
- port->gameport.io = ioport;
- port->size = iolen;
- port->dev = pdev;
- pci_set_drvdata(pdev, port);
-
- gameport_register_port(&port->gameport);
-
- printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
- port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
-
- return 0;
-}
-
-static void __devexit emu_remove(struct pci_dev *pdev)
-{
- struct emu *port = pci_get_drvdata(pdev);
- gameport_unregister_port(&port->gameport);
- release_region(port->gameport.io, port->size);
- kfree(port);
-}
-
-static struct pci_driver emu_driver = {
- name: "Emu10k1 Gameport",
- id_table: emu_tbl,
- probe: emu_probe,
- remove: emu_remove,
-};
-
-int __init emu_init(void)
-{
- return pci_module_init(&emu_driver);
-}
-
-void __exit emu_exit(void)
-{
- pci_unregister_driver(&emu_driver);
-}
-
-module_init(emu_init);
-module_exit(emu_exit);
+++ /dev/null
-/*
- * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
- *
- * Copyright (c) 1999-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Andree Borrmann John Dahlstrom
- * David Kuder Nathan Hand
- *
- * Sponsored by SuSE
- */
-
-/*
- * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/delay.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(gc, "2-6i");
-MODULE_PARM(gc_2,"2-6i");
-MODULE_PARM(gc_3,"2-6i");
-
-#define GC_SNES 1
-#define GC_NES 2
-#define GC_NES4 3
-#define GC_MULTI 4
-#define GC_MULTI2 5
-#define GC_N64 6
-#define GC_PSX 7
-
-#define GC_MAX 7
-
-#define GC_REFRESH_TIME HZ/100
-
-struct gc {
- struct pardevice *pd;
- struct input_dev dev[5];
- struct timer_list timer;
- unsigned char pads[GC_MAX + 1];
- int used;
-};
-
-static struct gc *gc_base[3];
-
-static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
-
-static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
-
-static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
- "Multisystem 2-button joystick", "N64 controller", "PSX controller" };
-/*
- * N64 support.
- */
-
-static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
-static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
-
-#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
-#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
-#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
-#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
-#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
- /* GC_N64_DWS > 24 is known to fail */
-#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
-#define GC_N64_POWER_R 0xfd /* power during read */
-#define GC_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 GC_N64_OUT is pulled low on the output port (by any routine) for more */
- /* than 123 us */
-#define GC_N64_CLOCK 0x02 /* clock bits for read */
-
-/*
- * gc_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 gc_n64_read_packet(struct gc *gc, unsigned char *data)
-{
- int i;
- unsigned long flags;
-
-/*
- * Request the pad to transmit data
- */
-
- __save_flags(flags);
- __cli();
- for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
- parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
- udelay(GC_N64_DWS);
- }
- __restore_flags(flags);
-
-/*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
- */
-
- udelay(GC_N64_DELAY);
-
-/*
- * Grab data (ignoring the last bit, which is a stop bit)
- */
-
- for (i = 0; i < GC_N64_LENGTH; i++) {
- parport_write_data(gc->pd->port, GC_N64_POWER_R);
- data[i] = parport_read_status(gc->pd->port);
- parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
- }
-
-/*
- * We must wait 200 ms here for the controller to reinitialize before the next read request.
- * No worries as long as gc_read is polled less frequently than this.
- */
-
-}
-
-/*
- * NES/SNES support.
- */
-
-#define GC_NES_DELAY 6 /* Delay between bits - 6us */
-#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */
-#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
-
-#define GC_NES_POWER 0xfc
-#define GC_NES_CLOCK 0x01
-#define GC_NES_LATCH 0x02
-
-static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
-static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
-static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
-
-/*
- * gc_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 gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
-{
- int i;
-
- parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
- udelay(GC_NES_DELAY * 2);
- parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
-
- for (i = 0; i < length; i++) {
- udelay(GC_NES_DELAY);
- parport_write_data(gc->pd->port, GC_NES_POWER);
- data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
- udelay(GC_NES_DELAY);
- parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
- }
-}
-
-/*
- * Multisystem joystick support
- */
-
-#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */
-#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */
-
-/*
- * gc_multi_read_packet() reads a Multisystem joystick packet.
- */
-
-static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
-{
- int i;
-
- for (i = 0; i < length; i++) {
- parport_write_data(gc->pd->port, ~(1 << i));
- data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
- }
-}
-
-/*
- * PSX support
- *
- * See documentation at:
- * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
- * http://www.gamesx.com/controldata/psxcont/psxcont.htm
- * ftp://milano.usal.es/pablo/
- *
- */
-
-#define GC_PSX_DELAY 60 /* 60 usec */
-#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
-
-#define GC_PSX_MOUSE 1 /* Mouse */
-#define GC_PSX_NEGCON 2 /* NegCon */
-#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */
-#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */
-#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */
-
-#define GC_PSX_CLOCK 0x04 /* Pin 4 */
-#define GC_PSX_COMMAND 0x01 /* Pin 1 */
-#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
-#define GC_PSX_SELECT 0x02 /* Pin 3 */
-
-#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */
-#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */
-
-static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
-static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
- BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
-
-/*
- * gc_psx_command() writes 8bit command and reads 8bit data from
- * the psx pad.
- */
-
-static int gc_psx_command(struct gc *gc, int b)
-{
- int i, cmd, data = 0;
-
- for (i = 0; i < 8; i++, b >>= 1) {
- cmd = (b & 1) ? GC_PSX_COMMAND : 0;
- parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
- udelay(GC_PSX_DELAY);
- data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
- parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
- udelay(GC_PSX_DELAY);
- }
- return data;
-}
-
-/*
- * gc_psx_read_packet() reads a whole psx packet and returns
- * device identifier code.
- */
-
-static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
-{
- int i, id;
- unsigned long flags;
-
- parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
- udelay(GC_PSX_DELAY * 2);
- parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
- udelay(GC_PSX_DELAY * 2);
-
- __save_flags(flags);
- __cli();
-
- gc_psx_command(gc, 0x01); /* Access pad */
- id = gc_psx_command(gc, 0x42); /* Get device id */
- if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */
- for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
- data[i] = gc_psx_command(gc, 0);
- } else id = 0;
-
- __restore_flags(flags);
-
- parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
-
- return GC_PSX_ID(id);
-}
-
-/*
- * gc_timer() reads and analyzes console pads data.
- */
-
-#define GC_MAX_LENGTH GC_N64_LENGTH
-
-static void gc_timer(unsigned long private)
-{
- struct gc *gc = (void *) private;
- struct input_dev *dev = gc->dev;
- unsigned char data[GC_MAX_LENGTH];
- int i, j, s;
-
-/*
- * N64 pads - must be read first, any read confuses them for 200 us
- */
-
- if (gc->pads[GC_N64]) {
-
- gc_n64_read_packet(gc, data);
-
- for (i = 0; i < 5; i++) {
-
- s = gc_status_bit[i];
-
- if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
-
- signed char axes[2];
- axes[0] = axes[1] = 0;
-
- for (j = 0; j < 8; j++) {
- if (data[23 - j] & s) axes[0] |= 1 << j;
- if (data[31 - j] & s) axes[1] |= 1 << j;
- }
-
- input_report_abs(dev + i, ABS_X, axes[0]);
- input_report_abs(dev + i, ABS_Y, -axes[1]);
-
- input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
- input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
-
- for (j = 0; j < 10; j++)
- input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
- }
- }
- }
-
-/*
- * NES and SNES pads
- */
-
- if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
-
- gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
-
- s = gc_status_bit[i];
-
- if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
- input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
- input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
- }
-
- if (s & gc->pads[GC_NES])
- for (j = 0; j < 4; j++)
- input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
-
- if (s & gc->pads[GC_SNES])
- for (j = 0; j < 8; j++)
- input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
- }
- }
-
-/*
- * Multi and Multi2 joysticks
- */
-
- if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
-
- gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
-
- s = gc_status_bit[i];
-
- if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
- input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3]));
- input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1]));
- input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
- }
-
- if (s & gc->pads[GC_MULTI2])
- input_report_key(dev + i, BTN_THUMB, s & data[5]);
- }
- }
-
-/*
- * PSX controllers
- */
-
- if (gc->pads[GC_PSX]) {
-
- for (i = 0; i < 5; i++)
- if (gc->pads[GC_PSX] & gc_status_bit[i])
- break;
-
- switch (gc_psx_read_packet(gc, data)) {
-
- case GC_PSX_RUMBLE:
-
- input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
- input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
-
- case GC_PSX_NEGCON:
- case GC_PSX_ANALOG:
-
- for (j = 0; j < 4; j++)
- input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
-
- input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
- input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
-
- for (j = 0; j < 8; j++)
- input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
-
- input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
- input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
-
- break;
-
- case GC_PSX_NORMAL:
-
- input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
- input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
-
- for (j = 0; j < 8; j++)
- input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
-
- input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
- input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
-
- break;
- }
- }
-
- mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
-}
-
-static int gc_open(struct input_dev *dev)
-{
- struct gc *gc = dev->private;
- if (!gc->used++) {
- parport_claim(gc->pd);
- parport_write_control(gc->pd->port, 0x04);
- mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
- }
- return 0;
-}
-
-static void gc_close(struct input_dev *dev)
-{
- struct gc *gc = dev->private;
- if (!--gc->used) {
- del_timer(&gc->timer);
- parport_write_control(gc->pd->port, 0x00);
- parport_release(gc->pd);
- }
-}
-
-static struct gc __init *gc_probe(int *config)
-{
- struct gc *gc;
- struct parport *pp;
- int i, j, psx;
- unsigned char data[32];
-
- if (config[0] < 0)
- return NULL;
-
- for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
- config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "gamecon.c: no such parport\n");
- return NULL;
- }
-
- if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
- return NULL;
- memset(gc, 0, sizeof(struct gc));
-
- gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
- if (!gc->pd) {
- printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
- kfree(gc);
- return NULL;
- }
-
- parport_claim(gc->pd);
-
- init_timer(&gc->timer);
- gc->timer.data = (long) gc;
- gc->timer.function = gc_timer;
-
- for (i = 0; i < 5; i++) {
-
- if (!config[i + 1])
- continue;
-
- if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
- printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
- continue;
- }
-
- gc->dev[i].private = gc;
- gc->dev[i].open = gc_open;
- gc->dev[i].close = gc_close;
-
- gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (j = 0; j < 2; j++) {
- set_bit(ABS_X + j, gc->dev[i].absbit);
- gc->dev[i].absmin[ABS_X + j] = -1;
- gc->dev[i].absmax[ABS_X + j] = 1;
- }
-
- gc->pads[0] |= gc_status_bit[i];
- gc->pads[config[i + 1]] |= gc_status_bit[i];
-
- switch(config[i + 1]) {
-
- case GC_N64:
- for (j = 0; j < 10; j++)
- set_bit(gc_n64_btn[j], gc->dev[i].keybit);
-
- for (j = 0; j < 2; j++) {
- set_bit(ABS_X + j, gc->dev[i].absbit);
- gc->dev[i].absmin[ABS_X + j] = -127;
- gc->dev[i].absmax[ABS_X + j] = 126;
- gc->dev[i].absflat[ABS_X + j] = 2;
- set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
- gc->dev[i].absmin[ABS_HAT0X + j] = -1;
- gc->dev[i].absmax[ABS_HAT0X + j] = 1;
- }
-
- break;
-
- case GC_SNES:
- for (j = 4; j < 8; j++)
- set_bit(gc_snes_btn[j], gc->dev[i].keybit);
- case GC_NES:
- for (j = 0; j < 4; j++)
- set_bit(gc_snes_btn[j], gc->dev[i].keybit);
- break;
-
- case GC_MULTI2:
- set_bit(BTN_THUMB, gc->dev[i].keybit);
- case GC_MULTI:
- set_bit(BTN_TRIGGER, gc->dev[i].keybit);
- break;
-
- case GC_PSX:
-
- psx = gc_psx_read_packet(gc, data);
-
- switch(psx) {
- case GC_PSX_NEGCON:
- case GC_PSX_NORMAL:
- case GC_PSX_ANALOG:
- case GC_PSX_RUMBLE:
-
- for (j = 0; j < 6; j++) {
- psx = gc_psx_abs[j];
- set_bit(psx, gc->dev[i].absbit);
- if (j < 4) {
- gc->dev[i].absmin[psx] = 4;
- gc->dev[i].absmax[psx] = 252;
- gc->dev[i].absflat[psx] = 2;
- } else {
- gc->dev[i].absmin[psx] = -1;
- gc->dev[i].absmax[psx] = 1;
- }
- }
-
- for (j = 0; j < 12; j++)
- set_bit(gc_psx_btn[j], gc->dev[i].keybit);
-
- break;
-
- case 0:
- gc->pads[GC_PSX] &= ~gc_status_bit[i];
- printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
- break;
-
- default:
- gc->pads[GC_PSX] &= ~gc_status_bit[i];
- printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
- " please report to <vojtech@suse.cz>.\n", psx);
- }
- break;
- }
-
- gc->dev[i].name = gc_names[config[i + 1]];
- gc->dev[i].idbus = BUS_PARPORT;
- gc->dev[i].idvendor = 0x0001;
- gc->dev[i].idproduct = config[i + 1];
- gc->dev[i].idversion = 0x0100;
- }
-
- parport_release(gc->pd);
-
- if (!gc->pads[0]) {
- parport_unregister_device(gc->pd);
- kfree(gc);
- return NULL;
- }
-
- for (i = 0; i < 5; i++)
- if (gc->pads[0] & gc_status_bit[i]) {
- input_register_device(gc->dev + i);
- printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
- }
-
- return gc;
-}
-
-#ifndef MODULE
-int __init gc_setup(char *str)
-{
- int i, ints[7];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
- return 1;
-}
-int __init gc_setup_2(char *str)
-{
- int i, ints[7];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
- return 1;
-}
-int __init gc_setup_3(char *str)
-{
- int i, ints[7];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
- return 1;
-}
-__setup("gc=", gc_setup);
-__setup("gc_2=", gc_setup_2);
-__setup("gc_3=", gc_setup_3);
-#endif
-
-int __init gc_init(void)
-{
- gc_base[0] = gc_probe(gc);
- gc_base[1] = gc_probe(gc_2);
- gc_base[2] = gc_probe(gc_3);
-
- if (gc_base[0] || gc_base[1] || gc_base[2])
- return 0;
-
- return -ENODEV;
-}
-
-void __exit gc_exit(void)
-{
- int i, j;
-
- for (i = 0; i < 3; i++)
- if (gc_base[i]) {
- for (j = 0; j < 5; j++)
- if (gc_base[i]->pads[0] & gc_status_bit[j])
- input_unregister_device(gc_base[i]->dev + j);
- parport_unregister_device(gc_base[i]->pd);
- }
-}
-
-module_init(gc_init);
-module_exit(gc_exit);
+++ /dev/null
-/*
- * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Generic gameport layer
- */
-
-/*
- * 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/module.h>
-#include <linux/ioport.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/isapnp.h>
-#include <linux/stddef.h>
-#include <linux/delay.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(gameport_register_port);
-EXPORT_SYMBOL(gameport_unregister_port);
-EXPORT_SYMBOL(gameport_register_device);
-EXPORT_SYMBOL(gameport_unregister_device);
-EXPORT_SYMBOL(gameport_open);
-EXPORT_SYMBOL(gameport_close);
-EXPORT_SYMBOL(gameport_rescan);
-EXPORT_SYMBOL(gameport_cooked_read);
-
-static struct gameport *gameport_list;
-static struct gameport_dev *gameport_dev;
-static int gameport_number;
-
-/*
- * gameport_measure_speed() measures the gameport i/o speed.
- */
-
-static int gameport_measure_speed(struct gameport *gameport)
-{
-#if defined(__i386__) || defined(__x86_64__)
-
-#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;
-
- if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
- return 0;
-
- 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++) gameport_read(gameport);
- 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 / (tx < 1 ? 1 : tx);
-
-#else
-
- unsigned int j, t = 0;
-
- j = jiffies; while (j == jiffies);
- j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
-
- return t * HZ / 1000;
-
-#endif
-
- gameport_close(gameport);
-}
-
-static void gameport_find_dev(struct gameport *gameport)
-{
- struct gameport_dev *dev = gameport_dev;
-
- while (dev && !gameport->dev) {
- if (dev->connect)
- dev->connect(gameport, dev);
- dev = dev->next;
- }
-}
-
-void gameport_rescan(struct gameport *gameport)
-{
- gameport_close(gameport);
- gameport_find_dev(gameport);
-}
-
-void gameport_register_port(struct gameport *gameport)
-{
- gameport->number = gameport_number++;
- gameport->next = gameport_list;
- gameport_list = gameport;
-
- gameport->speed = gameport_measure_speed(gameport);
-
- gameport_find_dev(gameport);
-}
-
-void gameport_unregister_port(struct gameport *gameport)
-{
- struct gameport **gameportptr = &gameport_list;
-
- while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
- *gameportptr = (*gameportptr)->next;
-
- if (gameport->dev && gameport->dev->disconnect)
- gameport->dev->disconnect(gameport);
-
- gameport_number--;
-}
-
-void gameport_register_device(struct gameport_dev *dev)
-{
- struct gameport *gameport = gameport_list;
-
- dev->next = gameport_dev;
- gameport_dev = dev;
-
- while (gameport) {
- if (!gameport->dev && dev->connect)
- dev->connect(gameport, dev);
- gameport = gameport->next;
- }
-}
-
-void gameport_unregister_device(struct gameport_dev *dev)
-{
- struct gameport_dev **devptr = &gameport_dev;
- struct gameport *gameport = gameport_list;
-
- while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
- *devptr = (*devptr)->next;
-
- while (gameport) {
- if (gameport->dev == dev && dev->disconnect)
- dev->disconnect(gameport);
- gameport_find_dev(gameport);
- gameport = gameport->next;
- }
-}
-
-int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
-{
- if (gameport->open) {
- if (gameport->open(gameport, mode))
- return -1;
- } else {
- if (mode != GAMEPORT_MODE_RAW)
- return -1;
- }
-
- if (gameport->dev)
- return -1;
-
- gameport->dev = dev;
-
- return 0;
-}
-
-void gameport_close(struct gameport *gameport)
-{
- gameport->dev = NULL;
- if (gameport->close) gameport->close(gameport);
-}
+++ /dev/null
-/*
- * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Genius Flight 2000 joystick driver for Linux
- */
-
-/*
- * 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/delay.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-
-#define GF2K_START 400 /* The time we wait for the first bit [400 us] */
-#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
-#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
-#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
-#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
-
-/*
- * Genius joystick ids ...
- */
-
-#define GF2K_ID_G09 1
-#define GF2K_ID_F30D 2
-#define GF2K_ID_F30 3
-#define GF2K_ID_F31D 4
-#define GF2K_ID_F305 5
-#define GF2K_ID_F23P 6
-#define GF2K_ID_F31 7
-#define GF2K_ID_MAX 7
-
-static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
-static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
- "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
-static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
-static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
-static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
-static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
-static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
-
-static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
-static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
-static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
-
-
-static short gf2k_seq_reset[] = { 240, 340, 0 };
-static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
-
-struct gf2k {
- struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev;
- int reads;
- int bads;
- int used;
- unsigned char id;
- unsigned char length;
-};
-
-/*
- * gf2k_read_packet() reads a Genius Flight2000 packet.
- */
-
-static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
-{
- unsigned char u, v;
- int i;
- unsigned int t, p;
- unsigned long flags;
-
- t = gameport_time(gameport, GF2K_START);
- p = gameport_time(gameport, GF2K_STROBE);
-
- i = 0;
-
- __save_flags(flags);
- __cli();
-
- gameport_trigger(gameport);
- v = gameport_read(gameport);;
-
- while (t > 0 && i < length) {
- t--; u = v;
- v = gameport_read(gameport);
- if (v & ~u & 0x10) {
- data[i++] = v >> 5;
- t = p;
- }
- }
-
- __restore_flags(flags);
-
- return i;
-}
-
-/*
- * gf2k_trigger_seq() initializes a Genius Flight2000 joystick
- * into digital mode.
- */
-
-static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
-{
-
- unsigned long flags;
- int i, t;
-
- __save_flags(flags);
- __cli();
-
- i = 0;
- do {
- gameport_trigger(gameport);
- t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
- while ((gameport_read(gameport) & 1) && t) t--;
- udelay(seq[i]);
- } while (seq[++i]);
-
- gameport_trigger(gameport);
-
- __restore_flags(flags);
-}
-
-/*
- * js_sw_get_bits() composes 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(p,n,s) gf2k_get_bits(data, p, n, s)
-
-static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
-{
- __u64 data = 0;
- int i;
-
- for (i = 0; i < num / 3 + 2; i++)
- data |= buf[pos / 3 + i] << (i * 3);
- data >>= pos % 3;
- data &= (1 << num) - 1;
- data <<= shift;
-
- return data;
-}
-
-static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
-{
- struct input_dev *dev = &gf2k->dev;
- int i, t;
-
- for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
- input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
-
- for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
- input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
-
- t = GB(40,4,0);
-
- for (i = 0; i < gf2k_hats[gf2k->id]; i++)
- input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
-
- t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
-
- for (i = 0; i < gf2k_joys[gf2k->id]; i++)
- input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
-
- for (i = 0; i < gf2k_pads[gf2k->id]; i++)
- input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
-}
-
-/*
- * gf2k_timer() reads and analyzes Genius joystick data.
- */
-
-static void gf2k_timer(unsigned long private)
-{
- struct gf2k *gf2k = (void *) private;
- unsigned char data[GF2K_LENGTH];
-
- gf2k->reads++;
-
- if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
- gf2k->bads++;
- } else gf2k_read(gf2k, data);
-
- mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
-}
-
-static int gf2k_open(struct input_dev *dev)
-{
- struct gf2k *gf2k = dev->private;
- if (!gf2k->used++)
- mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
- return 0;
-}
-
-static void gf2k_close(struct input_dev *dev)
-{
- struct gf2k *gf2k = dev->private;
- if (!--gf2k->used)
- del_timer(&gf2k->timer);
-}
-
-/*
- * gf2k_connect() probes for Genius id joysticks.
- */
-
-static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct gf2k *gf2k;
- unsigned char data[GF2K_LENGTH];
- int i;
-
- if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
- return;
- memset(gf2k, 0, sizeof(struct gf2k));
-
- gameport->private = gf2k;
-
- gf2k->gameport = gameport;
- init_timer(&gf2k->timer);
- gf2k->timer.data = (long) gf2k;
- gf2k->timer.function = gf2k_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- gf2k_trigger_seq(gameport, gf2k_seq_reset);
-
- wait_ms(GF2K_TIMEOUT);
-
- gf2k_trigger_seq(gameport, gf2k_seq_digital);
-
- wait_ms(GF2K_TIMEOUT);
-
- if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
- goto fail2;
-
- if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
- goto fail2;
-
-#ifdef RESET_WORKS
- if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
- (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
- goto fail2;
-#else
- gf2k->id = 6;
-#endif
-
- if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
- printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
- gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
- goto fail2;
- }
-
- gf2k->length = gf2k_lens[gf2k->id];
-
- gf2k->dev.private = gf2k;
- gf2k->dev.open = gf2k_open;
- gf2k->dev.close = gf2k_close;
- gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- gf2k->dev.name = gf2k_names[gf2k->id];
- gf2k->dev.idbus = BUS_GAMEPORT;
- gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
- gf2k->dev.idproduct = gf2k->id;
- gf2k->dev.idversion = 0x0100;
-
- for (i = 0; i < gf2k_axes[gf2k->id]; i++)
- set_bit(gf2k_abs[i], gf2k->dev.absbit);
-
- for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
- set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
- gf2k->dev.absmin[ABS_HAT0X + i] = -1;
- gf2k->dev.absmax[ABS_HAT0X + i] = 1;
- }
-
- for (i = 0; i < gf2k_joys[gf2k->id]; i++)
- set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
-
- for (i = 0; i < gf2k_pads[gf2k->id]; i++)
- set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
-
- gf2k_read_packet(gameport, gf2k->length, data);
- gf2k_read(gf2k, data);
-
- for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
- gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
- gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
- gf2k->dev.absmin[gf2k_abs[i]] = 32;
- gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
- gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
- }
-
- input_register_device(&gf2k->dev);
- printk(KERN_INFO "input%d: %s on gameport%d.0\n",
- gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(gf2k);
-}
-
-static void gf2k_disconnect(struct gameport *gameport)
-{
- struct gf2k *gf2k = gameport->private;
- input_unregister_device(&gf2k->dev);
- gameport_close(gameport);
- kfree(gf2k);
-}
-
-static struct gameport_dev gf2k_dev = {
- connect: gf2k_connect,
- disconnect: gf2k_disconnect,
-};
-
-int __init gf2k_init(void)
-{
- gameport_register_device(&gf2k_dev);
- return 0;
-}
-
-void __exit gf2k_exit(void)
-{
- gameport_unregister_device(&gf2k_dev);
-}
-
-module_init(gf2k_init);
-module_exit(gf2k_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define GRIP_MODE_GPP 1
-#define GRIP_MODE_BD 2
-#define GRIP_MODE_XT 3
-#define GRIP_MODE_DC 4
-
-#define GRIP_LENGTH_GPP 24
-#define GRIP_STROBE_GPP 200 /* 200 us */
-#define GRIP_LENGTH_XT 4
-#define GRIP_STROBE_XT 64 /* 64 us */
-#define GRIP_MAX_CHUNKS_XT 10
-#define GRIP_MAX_BITS_XT 30
-
-#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
-
-struct grip {
- struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev[2];
- unsigned char mode[2];
- int used;
- int reads;
- int bads;
-};
-
-static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
-static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
-static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
-static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
-
-static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
-static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
-static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-
-static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
- "Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
-static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
-static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
-static char grip_anx[] = { 0, 0, 3, 5, 5 };
-static char grip_cen[] = { 0, 0, 2, 2, 4 };
-
-/*
- * grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
- */
-
-static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v;
- unsigned int t;
- int i;
-
- int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
-
- data[0] = 0;
- t = strobe;
- i = 0;
-
- __save_flags(flags);
- __cli();
-
- v = gameport_read(gameport) >> shift;
-
- do {
- t--;
- u = v; v = (gameport_read(gameport) >> shift) & 3;
- if (~v & u & 1) {
- data[0] |= (v >> 1) << i++;
- t = strobe;
- }
- } while (i < GRIP_LENGTH_GPP && t > 0);
-
- __restore_flags(flags);
-
- if (i < GRIP_LENGTH_GPP) return -1;
-
- for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
- data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
-
- return -(i == GRIP_LENGTH_GPP);
-}
-
-/*
- * grip_xt_read_packet() reads a Gravis Xterminator packet.
- */
-
-static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
-{
- unsigned int i, j, buf, crc;
- unsigned char u, v, w;
- unsigned long flags;
- unsigned int t;
- char status;
-
- int strobe = gameport_time(gameport, GRIP_STROBE_XT);
-
- data[0] = data[1] = data[2] = data[3] = 0;
- status = buf = i = j = 0;
- t = strobe;
-
- __save_flags(flags);
- __cli();
-
- v = w = (gameport_read(gameport) >> shift) & 3;
-
- do {
- t--;
- u = (gameport_read(gameport) >> shift) & 3;
-
- if (u ^ v) {
-
- if ((u ^ v) & 1) {
- buf = (buf << 1) | (u >> 1);
- t = strobe;
- i++;
- } else
-
- if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
- 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++;
- }
- t = strobe;
- buf = 0;
- i = 0;
- }
- w = v;
- v = u;
- }
-
- } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
-
- __restore_flags(flags);
-
- return -(status != 0xf);
-}
-
-/*
- * grip_timer() repeatedly polls the joysticks and generates events.
- */
-
-static void grip_timer(unsigned long private)
-{
- struct grip *grip = (void*) private;
- unsigned int data[GRIP_LENGTH_XT];
- struct input_dev *dev;
- int i, j;
-
- for (i = 0; i < 2; i++) {
-
- dev = grip->dev + i;
- grip->reads++;
-
- switch (grip->mode[i]) {
-
- case GRIP_MODE_GPP:
-
- if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
- grip->bads++;
- break;
- }
-
- input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
- input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
-
- for (j = 0; j < 12; j++)
- if (grip_btn_gpp[j])
- input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
-
- break;
-
- case GRIP_MODE_BD:
-
- if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
- grip->bads++;
- break;
- }
-
- input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
- input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
- input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
- input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
- input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
-
- for (j = 0; j < 5; j++)
- input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
-
- break;
-
- case GRIP_MODE_XT:
-
- if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
- grip->bads++;
- break;
- }
-
- input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
- input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
- input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f);
- input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f);
- input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
- input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
- input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
- input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
- input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
-
- for (j = 0; j < 11; j++)
- input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
- break;
-
- case GRIP_MODE_DC:
-
- if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
- grip->bads++;
- break;
- }
-
- input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
- input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f);
- input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f);
- input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f);
- input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
-
- input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
- input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
-
- for (j = 0; j < 9; j++)
- input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
- break;
-
-
- }
- }
-
- mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
-}
-
-static int grip_open(struct input_dev *dev)
-{
- struct grip *grip = dev->private;
- if (!grip->used++)
- mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
- return 0;
-}
-
-static void grip_close(struct input_dev *dev)
-{
- struct grip *grip = dev->private;
- if (!--grip->used)
- del_timer(&grip->timer);
-}
-
-static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct grip *grip;
- unsigned int data[GRIP_LENGTH_XT];
- int i, j, t;
-
- if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
- return;
- memset(grip, 0, sizeof(struct grip));
-
- gameport->private = grip;
-
- grip->gameport = gameport;
- init_timer(&grip->timer);
- grip->timer.data = (long) grip;
- grip->timer.function = grip_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- for (i = 0; i < 2; i++) {
- if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
- grip->mode[i] = GRIP_MODE_GPP;
- continue;
- }
- if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
- if (!(data[3] & 7)) {
- grip->mode[i] = GRIP_MODE_BD;
- continue;
- }
- if (!(data[2] & 0xf0)) {
- grip->mode[i] = GRIP_MODE_XT;
- continue;
- }
- grip->mode[i] = GRIP_MODE_DC;
- continue;
- }
- }
-
- if (!grip->mode[0] && !grip->mode[1])
- goto fail2;
-
- for (i = 0; i < 2; i++)
- if (grip->mode[i]) {
-
- grip->dev[i].private = grip;
-
- grip->dev[i].open = grip_open;
- grip->dev[i].close = grip_close;
-
- grip->dev[i].name = grip_name[grip->mode[i]];
- grip->dev[i].idbus = BUS_GAMEPORT;
- grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
- grip->dev[i].idproduct = grip->mode[i];
- grip->dev[i].idversion = 0x0100;
-
- grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
-
- set_bit(t, grip->dev[i].absbit);
-
- if (j < grip_cen[grip->mode[i]]) {
- grip->dev[i].absmin[t] = 14;
- grip->dev[i].absmax[t] = 52;
- grip->dev[i].absfuzz[t] = 1;
- grip->dev[i].absflat[t] = 2;
- continue;
- }
-
- if (j < grip_anx[grip->mode[i]]) {
- grip->dev[i].absmin[t] = 3;
- grip->dev[i].absmax[t] = 57;
- grip->dev[i].absfuzz[t] = 1;
- continue;
- }
-
- grip->dev[i].absmin[t] = -1;
- grip->dev[i].absmax[t] = 1;
- }
-
- for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
- if (t > 0)
- set_bit(t, grip->dev[i].keybit);
-
- input_register_device(grip->dev + i);
-
- printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
- grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
- }
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(grip);
-}
-
-static void grip_disconnect(struct gameport *gameport)
-{
- int i;
-
- struct grip *grip = gameport->private;
- for (i = 0; i < 2; i++)
- if (grip->mode[i])
- input_unregister_device(grip->dev + i);
- gameport_close(gameport);
- kfree(grip);
-}
-
-static struct gameport_dev grip_dev = {
- connect: grip_connect,
- disconnect: grip_disconnect,
-};
-
-int __init grip_init(void)
-{
- gameport_register_device(&grip_dev);
- return 0;
-}
-
-void __exit grip_exit(void)
-{
- gameport_unregister_device(&grip_dev);
-}
-
-module_init(grip_init);
-module_exit(grip_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
- * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
- *
- * USB/RS232 I-Force joysticks and wheels.
- *
- * 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 <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/spinlock.h>
-#include <linux/usb.h>
-#include <linux/serio.h>
-#include <linux/config.h>
-
-/* FF: This module provides arbitrary resource management routines.
- * I use it to manage the device's memory.
- * Despite the name of this module, I am *not* going to access the ioports.
- */
-#include <linux/ioport.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
-MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
-MODULE_LICENSE("GPL");
-
-#define IFORCE_MAX_LENGTH 16
-
-#if defined(CONFIG_INPUT_IFORCE_232) || defined(CONFIG_INPUT_IFORCE_232_MODULE)
-#define IFORCE_232 1
-#endif
-#if defined(CONFIG_INPUT_IFORCE_USB) || defined(CONFIG_INPUT_IFORCE_USB_MODULE)
-#define IFORCE_USB 2
-#endif
-
-#define FF_EFFECTS_MAX 32
-
-/* Each force feedback effect is made of one core effect, which can be
- * associated to at most to effect modifiers
- */
-#define FF_MOD1_IS_USED 0
-#define FF_MOD2_IS_USED 1
-#define FF_CORE_IS_USED 2
-#define FF_CORE_IS_PLAYED 3
-#define FF_MODCORE_MAX 3
-
-struct iforce_core_effect {
- /* Information about where modifiers are stored in the device's memory */
- struct resource mod1_chunk;
- struct resource mod2_chunk;
- unsigned long flags[NBITS(FF_MODCORE_MAX)];
-};
-
-#define FF_CMD_EFFECT 0x010e
-#define FF_CMD_SHAPE 0x0208
-#define FF_CMD_MAGNITUDE 0x0303
-#define FF_CMD_PERIOD 0x0407
-#define FF_CMD_INTERACT 0x050a
-
-#define FF_CMD_AUTOCENTER 0x4002
-#define FF_CMD_PLAY 0x4103
-#define FF_CMD_ENABLE 0x4201
-#define FF_CMD_GAIN 0x4301
-
-#define FF_CMD_QUERY 0xff01
-
-static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
- BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
-static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
- BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
-static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
-static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
- FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
-
-static struct iforce_device {
- u16 idvendor;
- u16 idproduct;
- char *name;
- signed short *btn;
- signed short *abs;
- signed short *ff;
-} iforce_device[] = {
- { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce },
- { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce },
- { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick, ff_iforce },
- { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce },
- { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce },
- { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
-};
-
-struct iforce {
- struct input_dev dev; /* Input device interface */
- struct iforce_device *type;
- char name[64];
- int open;
- int bus;
-
- unsigned char data[IFORCE_MAX_LENGTH];
- unsigned char edata[IFORCE_MAX_LENGTH];
- u16 ecmd;
- u16 expect_packet;
-
-#ifdef IFORCE_232
- struct serio *serio; /* RS232 transfer */
- int idx, pkt, len, id;
- unsigned char csum;
-#endif
-#ifdef IFORCE_USB
- struct usb_device *usbdev; /* USB transfer */
- struct urb *irq, *out, *ctrl;
- struct usb_ctrlrequest dr;
-#endif
- /* Force Feedback */
- wait_queue_head_t wait;
- struct resource device_memory;
- struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
-};
-
-static struct {
- __s32 x;
- __s32 y;
-} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-/* Get hi and low bytes of a 16-bits int */
-#define HI(a) ((unsigned char)((a) >> 8))
-#define LO(a) ((unsigned char)((a) & 0xff))
-
-/* Encode a time value */
-#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
-
-static void dump_packet(char *msg, u16 cmd, unsigned char *data)
-{
- int i;
-
- printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
- for (i = 0; i < LO(cmd); i++)
- printk("%02x ", data[i]);
- printk(")\n");
-}
-
-/*
- * Send a packet of bytes to the device
- */
-static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
-{
- switch (iforce->bus) {
-
-#ifdef IFORCE_232
- case IFORCE_232: {
-
- int i;
- unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
-
- serio_write(iforce->serio, 0x2b);
- serio_write(iforce->serio, HI(cmd));
- serio_write(iforce->serio, LO(cmd));
-
- for (i = 0; i < LO(cmd); i++) {
- serio_write(iforce->serio, data[i]);
- csum = csum ^ data[i];
- }
-
- serio_write(iforce->serio, csum);
- return;
- }
-#endif
-#ifdef IFORCE_USB
- case IFORCE_USB: {
-
- DECLARE_WAITQUEUE(wait, current);
- int timeout = HZ; /* 1 second */
-
- memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
- ((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
- iforce->out->transfer_buffer_length = LO(cmd) + 2;
- iforce->out->dev = iforce->usbdev;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&iforce->wait, &wait);
-
- if (usb_submit_urb(iforce->out)) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
- return;
- }
-
- while (timeout && iforce->out->status == -EINPROGRESS)
- timeout = schedule_timeout(timeout);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
-
- if (!timeout)
- usb_unlink_urb(iforce->out);
-
- return;
- }
-#endif
- }
-}
-
-static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
-{
- struct input_dev *dev = &iforce->dev;
- int i;
-
-#ifdef IFORCE_232
- if (HI(iforce->expect_packet) == HI(cmd)) {
- iforce->expect_packet = 0;
- iforce->ecmd = cmd;
- memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
- }
-#endif
-
- if (!iforce->type)
- return;
-
- switch (HI(cmd)) {
-
- case 0x01: /* joystick position data */
- case 0x03: /* wheel position data */
-
- if (HI(cmd) == 1) {
- input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
- input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
- } else {
- input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
- input_report_abs(dev, ABS_GAS, 255 - data[2]);
- input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
- }
-
- input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
- input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
-
- for (i = 0; iforce->type->btn[i] >= 0; i++)
- input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
-
- break;
-
- case 0x02: /* status report */
-
- input_report_key(dev, BTN_DEAD, data[0] & 0x02);
- break;
- }
-}
-
-static int get_id_packet(struct iforce *iforce, char *packet)
-{
- DECLARE_WAITQUEUE(wait, current);
- int timeout = HZ; /* 1 second */
-
- switch (iforce->bus) {
-
-#ifdef IFORCE_USB
- case IFORCE_USB:
-
- iforce->dr.bRequest = packet[0];
- iforce->ctrl->dev = iforce->usbdev;
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&iforce->wait, &wait);
-
- if (usb_submit_urb(iforce->ctrl)) {
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
- return -1;
- }
-
- while (timeout && iforce->ctrl->status == -EINPROGRESS)
- timeout = schedule_timeout(timeout);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
-
- if (!timeout) {
- usb_unlink_urb(iforce->ctrl);
- return -1;
- }
-
- break;
-#endif
-#ifdef IFORCE_232
- case IFORCE_232:
-
- iforce->expect_packet = FF_CMD_QUERY;
- send_packet(iforce, FF_CMD_QUERY, packet);
-
- set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&iforce->wait, &wait);
-
- while (timeout && iforce->expect_packet)
- timeout = schedule_timeout(timeout);
-
- set_current_state(TASK_RUNNING);
- remove_wait_queue(&iforce->wait, &wait);
-
- if (!timeout) {
- iforce->expect_packet = 0;
- return -1;
- }
-
- break;
-#endif
- }
-
- return -(iforce->edata[0] != packet[0]);
-}
-
-static int iforce_open(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- switch (iforce->bus) {
-#ifdef IFORCE_USB
- case IFORCE_USB:
- if (iforce->open++)
- break;
- iforce->irq->dev = iforce->usbdev;
- if (usb_submit_urb(iforce->irq))
- return -EIO;
- break;
-#endif
- }
- return 0;
-}
-
-static void iforce_close(struct input_dev *dev)
-{
- struct iforce *iforce = dev->private;
-
- switch (iforce->bus) {
-#ifdef IFORCE_USB
- case IFORCE_USB:
- if (!--iforce->open)
- usb_unlink_urb(iforce->irq);
- break;
-#endif
- }
-}
-
-/*
- * Start or stop playing an effect
- */
-
-static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
-{
- struct iforce* iforce = (struct iforce*)(dev->private);
- unsigned char data[3];
-
- printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
-
- if (type != EV_FF)
- return -1;
-
- switch (code) {
-
- case FF_GAIN:
-
- data[0] = value >> 9;
- send_packet(iforce, FF_CMD_GAIN, data);
-
- return 0;
-
- case FF_AUTOCENTER:
-
- data[0] = 0x03;
- data[1] = value >> 9;
- send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
- data[0] = 0x04;
- data[1] = 0x01;
- send_packet(iforce, FF_CMD_AUTOCENTER, data);
-
- return 0;
-
- default: /* Play an effect */
-
- if (code >= iforce->dev.ff_effects_max)
- return -1;
-
- data[0] = LO(code);
- data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
- data[2] = LO(value);
- send_packet(iforce, FF_CMD_PLAY, data);
-
- return 0;
- }
-
- return -1;
-}
-
-/*
- * Set the magnitude of a constant force effect
- * Return error code
- *
- * Note: caller must ensure exclusive access to device
- */
-
-static int make_magnitude_modifier(struct iforce* iforce,
- struct resource* mod_chunk, __s16 level)
-{
- unsigned char data[3];
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
- data[2] = HI(level);
-
- send_packet(iforce, FF_CMD_MAGNITUDE, data);
-
- return 0;
-}
-
-/*
- * Upload the component of an effect dealing with the period, phase and magnitude
- */
-
-static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk,
- __s16 magnitude, __s16 offset, u16 period, u16 phase)
-{
- unsigned char data[7];
-
- period = TIME_SCALE(period);
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
-
- data[2] = HI(magnitude);
- data[3] = HI(offset);
- data[4] = HI(phase);
-
- data[5] = LO(period);
- data[6] = HI(period);
-
- send_packet(iforce, FF_CMD_PERIOD, data);
-
- return 0;
-}
-
-/*
- * Uploads the part of an effect setting the shape of the force
- */
-
-static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
- u16 attack_duration, __s16 initial_level,
- u16 fade_duration, __s16 final_level)
-{
- unsigned char data[8];
-
- attack_duration = TIME_SCALE(attack_duration);
- fade_duration = TIME_SCALE(fade_duration);
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
-
- data[2] = LO(attack_duration);
- data[3] = HI(attack_duration);
- data[4] = HI(initial_level);
-
- data[5] = LO(fade_duration);
- data[6] = HI(fade_duration);
- data[7] = HI(final_level);
-
- send_packet(iforce, FF_CMD_SHAPE, data);
-
- return 0;
-}
-
-/*
- * Component of spring, friction, inertia... effects
- */
-
-static int make_interactive_modifier(struct iforce* iforce,
- struct resource* mod_chunk,
- __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
-{
- unsigned char data[10];
-
- if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
- iforce->device_memory.start, iforce->device_memory.end, 2L,
- NULL, NULL)) {
- return -ENOMEM;
- }
-
- data[0] = LO(mod_chunk->start);
- data[1] = HI(mod_chunk->start);
-
- data[2] = HI(rk);
- data[3] = HI(lk);
-
- data[4] = LO(center);
- data[5] = HI(center);
-
- data[6] = LO(db);
- data[7] = HI(db);
-
- data[8] = HI(rsat);
- data[9] = HI(lsat);
-
- send_packet(iforce, FF_CMD_INTERACT, data);
-
- return 0;
-}
-
-static unsigned char find_button(struct iforce *iforce, signed short button)
-{
- int i;
- for (i = 1; iforce->type->btn[i] >= 0; i++)
- if (iforce->type->btn[i] == button)
- return i + 1;
- return 0;
-}
-
-/*
- * Send the part common to all effects to the device
- */
-
-static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
- u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,
- u16 interval, u16 direction)
-{
- unsigned char data[14];
-
- duration = TIME_SCALE(duration);
- delay = TIME_SCALE(delay);
- interval = TIME_SCALE(interval);
-
- data[0] = LO(id);
- data[1] = effect_type;
- data[2] = LO(axes) | find_button(iforce, button);
-
- data[3] = LO(duration);
- data[4] = HI(duration);
-
- data[5] = HI(direction);
-
- data[6] = LO(interval);
- data[7] = HI(interval);
-
- data[8] = LO(mod_id1);
- data[9] = HI(mod_id1);
- data[10] = LO(mod_id2);
- data[11] = HI(mod_id2);
-
- data[12] = LO(delay);
- data[13] = HI(delay);
-
- send_packet(iforce, FF_CMD_EFFECT, data);
-
- return 0;
-}
-
-/*
- * Upload a periodic effect to the device
- */
-
-static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
-{
- u8 wave_code;
- int core_id = effect->id;
- struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
- struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
- struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
- int err = 0;
-
- err = make_period_modifier(iforce, mod1_chunk,
- effect->u.periodic.magnitude, effect->u.periodic.offset,
- effect->u.periodic.period, effect->u.periodic.phase);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- err = make_shape_modifier(iforce, mod2_chunk,
- effect->u.periodic.shape.attack_length,
- effect->u.periodic.shape.attack_level,
- effect->u.periodic.shape.fade_length,
- effect->u.periodic.shape.fade_level);
- if (err) return err;
- set_bit(FF_MOD2_IS_USED, core_effect->flags);
-
- switch (effect->u.periodic.waveform) {
- case FF_SQUARE: wave_code = 0x20; break;
- case FF_TRIANGLE: wave_code = 0x21; break;
- case FF_SINE: wave_code = 0x22; break;
- case FF_SAW_UP: wave_code = 0x23; break;
- case FF_SAW_DOWN: wave_code = 0x24; break;
- default: wave_code = 0x20; break;
- }
-
- err = make_core(iforce, effect->id,
- mod1_chunk->start,
- mod2_chunk->start,
- wave_code,
- 0x20,
- effect->replay.length,
- effect->replay.delay,
- effect->trigger.button,
- effect->trigger.interval,
- effect->u.periodic.direction);
-
- return err;
-}
-
-/*
- * Upload a constant force effect
- */
-static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
-{
- int core_id = effect->id;
- struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
- struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
- struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
- int err = 0;
-
- printk(KERN_DEBUG "iforce.c: make constant effect\n");
-
- err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- err = make_shape_modifier(iforce, mod2_chunk,
- effect->u.constant.shape.attack_length,
- effect->u.constant.shape.attack_level,
- effect->u.constant.shape.fade_length,
- effect->u.constant.shape.fade_level);
- if (err) return err;
- set_bit(FF_MOD2_IS_USED, core_effect->flags);
-
- err = make_core(iforce, effect->id,
- mod1_chunk->start,
- mod2_chunk->start,
- 0x00,
- 0x20,
- effect->replay.length,
- effect->replay.delay,
- effect->trigger.button,
- effect->trigger.interval,
- effect->u.constant.direction);
-
- return err;
-}
-
-/*
- * Upload an interactive effect. Those are for example friction, inertia, springs...
- */
-static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
-{
- int core_id = effect->id;
- struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
- struct resource* mod_chunk = &(core_effect->mod1_chunk);
- u8 type, axes;
- u16 mod1, mod2, direction;
- int err = 0;
-
- printk(KERN_DEBUG "iforce.c: make interactive effect\n");
-
- switch (effect->type) {
- case FF_SPRING: type = 0x40; break;
- case FF_FRICTION: type = 0x41; break;
- default: return -1;
- }
-
- err = make_interactive_modifier(iforce, mod_chunk,
- effect->u.interactive.right_saturation,
- effect->u.interactive.left_saturation,
- effect->u.interactive.right_coeff,
- effect->u.interactive.left_coeff,
- effect->u.interactive.deadband,
- effect->u.interactive.center);
- if (err) return err;
- set_bit(FF_MOD1_IS_USED, core_effect->flags);
-
- switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
- test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
- (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
-
- case 0: /* Only one axis, choose orientation */
- mod1 = mod_chunk->start;
- mod2 = 0xffff;
- direction = effect->u.interactive.direction;
- axes = 0x20;
- break;
-
- case 1: /* Only X axis */
- mod1 = mod_chunk->start;
- mod2 = 0xffff;
- direction = 0x5a00;
- axes = 0x40;
- break;
-
- case 2: /* Only Y axis */
- mod1 = 0xffff;
- mod2 = mod_chunk->start;
- direction = 0xb400;
- axes = 0x80;
- break;
-
- case 3: /* Both X and Y axes */
- /* TODO: same setting for both axes is not mandatory */
- mod1 = mod_chunk->start;
- mod2 = mod_chunk->start;
- direction = 0x6000;
- axes = 0xc0;
- break;
-
- default:
- return -1;
- }
-
- err = make_core(iforce, effect->id,
- mod1, mod2,
- type, axes,
- effect->replay.length, effect->replay.delay,
- effect->trigger.button, effect->trigger.interval,
- direction);
-
- return err;
-}
-
-/*
- * Function called when an ioctl is performed on the event dev entry.
- * It uploads an effect to the device
- */
-static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
-{
- struct iforce* iforce = (struct iforce*)(dev->private);
- int id;
-
- printk(KERN_DEBUG "iforce.c: upload effect\n");
-
-/*
- * Get a free id
- */
-
- for (id=0; id < FF_EFFECTS_MAX; ++id)
- if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break;
-
- if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max)
- return -ENOMEM;
-
- effect->id = id;
- set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
-
-/*
- * Upload the effect
- */
-
- switch (effect->type) {
-
- case FF_PERIODIC:
- return iforce_upload_periodic(iforce, effect);
-
- case FF_CONSTANT:
- return iforce_upload_constant(iforce, effect);
-
- case FF_SPRING:
- case FF_FRICTION:
- return iforce_upload_interactive(iforce, effect);
-
- default:
- return -1;
- }
-}
-
-/*
- * Erases an effect: it frees the effect id and mark as unused the memory
- * allocated for the parameters
- */
-static int iforce_erase_effect(struct input_dev *dev, int effect_id)
-{
- struct iforce* iforce = (struct iforce*)(dev->private);
- int err = 0;
- struct iforce_core_effect* core_effect;
-
- printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
-
- if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
- return -EINVAL;
-
- core_effect = iforce->core_effects + effect_id;
-
- if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
- err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
-
- if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
- err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
-
- /*TODO: remember to change that if more FF_MOD* bits are added */
- core_effect->flags[0] = 0;
-
- return err;
-}
-static int iforce_init_device(struct iforce *iforce)
-{
- unsigned char c[] = "CEOV";
- int i;
-
- init_waitqueue_head(&iforce->wait);
- iforce->dev.ff_effects_max = 10;
-
-/*
- * Input device fields.
- */
-
- iforce->dev.idbus = BUS_USB;
- iforce->dev.private = iforce;
- iforce->dev.name = iforce->name;
- iforce->dev.open = iforce_open;
- iforce->dev.close = iforce_close;
- iforce->dev.event = iforce_input_event;
- iforce->dev.upload_effect = iforce_upload_effect;
- iforce->dev.erase_effect = iforce_erase_effect;
-
-/*
- * On-device memory allocation.
- */
-
- iforce->device_memory.name = "I-Force device effect memory";
- iforce->device_memory.start = 0;
- iforce->device_memory.end = 200;
- iforce->device_memory.flags = IORESOURCE_MEM;
- iforce->device_memory.parent = NULL;
- iforce->device_memory.child = NULL;
- iforce->device_memory.sibling = NULL;
-
-/*
- * Wait until device ready - until it sends its first response.
- */
-
- for (i = 0; i < 20; i++)
- if (!get_id_packet(iforce, "O"))
- break;
-
- if (i == 20) { /* 5 seconds */
- printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
- iforce_close(&iforce->dev);
- return -1;
- }
-
-/*
- * Get device info.
- */
-
- if (!get_id_packet(iforce, "M"))
- iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "P"))
- iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "B"))
- iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
- if (!get_id_packet(iforce, "N"))
- iforce->dev.ff_effects_max = iforce->edata[1];
-
-/*
- * Display additional info.
- */
-
- for (i = 0; c[i]; i++)
- if (!get_id_packet(iforce, c + i))
- dump_packet("info", iforce->ecmd, iforce->edata);
-
-/*
- * Disable spring, enable force feedback.
- * FIXME: We should use iforce_set_autocenter() et al here.
- */
-
- send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
- send_packet(iforce, FF_CMD_ENABLE, "\004");
-
-/*
- * Find appropriate device entry
- */
-
- for (i = 0; iforce_device[i].idvendor; i++)
- if (iforce_device[i].idvendor == iforce->dev.idvendor &&
- iforce_device[i].idproduct == iforce->dev.idproduct)
- break;
-
- iforce->type = iforce_device + i;
-
- sprintf(iforce->name, iforce->type->name,
- iforce->dev.idproduct, iforce->dev.idvendor);
-
-/*
- * Set input device bitfields and ranges.
- */
-
- iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
-
- for (i = 0; iforce->type->btn[i] >= 0; i++) {
- signed short t = iforce->type->btn[i];
- set_bit(t, iforce->dev.keybit);
- if (t != BTN_DEAD)
- set_bit(FF_BTN(t), iforce->dev.ffbit);
- }
-
- for (i = 0; iforce->type->abs[i] >= 0; i++) {
-
- signed short t = iforce->type->abs[i];
- set_bit(t, iforce->dev.absbit);
-
- switch (t) {
-
- case ABS_X:
- case ABS_Y:
- case ABS_WHEEL:
-
- iforce->dev.absmax[t] = 1920;
- iforce->dev.absmin[t] = -1920;
- iforce->dev.absflat[t] = 128;
- iforce->dev.absfuzz[t] = 16;
-
- set_bit(FF_ABS(t), iforce->dev.ffbit);
- break;
-
- case ABS_THROTTLE:
- case ABS_GAS:
- case ABS_BRAKE:
-
- iforce->dev.absmax[t] = 255;
- iforce->dev.absmin[t] = 0;
- break;
-
- case ABS_HAT0X:
- case ABS_HAT0Y:
- iforce->dev.absmax[t] = 1;
- iforce->dev.absmin[t] = -1;
- break;
- }
- }
-
- for (i = 0; iforce->type->ff[i] >= 0; i++)
- set_bit(iforce->type->ff[i], iforce->dev.ffbit);
-
-/*
- * Register input device.
- */
-
- input_register_device(&iforce->dev);
-
- return 0;
-}
-
-#ifdef IFORCE_USB
-
-static void iforce_usb_irq(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce_process_packet(iforce,
- (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
-}
-
-static void iforce_usb_out(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
-}
-
-static void iforce_usb_ctrl(struct urb *urb)
-{
- struct iforce *iforce = urb->context;
- if (urb->status) return;
- iforce->ecmd = 0xff00 | urb->actual_length;
- if (waitqueue_active(&iforce->wait))
- wake_up(&iforce->wait);
-}
-
-static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
- const struct usb_device_id *id)
-{
- struct usb_endpoint_descriptor *epirq, *epout;
- struct iforce *iforce;
-
- epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
- epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
-
- if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
- memset(iforce, 0, sizeof(struct iforce));
-
- iforce->irq = usb_alloc_urb(0);
- if (!iforce->irq) {
- kfree(iforce);
- return NULL;
- }
- iforce->out = usb_alloc_urb(0);
- if (!iforce->out) {
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
- iforce->ctrl = usb_alloc_urb(0);
- if (!iforce->ctrl) {
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
-
- iforce->bus = IFORCE_USB;
- iforce->usbdev = dev;
-
- iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
- iforce->dr.wIndex = 0;
- iforce->dr.wLength = 16;
-
- FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
- iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
-
- FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
- iforce + 1, 32, iforce_usb_out, iforce);
-
- FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
- (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
-
- if (iforce_init_device(iforce)) {
- usb_free_urb(iforce->ctrl);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
- return NULL;
- }
-
- printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
- iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
- iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
-
- return iforce;
-}
-
-static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
-{
- struct iforce *iforce = ptr;
- usb_unlink_urb(iforce->irq);
- input_unregister_device(&iforce->dev);
- usb_free_urb(iforce->ctrl);
- usb_free_urb(iforce->out);
- usb_free_urb(iforce->irq);
- kfree(iforce);
-}
-
-static struct usb_device_id iforce_usb_ids [] = {
- { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */
- { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */
- { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */
- { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */
- { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
- { } /* Terminating entry */
-};
-
-MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
-
-static struct usb_driver iforce_usb_driver = {
- name: "iforce",
- probe: iforce_usb_probe,
- disconnect: iforce_usb_disconnect,
- id_table: iforce_usb_ids,
-};
-
-#endif
-
-#ifdef IFORCE_232
-
-static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct iforce* iforce = serio->private;
-
- if (!iforce->pkt) {
- if (data != 0x2b) {
- return;
- }
- iforce->pkt = 1;
- return;
- }
-
- if (!iforce->id) {
- if (data > 3 && data != 0xff) {
- iforce->pkt = 0;
- return;
- }
- iforce->id = data;
- return;
- }
-
- if (!iforce->len) {
- if (data > IFORCE_MAX_LENGTH) {
- iforce->pkt = 0;
- iforce->id = 0;
- return;
- }
- iforce->len = data;
- return;
- }
-
- if (iforce->idx < iforce->len) {
- iforce->csum += iforce->data[iforce->idx++] = data;
- return;
- }
-
- if (iforce->idx == iforce->len) {
- iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
- iforce->pkt = 0;
- iforce->id = 0;
- iforce->len = 0;
- iforce->idx = 0;
- iforce->csum = 0;
- }
-}
-
-static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct iforce *iforce;
- if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
- return;
-
- if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
- memset(iforce, 0, sizeof(struct iforce));
-
- iforce->bus = IFORCE_232;
- iforce->serio = serio;
- serio->private = iforce;
-
- if (serio_open(serio, dev)) {
- kfree(iforce);
- return;
- }
-
- if (iforce_init_device(iforce)) {
- serio_close(serio);
- kfree(iforce);
- return;
- }
-
- printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
- iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
- iforce->device_memory.end, serio->number);
-}
-
-static void iforce_serio_disconnect(struct serio *serio)
-{
- struct iforce* iforce = serio->private;
-
- input_unregister_device(&iforce->dev);
- serio_close(serio);
- kfree(iforce);
-}
-
-static struct serio_dev iforce_serio_dev = {
- interrupt: iforce_serio_irq,
- connect: iforce_serio_connect,
- disconnect: iforce_serio_disconnect,
-};
-
-#endif
-
-static int __init iforce_init(void)
-{
-#ifdef IFORCE_USB
- usb_register(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_register_device(&iforce_serio_dev);
-#endif
- return 0;
-}
-
-static void __exit iforce_exit(void)
-{
-#ifdef IFORCE_USB
- usb_deregister(&iforce_usb_driver);
-#endif
-#ifdef IFORCE_232
- serio_unregister_device(&iforce_serio_dev);
-#endif
-}
-
-module_init(iforce_init);
-module_exit(iforce_exit);
+++ /dev/null
-/*
- * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
- *
- * Copyright (c) 2000 Vojtech Pavlik
- *
- * Based on the work of:
- * Toby Deshane
- *
- * Sponsored by SuSE
- */
-
-/*
- * InterAct digital gamepad/joystick driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define INTERACT_MAX_START 400 /* 400 us */
-#define INTERACT_MAX_STROBE 40 /* 40 us */
-#define INTERACT_MAX_LENGTH 32 /* 32 bits */
-#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
-
-#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
-#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
-
-struct interact {
- struct gameport *gameport;
- struct input_dev dev;
- struct timer_list timer;
- int used;
- int bads;
- int reads;
- unsigned char type;
- unsigned char length;
-};
-
-static short interact_abs_hhfx[] =
- { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
-static short interact_abs_pp8d[] =
- { ABS_X, ABS_Y, -1 };
-
-static short interact_btn_hhfx[] =
- { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
-static short interact_btn_pp8d[] =
- { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
-
-struct interact_type {
- int id;
- short *abs;
- short *btn;
- char *name;
- unsigned char length;
- unsigned char b8;
-};
-
-static struct interact_type interact_type[] = {
- { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 },
- { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
- { 0 }};
-
-/*
- * interact_read_packet() reads and InterAct joystick data.
- */
-
-static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
-{
- unsigned long flags;
- unsigned char u, v;
- unsigned int t, s;
- int i;
-
- i = 0;
- data[0] = data[1] = data[2] = 0;
- t = gameport_time(gameport, INTERACT_MAX_START);
- s = gameport_time(gameport, INTERACT_MAX_STROBE);
-
- __save_flags(flags);
- __cli();
- gameport_trigger(gameport);
- v = gameport_read(gameport);
-
- while (t > 0 && i < length) {
- t--;
- u = v; v = gameport_read(gameport);
- if (v & ~u & 0x40) {
- data[0] = (data[0] << 1) | ((v >> 4) & 1);
- data[1] = (data[1] << 1) | ((v >> 5) & 1);
- data[2] = (data[2] << 1) | ((v >> 7) & 1);
- i++;
- t = s;
- }
- }
-
- __restore_flags(flags);
-
- return i;
-}
-
-/*
- * interact_timer() reads and analyzes InterAct joystick data.
- */
-
-static void interact_timer(unsigned long private)
-{
- struct interact *interact = (struct interact *) private;
- struct input_dev *dev = &interact->dev;
- u32 data[3];
- int i;
-
- interact->reads++;
-
- if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
- interact->bads++;
- } else
-
- for (i = 0; i < 3; i++)
- data[i] <<= INTERACT_MAX_LENGTH - interact->length;
-
- switch (interact->type) {
-
- case INTERACT_TYPE_HHFX:
-
- for (i = 0; i < 4; i++)
- input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
-
- for (i = 0; i < 2; i++)
- input_report_abs(dev, ABS_HAT0Y - i,
- ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1));
-
- for (i = 0; i < 8; i++)
- input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
-
- for (i = 0; i < 4; i++)
- input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
-
- break;
-
- case INTERACT_TYPE_PP8D:
-
- for (i = 0; i < 2; i++)
- input_report_abs(dev, interact_abs_pp8d[i],
- ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1));
-
- for (i = 0; i < 8; i++)
- input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
-
- break;
- }
-
- mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
-
-}
-
-/*
- * interact_open() is a callback from the input open routine.
- */
-
-static int interact_open(struct input_dev *dev)
-{
- struct interact *interact = dev->private;
- if (!interact->used++)
- mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
- return 0;
-}
-
-/*
- * interact_close() is a callback from the input close routine.
- */
-
-static void interact_close(struct input_dev *dev)
-{
- struct interact *interact = dev->private;
- if (!--interact->used)
- del_timer(&interact->timer);
-}
-
-/*
- * interact_connect() probes for InterAct joysticks.
- */
-
-static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct interact *interact;
- __u32 data[3];
- int i, t;
-
- if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
- return;
- memset(interact, 0, sizeof(struct interact));
-
- gameport->private = interact;
-
- interact->gameport = gameport;
- init_timer(&interact->timer);
- interact->timer.data = (long) interact;
- interact->timer.function = interact_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
-
- if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
- goto fail2;
- }
-
- for (i = 0; interact_type[i].length; i++)
- if (interact_type[i].id == (data[2] >> 16))
- break;
-
- if (!interact_type[i].length) {
- printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
- gameport->number, i, data[0], data[1], data[2]);
- goto fail2;
- }
-
- interact->type = i;
- interact->length = interact_type[i].length;
-
- interact->dev.private = interact;
- interact->dev.open = interact_open;
- interact->dev.close = interact_close;
-
- interact->dev.name = interact_type[i].name;
- interact->dev.idbus = BUS_GAMEPORT;
- interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
- interact->dev.idproduct = interact_type[i].id;
- interact->dev.idversion = 0x0100;
-
- interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
- set_bit(t, interact->dev.absbit);
- if (i < interact_type[interact->type].b8) {
- interact->dev.absmin[t] = 0;
- interact->dev.absmax[t] = 255;
- } else {
- interact->dev.absmin[t] = -1;
- interact->dev.absmax[t] = 1;
- }
- }
-
- for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
- set_bit(t, interact->dev.keybit);
-
- input_register_device(&interact->dev);
- printk(KERN_INFO "input%d: %s on gameport%d.0\n",
- interact->dev.number, interact_type[interact->type].name, gameport->number);
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(interact);
-}
-
-static void interact_disconnect(struct gameport *gameport)
-{
- struct interact *interact = gameport->private;
- input_unregister_device(&interact->dev);
- gameport_close(gameport);
- kfree(interact);
-}
-
-static struct gameport_dev interact_dev = {
- connect: interact_connect,
- disconnect: interact_disconnect,
-};
-
-int __init interact_init(void)
-{
- gameport_register_device(&interact_dev);
- return 0;
-}
-
-void __exit interact_exit(void)
-{
- gameport_unregister_device(&interact_dev);
-}
-
-module_init(interact_init);
-module_exit(interact_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
- *
- * Copyright (c) 1998-2001 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * PDPI Lightning 4 gamecard driver for Linux.
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-
-#define L4_PORT 0x201
-#define L4_SELECT_ANALOG 0xa4
-#define L4_SELECT_DIGITAL 0xa5
-#define L4_SELECT_SECONDARY 0xa6
-#define L4_CMD_ID 0x80
-#define L4_CMD_GETCAL 0x92
-#define L4_CMD_SETCAL 0x93
-#define L4_ID 0x04
-#define L4_BUSY 0x01
-#define L4_TIMEOUT 80 /* 80 us */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-
-struct l4 {
- struct gameport gameport;
- unsigned char port;
-} *l4_port[8];
-
-/*
- * l4_wait_ready() waits for the L4 to become ready.
- */
-
-static int l4_wait_ready(void)
-{
- unsigned int t;
- t = L4_TIMEOUT;
- while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
- return -(t<=0);
-}
-
-/*
- * l4_cooked_read() reads data from the Lightning 4.
- */
-
-static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct l4 *l4 = gameport->private;
- unsigned char status;
- int i, result = -1;
-
- outb(L4_SELECT_ANALOG, L4_PORT);
- outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
-
- if (inb(L4_PORT) & L4_BUSY) goto fail;
- outb(l4->port & 3, L4_PORT);
-
- if (l4_wait_ready()) goto fail;
- status = inb(L4_PORT);
-
- for (i = 0; i < 4; i++)
- if (status & (1 << i)) {
- if (l4_wait_ready()) goto fail;
- axes[i] = inb(L4_PORT);
- if (axes[i] > 252) axes[i] = -1;
- }
-
- if (status & 0x10) {
- if (l4_wait_ready()) goto fail;
- *buttons = inb(L4_PORT) & 0x0f;
- }
-
- result = 0;
-
-fail: outb(L4_SELECT_ANALOG, L4_PORT);
- return result;
-}
-
-static int l4_open(struct gameport *gameport, int mode)
-{
- struct l4 *l4 = gameport->private;
- if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
- return -1;
- outb(L4_SELECT_ANALOG, L4_PORT);
- return 0;
-}
-
-/*
- * l4_getcal() reads the L4 with calibration values.
- */
-
-static int l4_getcal(int port, int *cal)
-{
- int i, result = -1;
-
- outb(L4_SELECT_ANALOG, L4_PORT);
- outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
-
- if (inb(L4_PORT) & L4_BUSY) goto fail;
- outb(L4_CMD_GETCAL, L4_PORT);
-
- if (l4_wait_ready()) goto fail;
- if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
-
- if (l4_wait_ready()) goto fail;
- outb(port & 3, L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (l4_wait_ready()) goto fail;
- cal[i] = inb(L4_PORT);
- }
-
- result = 0;
-
-fail: outb(L4_SELECT_ANALOG, L4_PORT);
- return result;
-}
-
-/*
- * l4_setcal() programs the L4 with calibration values.
- */
-
-static int l4_setcal(int port, int *cal)
-{
- int i, result = -1;
-
- outb(L4_SELECT_ANALOG, L4_PORT);
- outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
-
- if (inb(L4_PORT) & L4_BUSY) goto fail;
- outb(L4_CMD_SETCAL, L4_PORT);
-
- if (l4_wait_ready()) goto fail;
- if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
-
- if (l4_wait_ready()) goto fail;
- outb(port & 3, L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (l4_wait_ready()) goto fail;
- outb(cal[i], L4_PORT);
- }
-
- result = 0;
-
-fail: outb(L4_SELECT_ANALOG, L4_PORT);
- return result;
-}
-
-/*
- * l4_calibrate() calibrates the L4 for the attached device, so
- * that the device's resistance fits into the L4's 8-bit range.
- */
-
-static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
-{
- int i, t;
- int cal[4];
- struct l4 *l4 = gameport->private;
-
- if (l4_getcal(l4->port, cal))
- return -1;
-
- for (i = 0; i < 4; i++) {
- t = (max[i] * cal[i]) / 200;
- t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
- axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
- axes[i] = (axes[i] > 252) ? 252 : axes[i];
- cal[i] = t;
- }
-
- if (l4_setcal(l4->port, cal))
- return -1;
-
- return 0;
-}
-
-int __init l4_init(void)
-{
- int cal[4] = {255,255,255,255};
- int i, j, rev, cards = 0;
- struct gameport *gameport;
- struct l4 *l4;
-
- if (!request_region(L4_PORT, 1, "lightning"))
- return -1;
-
- for (i = 0; i < 2; i++) {
-
- outb(L4_SELECT_ANALOG, L4_PORT);
- outb(L4_SELECT_DIGITAL + i, L4_PORT);
-
- if (inb(L4_PORT) & L4_BUSY) continue;
- outb(L4_CMD_ID, L4_PORT);
-
- if (l4_wait_ready()) continue;
- if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
-
- if (l4_wait_ready()) continue;
- if (inb(L4_PORT) != L4_ID) continue;
-
- if (l4_wait_ready()) continue;
- rev = inb(L4_PORT);
-
- if (!rev) continue;
-
- if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
- printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
- continue;
- }
- memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
-
- for (j = 0; j < 4; j++) {
-
- l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
- l4->port = i * 4 + j;
-
- gameport = &l4->gameport;
- gameport->private = l4;
- gameport->open = l4_open;
- gameport->cooked_read = l4_cooked_read;
- gameport->calibrate = l4_calibrate;
-
- if (!i && !j)
- gameport->io = L4_PORT;
-
- if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
- l4_setcal(l4->port, cal);
-
- gameport_register_port(gameport);
- }
-
- printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
- l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number,
- l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number,
- i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
-
- cards++;
- }
-
- outb(L4_SELECT_ANALOG, L4_PORT);
-
- if (!cards) {
- release_region(L4_PORT, 1);
- return -1;
- }
-
- return 0;
-}
-
-void __init l4_exit(void)
-{
- int i;
- int cal[4] = {59, 59, 59, 59};
-
- for (i = 0; i < 8; i++)
- if (l4_port[i]) {
- l4_setcal(l4_port[i]->port, cal);
- gameport_unregister_port(&l4_port[i]->gameport);
- }
- outb(L4_SELECT_ANALOG, L4_PORT);
- release_region(L4_PORT, 1);
-}
-
-module_init(l4_init);
-module_exit(l4_exit);
+++ /dev/null
-/*
- * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Magellan and Space Mouse 6dof controller driver for Linux
- */
-
-/*
- * 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Definitions & global arrays.
- */
-
-#define MAGELLAN_MAX_LENGTH 32
-
-static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
-static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *magellan_name = "LogiCad3D Magellan";
-
-/*
- * Per-Magellan data.
- */
-
-struct magellan {
- struct input_dev dev;
- int idx;
- unsigned char data[MAGELLAN_MAX_LENGTH];
-};
-
-/*
- * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
- * have correct upper nibbles for the lower ones, if not, the packet will
- * be thrown away. It also strips these upper halves to simplify further
- * processing.
- */
-
-static int magellan_crunch_nibbles(unsigned char *data, int count)
-{
- static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
-
- do {
- if (data[count] == nibbles[data[count] & 0xf])
- data[count] = data[count] & 0xf;
- else
- return -1;
- } while (--count);
-
- return 0;
-}
-
-static void magellan_process_packet(struct magellan* magellan)
-{
- struct input_dev *dev = &magellan->dev;
- unsigned char *data = magellan->data;
- int i, t;
-
- if (!magellan->idx) return;
-
- switch (magellan->data[0]) {
-
- case 'd': /* Axis data */
- if (magellan->idx != 25) return;
- if (magellan_crunch_nibbles(data, 24)) return;
- for (i = 0; i < 6; i++)
- input_report_abs(dev, magellan_axes[i],
- (data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
- data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768);
- break;
-
- case 'k': /* Button data */
- if (magellan->idx != 4) return;
- if (magellan_crunch_nibbles(data, 3)) return;
- t = (data[1] << 1) | (data[2] << 5) | data[3];
- for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
- break;
- }
-}
-
-static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct magellan* magellan = serio->private;
-
- if (data == '\r') {
- magellan_process_packet(magellan);
- magellan->idx = 0;
- } else {
- if (magellan->idx < MAGELLAN_MAX_LENGTH)
- magellan->data[magellan->idx++] = data;
- }
-}
-
-/*
- * magellan_disconnect() is the opposite of magellan_connect()
- */
-
-static void magellan_disconnect(struct serio *serio)
-{
- struct magellan* magellan = serio->private;
- input_unregister_device(&magellan->dev);
- serio_close(serio);
- kfree(magellan);
-}
-
-/*
- * magellan_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
- */
-
-static void magellan_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct magellan *magellan;
- int i, t;
-
- if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
- return;
-
- if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
- return;
-
- memset(magellan, 0, sizeof(struct magellan));
-
- magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = 0; i < 9; i++)
- set_bit(magellan_buttons[i], &magellan->dev.keybit);
-
- for (i = 0; i < 6; i++) {
- t = magellan_axes[i];
- set_bit(t, magellan->dev.absbit);
- magellan->dev.absmin[t] = -360;
- magellan->dev.absmax[t] = 360;
- }
-
- magellan->dev.private = magellan;
- magellan->dev.name = magellan_name;
- magellan->dev.idbus = BUS_RS232;
- magellan->dev.idvendor = SERIO_MAGELLAN;
- magellan->dev.idproduct = 0x0001;
- magellan->dev.idversion = 0x0100;
-
- serio->private = magellan;
-
- if (serio_open(serio, dev)) {
- kfree(magellan);
- return;
- }
-
- input_register_device(&magellan->dev);
-
- printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev magellan_dev = {
- interrupt: magellan_interrupt,
- connect: magellan_connect,
- disconnect: magellan_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init magellan_init(void)
-{
- serio_register_device(&magellan_dev);
- return 0;
-}
-
-void __exit magellan_exit(void)
-{
- serio_unregister_device(&magellan_dev);
-}
-
-module_init(magellan_init);
-module_exit(magellan_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
- *
- * Copyright (c) 1999-2001 Vojtech Pavlik
- * Copyright (c) 1999 Brian Gerst
- *
- * Sponsored by SuSE
- */
-
-/*
- * NS558 based standard IBM game port driver for Linux
- */
-
-/*
- * 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-
-#include <linux/module.h>
-#include <linux/ioport.h>
-#include <linux/config.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/slab.h>
-#include <linux/isapnp.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-#define NS558_ISA 1
-#define NS558_PNP 2
-
-static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
- 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
-
-struct ns558 {
- int type;
- int size;
- struct pci_dev *dev;
- struct ns558 *next;
- struct gameport gameport;
-};
-
-static struct ns558 *ns558;
-
-/*
- * ns558_isa_probe() tries to find an isa gameport at the
- * specified address, and also checks for mirrors.
- * A joystick must be attached for this to work.
- */
-
-static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
-{
- int i, j, b;
- unsigned char c, u, v;
- struct ns558 *port;
-
-/*
- * No one should be using this address.
- */
-
- if (check_region(io, 1))
- return next;
-
-/*
- * We must not be able to write arbitrary values to the port.
- * The lower two axis bits must be 1 after a write.
- */
-
- c = inb(io);
- outb(~c & ~3, io);
- if (~(u = v = inb(io)) & 3) {
- outb(c, io);
- return next;
- }
-/*
- * After a trigger, there must be at least some bits changing.
- */
-
- for (i = 0; i < 1000; i++) v &= inb(io);
-
- if (u == v) {
- outb(c, io);
- return next;
- }
- wait_ms(3);
-/*
- * After some time (4ms) the axes shouldn't change anymore.
- */
-
- u = inb(io);
- for (i = 0; i < 1000; i++)
- if ((u ^ inb(io)) & 0xf) {
- outb(c, io);
- return next;
- }
-/*
- * And now find the number of mirrors of the port.
- */
-
- for (i = 1; i < 5; i++) {
-
- if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */
- break;
-
- outb(0xff, io & (-1 << i));
- for (j = b = 0; j < 1000; j++)
- if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
- wait_ms(3);
-
- if (b > 300) /* We allow 30% difference */
- break;
- }
-
- i--;
-
- if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
- printk(KERN_ERR "ns558: Memory allocation failed.\n");
- return next;
- }
- memset(port, 0, sizeof(struct ns558));
-
- port->next = next;
- port->type = NS558_ISA;
- port->size = (1 << i);
- port->gameport.io = io & (-1 << i);
-
- request_region(port->gameport.io, (1 << i), "ns558-isa");
-
- gameport_register_port(&port->gameport);
-
- printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
- if (port->size > 1) printk(" size %d", port->size);
- printk(" speed %d kHz\n", port->gameport.speed);
-
- return port;
-}
-
-#ifdef __ISAPNP__
-
-static struct isapnp_device_id pnp_devids[] = {
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
- { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
- { 0, },
-};
-
-MODULE_DEVICE_TABLE(isapnp, pnp_devids);
-
-static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
-{
- int ioport, iolen;
- struct ns558 *port;
-
- if (dev->prepare && dev->prepare(dev) < 0)
- return next;
-
- if (!(dev->resource[0].flags & IORESOURCE_IO)) {
- printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
- return next;
- }
-
- if (dev->activate && dev->activate(dev) < 0) {
- printk(KERN_ERR "ns558: PnP resource allocation failed\n");
- return next;
- }
-
- ioport = pci_resource_start(dev, 0);
- iolen = pci_resource_len(dev, 0);
-
- if (!request_region(ioport, iolen, "ns558-pnp"))
- goto deactivate;
-
- if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
- printk(KERN_ERR "ns558: Memory allocation failed.\n");
- goto deactivate;
- }
- memset(port, 0, sizeof(struct ns558));
-
- port->next = next;
- port->type = NS558_PNP;
- port->gameport.io = ioport;
- port->size = iolen;
- port->dev = dev;
-
- gameport_register_port(&port->gameport);
-
- printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
- if (iolen > 1) printk(" size %d", iolen);
- printk(" speed %d kHz\n", port->gameport.speed);
-
- return port;
-
-deactivate:
- if (dev->deactivate)
- dev->deactivate(dev);
- return next;
-}
-#endif
-
-int __init ns558_init(void)
-{
- int i = 0;
-#ifdef __ISAPNP__
- struct isapnp_device_id *devid;
- struct pci_dev *dev = NULL;
-#endif
-
-/*
- * Probe for ISA ports.
- */
-
- while (ns558_isa_portlist[i])
- ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
-
-/*
- * Probe for PnP ports.
- */
-
-#ifdef __ISAPNP__
- for (devid = pnp_devids; devid->vendor; devid++) {
- while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
- ns558 = ns558_pnp_probe(dev, ns558);
- }
- }
-#endif
-
- return ns558 ? 0 : -ENODEV;
-}
-
-void __exit ns558_exit(void)
-{
- struct ns558 *next, *port = ns558;
-
- while (port) {
- gameport_unregister_port(&port->gameport);
- switch (port->type) {
-
-#ifdef __ISAPNP__
- case NS558_PNP:
- if (port->dev->deactivate)
- port->dev->deactivate(port->dev);
- /* fall through */
-#endif
-
- case NS558_ISA:
- release_region(port->gameport.io, port->size);
- break;
-
- default:
- break;
- }
-
- next = port->next;
- kfree(port);
- port = next;
- }
-}
-
-module_init(ns558_init);
-module_exit(ns558_exit);
+++ /dev/null
-/*
- * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- *
- * Based on the work of:
- * Raymond Ingles
- *
- * Sponsored by SuSE
- */
-
-/*
- * Trident 4DWave and Aureal Vortex gameport driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/module.h>
-#include <linux/pci.h>
-#include <linux/init.h>
-#include <linux/slab.h>
-#include <linux/gameport.h>
-
-#define PCI_VENDOR_ID_AUREAL 0x12eb
-
-#define PCIGAME_DATA_WAIT 20 /* 20 ms */
-
-#define PCIGAME_4DWAVE 0
-#define PCIGAME_VORTEX 1
-#define PCIGAME_VORTEX2 2
-
-struct pcigame_data {
- int gcr; /* Gameport control register */
- int legacy; /* Legacy port location */
- int axes; /* Axes start */
- int axsize; /* Axis field size */
- int axmax; /* Axis field max value */
- int adcmode; /* Value to enable ADC mode in GCR */
-};
-
-static struct pcigame_data pcigame_data[] __devinitdata =
-{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
- { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
- { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
- { 0 }};
-
-struct pcigame {
- struct gameport gameport;
- struct pci_dev *dev;
- unsigned char *base;
- struct pcigame_data *data;
-};
-
-static unsigned char pcigame_read(struct gameport *gameport)
-{
- struct pcigame *pcigame = gameport->private;
- return readb(pcigame->base + pcigame->data->legacy);
-}
-
-static void pcigame_trigger(struct gameport *gameport)
-{
- struct pcigame *pcigame = gameport->private;
- writeb(0xff, pcigame->base + pcigame->data->legacy);
-}
-
-static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
-{
- struct pcigame *pcigame = gameport->private;
- int i;
-
- *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
-
- for (i = 0; i < 4; i++) {
- axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
- if (axes[i] == pcigame->data->axmax) axes[i] = -1;
- }
-
- return 0;
-}
-
-static int pcigame_open(struct gameport *gameport, int mode)
-{
- struct pcigame *pcigame = gameport->private;
-
- switch (mode) {
- case GAMEPORT_MODE_COOKED:
- writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
- wait_ms(PCIGAME_DATA_WAIT);
- return 0;
- case GAMEPORT_MODE_RAW:
- writeb(0, pcigame->base + pcigame->data->gcr);
- return 0;
- default:
- return -1;
- }
-
- return 0;
-}
-
-static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
-{
- struct pcigame *pcigame;
- int i;
-
- if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
- return -1;
- memset(pcigame, 0, sizeof(struct pcigame));
-
-
- pcigame->data = pcigame_data + id->driver_data;
-
- pcigame->dev = dev;
- pci_set_drvdata(dev, pcigame);
-
- pcigame->gameport.private = pcigame;
- pcigame->gameport.fuzz = 64;
-
- pcigame->gameport.read = pcigame_read;
- pcigame->gameport.trigger = pcigame_trigger;
- pcigame->gameport.cooked_read = pcigame_cooked_read;
- pcigame->gameport.open = pcigame_open;
-
- for (i = 0; i < 6; i++)
- if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
- break;
-
- pci_enable_device(dev);
-
- pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
- pci_resource_len(pcigame->dev, i));
-
- gameport_register_port(&pcigame->gameport);
-
- printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
- pcigame->gameport.number, dev->name, dev->bus->number,
- PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
-
- return 0;
-}
-
-static void __devexit pcigame_remove(struct pci_dev *dev)
-{
- struct pcigame *pcigame = pci_get_drvdata(dev);
- gameport_unregister_port(&pcigame->gameport);
- iounmap(pcigame->base);
- kfree(pcigame);
-}
-
-static struct pci_device_id pcigame_id_table[] __devinitdata =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
- { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
- { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX },
- { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
- { 0 }};
-
-static struct pci_driver pcigame_driver = {
- name: "pcigame",
- id_table: pcigame_id_table,
- probe: pcigame_probe,
- remove: pcigame_remove,
-};
-
-int __init pcigame_init(void)
-{
- return pci_module_init(&pcigame_driver);
-}
-
-void __exit pcigame_exit(void)
-{
- pci_unregister_driver(&pcigame_driver);
-}
-
-module_init(pcigame_init);
-module_exit(pcigame_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * The Serio abstraction module
- */
-
-/*
- * 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/stddef.h>
-#include <linux/module.h>
-#include <linux/serio.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
-MODULE_LICENSE("GPL");
-
-EXPORT_SYMBOL(serio_register_port);
-EXPORT_SYMBOL(serio_unregister_port);
-EXPORT_SYMBOL(serio_register_device);
-EXPORT_SYMBOL(serio_unregister_device);
-EXPORT_SYMBOL(serio_open);
-EXPORT_SYMBOL(serio_close);
-EXPORT_SYMBOL(serio_rescan);
-
-static struct serio *serio_list;
-static struct serio_dev *serio_dev;
-static int serio_number;
-
-static void serio_find_dev(struct serio *serio)
-{
- struct serio_dev *dev = serio_dev;
-
- while (dev && !serio->dev) {
- if (dev->connect)
- dev->connect(serio, dev);
- dev = dev->next;
- }
-}
-
-void serio_rescan(struct serio *serio)
-{
- if (serio->dev && serio->dev->disconnect)
- serio->dev->disconnect(serio);
- serio_find_dev(serio);
-}
-
-void serio_register_port(struct serio *serio)
-{
- serio->number = serio_number++;
- serio->next = serio_list;
- serio_list = serio;
- serio_find_dev(serio);
-}
-
-void serio_unregister_port(struct serio *serio)
-{
- struct serio **serioptr = &serio_list;
-
- while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
- *serioptr = (*serioptr)->next;
-
- if (serio->dev && serio->dev->disconnect)
- serio->dev->disconnect(serio);
-
- serio_number--;
-}
-
-void serio_register_device(struct serio_dev *dev)
-{
- struct serio *serio = serio_list;
-
- dev->next = serio_dev;
- serio_dev = dev;
-
- while (serio) {
- if (!serio->dev && dev->connect)
- dev->connect(serio, dev);
- serio = serio->next;
- }
-}
-
-void serio_unregister_device(struct serio_dev *dev)
-{
- struct serio_dev **devptr = &serio_dev;
- struct serio *serio = serio_list;
-
- while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
- *devptr = (*devptr)->next;
-
- while (serio) {
- if (serio->dev == dev && dev->disconnect)
- dev->disconnect(serio);
- serio_find_dev(serio);
- serio = serio->next;
- }
-}
-
-int serio_open(struct serio *serio, struct serio_dev *dev)
-{
- if (serio->open(serio))
- return -1;
- serio->dev = dev;
- return 0;
-}
-
-void serio_close(struct serio *serio)
-{
- serio->close(serio);
- serio->dev = NULL;
-}
+++ /dev/null
-/*
- * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
- *
- * Copyright (c) 1999-2001 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module that converts a tty line into a much simpler
- * 'serial io port' abstraction that the input device drivers use.
- */
-
-/*
- * 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/uaccess.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/serio.h>
-#include <linux/tty.h>
-
-struct serport {
- struct tty_struct *tty;
- wait_queue_head_t wait;
- struct serio serio;
-};
-
-/*
- * Callback functions from the serio code.
- */
-
-static int serport_serio_write(struct serio *serio, unsigned char data)
-{
- struct serport *serport = serio->driver;
- return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
-}
-
-static int serport_serio_open(struct serio *serio)
-{
- return 0;
-}
-
-static void serport_serio_close(struct serio *serio)
-{
- struct serport *serport = serio->driver;
- wake_up_interruptible(&serport->wait);
-}
-
-/*
- * serport_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty. It looks for the Mag, and if found, registers
- * it as a joystick device.
- */
-
-static int serport_ldisc_open(struct tty_struct *tty)
-{
- struct serport *serport;
-
- MOD_INC_USE_COUNT;
-
- if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
- MOD_DEC_USE_COUNT;
- return -ENOMEM;
- }
-
- memset(serport, 0, sizeof(struct serport));
-
- serport->tty = tty;
- tty->disc_data = serport;
-
- serport->serio.type = SERIO_RS232;
- serport->serio.write = serport_serio_write;
- serport->serio.open = serport_serio_open;
- serport->serio.close = serport_serio_close;
- serport->serio.driver = serport;
-
- init_waitqueue_head(&serport->wait);
-
- return 0;
-}
-
-/*
- * serport_ldisc_close() is the opposite of serport_ldisc_open()
- */
-
-static void serport_ldisc_close(struct tty_struct *tty)
-{
- struct serport *serport = (struct serport*) tty->disc_data;
- kfree(serport);
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * serport_ldisc_receive() is called by the low level tty driver when characters
- * are ready for us. We forward the characters, one by one to the 'interrupt'
- * routine.
- */
-
-static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct serport *serport = (struct serport*) tty->disc_data;
- int i;
- for (i = 0; i < count; i++)
- if (serport->serio.dev)
- serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
-}
-
-/*
- * serport_ldisc_room() reports how much room we do have for receiving data.
- * Although we in fact have infinite room, we need to specify some value
- * here, and 256 seems to be reasonable.
- */
-
-static int serport_ldisc_room(struct tty_struct *tty)
-{
- return 256;
-}
-
-/*
- * serport_ldisc_read() just waits indefinitely if everything goes well.
- * However, when the serio driver closes the serio port, it finishes,
- * returning 0 characters.
- */
-
-static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
-{
- struct serport *serport = (struct serport*) tty->disc_data;
- DECLARE_WAITQUEUE(wait, current);
- char name[32];
-
-#ifdef CONFIG_DEVFS_FS
- sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#else
- sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
-#endif
-
- serio_register_port(&serport->serio);
-
- printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
-
- add_wait_queue(&serport->wait, &wait);
- current->state = TASK_INTERRUPTIBLE;
-
- while(serport->serio.type && !signal_pending(current)) schedule();
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&serport->wait, &wait);
-
- serio_unregister_port(&serport->serio);
-
- return 0;
-}
-
-/*
- * serport_ldisc_ioctl() allows to set the port protocol, and device ID
- */
-
-static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
-{
- struct serport *serport = (struct serport*) tty->disc_data;
-
- switch (cmd) {
- case SPIOCSTYPE:
- return get_user(serport->serio.type, (unsigned long *) arg);
- }
-
- return -EINVAL;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc serport_ldisc = {
- name: "input",
- open: serport_ldisc_open,
- close: serport_ldisc_close,
- read: serport_ldisc_read,
- ioctl: serport_ldisc_ioctl,
- receive_buf: serport_ldisc_receive,
- receive_room: serport_ldisc_room,
-};
-
-/*
- * The functions for insering/removing us as a module.
- */
-
-int __init serport_init(void)
-{
- if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
- printk(KERN_ERR "serport.c: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-void __exit serport_exit(void)
-{
- tty_register_ldisc(N_MOUSE, NULL);
-}
-
-module_init(serport_init);
-module_exit(serport_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
- *
- * Copyright (c) 1998-2001 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Microsoft SideWinder joystick family driver for Linux
- */
-
-/*
- * 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/delay.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/gameport.h>
-
-/*
- * These are really magic values. Changing them can make a problem go away,
- * as well as break everything.
- */
-
-#undef SW_DEBUG
-
-#define SW_START 400 /* The time we wait for the first bit [400 us] */
-#define SW_STROBE 45 /* Max time per bit [45 us] */
-#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
-#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
-#define SW_END 8 /* Number of bits before end of packet to kick */
-#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
-#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
-#define SW_OK 64 /* Number of packet read successes to switch optimization back on */
-#define SW_LENGTH 512 /* Max number of bits in a packet */
-#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */
-
-#ifdef SW_DEBUG
-#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
-#else
-#define dbg(format, arg...) do {} while (0)
-#endif
-
-/*
- * SideWinder joystick types ...
- */
-
-#define SW_ID_3DP 0
-#define SW_ID_GP 1
-#define SW_ID_PP 2
-#define SW_ID_FFP 3
-#define SW_ID_FSP 4
-#define SW_ID_FFW 5
-
-/*
- * Names, buttons, axes ...
- */
-
-static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
- "Force Feedback Wheel" };
-
-static char sw_abs[][7] = {
- { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
- { ABS_X, ABS_Y },
- { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
- { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
- { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
- { ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
-
-static char sw_bit[][7] = {
- { 10, 10, 9, 10, 1, 1 },
- { 1, 1 },
- { 10, 10, 6, 7, 1, 1 },
- { 10, 10, 6, 7, 1, 1 },
- { 10, 10, 6, 1, 1 },
- { 10, 7, 7, 1, 1 }};
-
-static short sw_btn[][12] = {
- { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
- { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
- { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
- { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
- { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
- { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
-
-static struct {
- int x;
- int y;
-} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-struct sw {
- struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev[4];
- char name[64];
- int length;
- int type;
- int bits;
- int number;
- int fail;
- int ok;
- int reads;
- int bads;
- int used;
-};
-
-/*
- * sw_read_packet() is a function which reads either a data packet, or an
- * identification packet from a SideWinder joystick. The protocol is very,
- * very, very braindamaged. Microsoft patented it in US patent #5628686.
- */
-
-static int sw_read_packet(struct gameport *gameport, 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 ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
- kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */
- start = gameport_time(gameport, SW_START);
- strobe = gameport_time(gameport, SW_STROBE);
- bitout = start;
- pending = 0;
- sched = 0;
-
- __save_flags(flags); /* Quiet, please */
- __cli();
-
- gameport_trigger(gameport); /* Trigger */
- v = gameport_read(gameport);
-
- do {
- bitout--;
- u = v;
- v = gameport_read(gameport);
- } 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 = gameport_read(gameport);
-
- 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 > -SW_END)) { /* Second trigger time */
- gameport_trigger(gameport); /* Trigger */
- bitout = start; /* Long bit timeout */
- pending = 0; /* Unmark schedule */
- timeout = 0; /* Switch from global to bit timeouts */
- }
- }
-
- __restore_flags(flags); /* Done - relax */
-
-#ifdef SW_DEBUG
- {
- int j;
- printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
- for (j = 0; j < i; j++) printk("%d", buf[j]);
- printk("]\n");
- }
-#endif
-
- return i;
-}
-
-/*
- * 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) sw_get_bits(buf, pos, num, sw->bits)
-
-static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
-{
- __u64 data = 0;
- int tri = pos % bits; /* Start position */
- int i = pos / bits;
- int bit = 0;
-
- while (num--) {
- data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
- if (tri == bits) {
- i++; /* Next triplet */
- tri = 0;
- }
- }
-
- return data;
-}
-
-/*
- * sw_init_digital() initializes a SideWinder 3D Pro joystick
- * into digital mode.
- */
-
-static void sw_init_digital(struct gameport *gameport)
-{
- int seq[] = { 140, 140+725, 140+300, 0 };
- unsigned long flags;
- int i, t;
-
- __save_flags(flags);
- __cli();
-
- i = 0;
- do {
- gameport_trigger(gameport); /* Trigger */
- t = gameport_time(gameport, SW_TIMEOUT);
- while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
- udelay(seq[i]); /* Delay magic time */
- } while (seq[++i]);
-
- gameport_trigger(gameport); /* Last trigger */
-
- __restore_flags(flags);
-}
-
-/*
- * sw_parity() computes parity of __u64
- */
-
-static int 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;
-}
-
-/*
- * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
- */
-
-static int sw_check(__u64 t)
-{
- unsigned char sum = 0;
-
- if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
- return -1;
-
- while (t) { /* Sum */
- sum += t & 0xf;
- t >>= 4;
- }
-
- return sum & 0xf;
-}
-
-/*
- * sw_parse() analyzes SideWinder joystick data, and writes the results into
- * the axes and buttons arrays.
- */
-
-static int sw_parse(unsigned char *buf, struct sw *sw)
-{
- int hat, i, j;
- struct input_dev *dev = sw->dev;
-
- switch (sw->type) {
-
- case SW_ID_3DP:
-
- if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
-
- input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
- input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
- input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
- input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
-
- input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
- input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
- for (j = 0; j < 7; j++)
- input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
-
- input_report_key(dev, BTN_BASE4, !GB(38,1));
- input_report_key(dev, BTN_BASE5, !GB(37,1));
-
- return 0;
-
- case SW_ID_GP:
-
- for (i = 0; i < sw->number; i ++) {
-
- if (sw_parity(GB(i*15,15))) return -1;
-
- input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
- input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
-
- for (j = 0; j < 10; j++)
- input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
- }
-
- return 0;
-
- case SW_ID_PP:
- case SW_ID_FFP:
-
- if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
-
- input_report_abs(dev, ABS_X, GB( 9,10));
- input_report_abs(dev, ABS_Y, GB(19,10));
- input_report_abs(dev, ABS_RZ, GB(36, 6));
- input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
-
- input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
- input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
- for (j = 0; j < 9; j++)
- input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
-
- return 0;
-
- case SW_ID_FSP:
-
- if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
-
- input_report_abs(dev, ABS_X, GB( 0,10));
- input_report_abs(dev, ABS_Y, GB(16,10));
- input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
-
- input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
- input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
-
- for (j = 0; j < 6; j++)
- input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
-
- input_report_key(dev, BTN_TR, GB(26,1));
- input_report_key(dev, BTN_START, GB(27,1));
- input_report_key(dev, BTN_MODE, GB(38,1));
- input_report_key(dev, BTN_SELECT, GB(39,1));
-
- return 0;
-
- case SW_ID_FFW:
-
- if (!sw_parity(GB(0,33))) return -1;
-
- input_report_abs(dev, ABS_RX, GB( 0,10));
- input_report_abs(dev, ABS_RUDDER, GB(10, 6));
- input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
-
- for (j = 0; j < 8; j++)
- input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
-
- return 0;
- }
-
- return -1;
-}
-
-/*
- * 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 sw_read(struct sw *sw)
-{
- unsigned char buf[SW_LENGTH];
- int i;
-
- i = sw_read_packet(sw->gameport, buf, sw->length, 0);
-
- if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */
-
- if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */
- printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
- " - going to reinitialize.\n", sw->gameport->number);
- sw->fail = SW_FAIL; /* Reinitialize */
- i = 128; /* Bogus value */
- }
-
- if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */
- memmove(buf, buf + i - 22, 22); /* Move data */
- i = 66; /* Carry on */
- }
- }
-
- if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */
-
- sw->fail = 0;
- sw->ok++;
-
- if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */
- && sw->ok > SW_OK) {
-
- printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
- " - enabling optimization again.\n", sw->gameport->number);
- sw->length = 22;
- }
-
- return 0;
- }
-
- sw->ok = 0;
- sw->fail++;
-
- if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */
-
- printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
- " - disabling optimization.\n", sw->gameport->number);
- sw->length = 66;
- }
-
- if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
-
- printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
- " - reinitializing joystick.\n", sw->gameport->number);
-
- if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */
- udelay(3 * SW_TIMEOUT);
- sw_init_digital(sw->gameport);
- }
-
- udelay(SW_TIMEOUT);
- i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
- udelay(SW_TIMEOUT);
- sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
-
- sw->fail = SW_FAIL;
-
- return -1;
-}
-
-static void sw_timer(unsigned long private)
-{
- struct sw *sw = (void *) private;
-
- sw->reads++;
- if (sw_read(sw)) sw->bads++;
- mod_timer(&sw->timer, jiffies + SW_REFRESH);
-}
-
-static int sw_open(struct input_dev *dev)
-{
- struct sw *sw = dev->private;
- if (!sw->used++)
- mod_timer(&sw->timer, jiffies + SW_REFRESH);
- return 0;
-}
-
-static void sw_close(struct input_dev *dev)
-{
- struct sw *sw = dev->private;
- if (!--sw->used)
- del_timer(&sw->timer);
-}
-
-/*
- * sw_print_packet() prints the contents of a SideWinder packet.
- */
-
-static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
-{
- int i;
-
- printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
- for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
- printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
- printk("]\n");
-}
-
-/*
- * 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 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] = sw_get_bits(buf, 24+8*i, 8, 1);
-
- for (i = 0; i < 8; i++) /* ASCII firmware revision */
- rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
-
- pnp[7] = rev[8] = 0;
-
- sprintf(comment, " [PnP %d.%02d id %s rev %s]",
- (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
- sw_get_bits(buf, 16, 6, 1)) / 100,
- (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
- sw_get_bits(buf, 16, 6, 1)) % 100,
- pnp, rev);
-}
-
-/*
- * 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 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;
-}
-
-/*
- * sw_connect() probes for SideWinder type joysticks.
- */
-
-static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct sw *sw;
- int i, j, k, l;
- unsigned char buf[SW_LENGTH];
- unsigned char idbuf[SW_LENGTH];
- unsigned char m = 1;
- char comment[40];
-
- comment[0] = 0;
-
- if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
- memset(sw, 0, sizeof(struct sw));
-
- gameport->private = sw;
-
- sw->gameport = gameport;
- init_timer(&sw->timer);
- sw->timer.data = (long) sw;
- sw->timer.function = sw_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- dbg("Init 0: Opened gameport %d, io %#x, speed %d",
- gameport->number, gameport->io, gameport->speed);
-
- i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
- m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
- udelay(SW_TIMEOUT);
- dbg("Init 1: Mode %d. Length %d.", m , i);
-
- if (!i) { /* No data. 3d Pro analog mode? */
- sw_init_digital(gameport); /* Switch to digital */
- udelay(SW_TIMEOUT);
- i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
- udelay(SW_TIMEOUT);
- dbg("Init 1b: Length %d.", i);
- if (!i) goto fail2; /* No data -> FAIL */
- }
-
- j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */
- m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
- dbg("Init 2: Mode %d. ID Length %d.", m , j);
-
- if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
- udelay(SW_TIMEOUT);
- i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
- dbg("Init 2b: Mode %d. Length %d.", m, i);
- if (!i) goto fail2;
- udelay(SW_TIMEOUT);
- j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */
- dbg("Init 2c: ID Length %d.", j);
- }
-
- sw->type = -1;
- k = SW_FAIL; /* Try SW_FAIL times */
- l = 0;
-
- do {
- k--;
- udelay(SW_TIMEOUT);
- i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */
- dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
-
- 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 */
-
- sw->number = 1;
- sw->gameport = gameport;
- sw->length = i;
- sw->bits = m;
-
- dbg("Init 3a: Case %d.\n", i * m);
-
- switch (i * m) {
- case 60:
- sw->number++;
- case 45: /* Ambiguous packet length */
- if (j <= 40) { /* ID length less or eq 40 -> FSP */
- case 43:
- sw->type = SW_ID_FSP;
- break;
- }
- sw->number++;
- case 30:
- sw->number++;
- case 15:
- sw->type = SW_ID_GP;
- break;
- case 33:
- case 31:
- sw->type = SW_ID_FFW;
- break;
- case 48: /* Ambiguous */
- if (j == 14) { /* ID length 14*3 -> FFP */
- sw->type = SW_ID_FFP;
- sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
- } else
- sw->type = SW_ID_PP;
- break;
- case 198:
- sw->length = 22;
- case 64:
- sw->type = SW_ID_3DP;
- if (j == 160) sw_3dp_id(idbuf, comment);
- break;
- }
- }
-
- } while (k && (sw->type == -1));
-
- if (sw->type == -1) {
- printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
- "on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
- sw_print_packet("ID", j * 3, idbuf, 3);
- sw_print_packet("Data", i * m, buf, m);
- goto fail2;
- }
-
-#ifdef SW_DEBUG
- sw_print_packet("ID", j * 3, idbuf, 3);
- sw_print_packet("Data", i * m, buf, m);
-#endif
-
- k = i;
- l = j;
-
- for (i = 0; i < sw->number; i++) {
- int bits, code;
-
- sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
-
- sw->dev[i].private = sw;
-
- sw->dev[i].open = sw_open;
- sw->dev[i].close = sw_close;
-
- sw->dev[i].name = sw->name;
- sw->dev[i].idbus = BUS_GAMEPORT;
- sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
- sw->dev[i].idproduct = sw->type;
- sw->dev[i].idversion = 0x0100;
-
- sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
- code = sw_abs[sw->type][j];
- set_bit(code, sw->dev[i].absbit);
- sw->dev[i].absmax[code] = (1 << bits) - 1;
- sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
- sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
- if (code != ABS_THROTTLE)
- sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
- }
-
- for (j = 0; (code = sw_btn[sw->type][j]); j++)
- set_bit(code, sw->dev[i].keybit);
-
- input_register_device(sw->dev + i);
- printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
- sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
- }
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(sw);
-}
-
-static void sw_disconnect(struct gameport *gameport)
-{
- int i;
-
- struct sw *sw = gameport->private;
- for (i = 0; i < sw->number; i++)
- input_unregister_device(sw->dev + i);
- gameport_close(gameport);
- kfree(sw);
-}
-
-static struct gameport_dev sw_dev = {
- connect: sw_connect,
- disconnect: sw_disconnect,
-};
-
-int __init sw_init(void)
-{
- gameport_register_device(&sw_dev);
- return 0;
-}
-
-void __exit sw_exit(void)
-{
- gameport_unregister_device(&sw_dev);
-}
-
-module_init(sw_init);
-module_exit(sw_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Based on the work of:
- * David Thompson
- * Joseph Krahn
- *
- * Sponsored by SuSE
- */
-
-/*
- * SpaceTec SpaceBall 4000 FLX driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-
-/*
- * Constants.
- */
-
-#define JS_SBALL_MAX_LENGTH 128
-static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
-static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX";
-
-/*
- * Per-Ball data.
- */
-
-struct spaceball {
- struct input_dev dev;
- struct serio *serio;
- int idx;
- int escape;
- unsigned char data[JS_SBALL_MAX_LENGTH];
-};
-
-/*
- * spaceball_process_packet() decodes packets the driver receives from the
- * SpaceBall.
- */
-
-static void spaceball_process_packet(struct spaceball* spaceball)
-{
- struct input_dev *dev = &spaceball->dev;
- unsigned char *data = spaceball->data;
- int i;
-
- if (spaceball->idx < 2) return;
-
- printk("%c %d\n", spaceball->data[0], spaceball->idx);
-
- switch (spaceball->data[0]) {
-
- case '@': /* Reset packet */
- spaceball->data[spaceball->idx - 1] = 0;
- for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
- printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
- spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
- break;
-
- case 'D': /* Ball data */
- if (spaceball->idx != 15) return;
- for (i = 0; i < 6; i++) {
- input_report_abs(dev, spaceball_axes[i],
- (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
- }
- break;
-
- case '.': /* Button data, part2 */
- if (spaceball->idx != 3) return;
- input_report_key(dev, BTN_0, data[2] & 1);
- input_report_key(dev, BTN_1, data[2] & 2);
- break;
-
- case '?': /* Error packet */
- spaceball->data[spaceball->idx - 1] = 0;
- printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
- break;
- }
-}
-
-/*
- * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
- * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
- * can occur in the axis values.
- */
-
-static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct spaceball *spaceball = serio->private;
-
- switch (data) {
- case 0xd:
- spaceball_process_packet(spaceball);
- spaceball->idx = 0;
- spaceball->escape = 0;
- return;
- case '^':
- if (!spaceball->escape) {
- spaceball->escape = 1;
- return;
- }
- spaceball->escape = 0;
- case 'M':
- case 'Q':
- case 'S':
- if (spaceball->escape) {
- spaceball->escape = 0;
- data &= 0x1f;
- }
- default:
- if (spaceball->escape) {
- spaceball->escape = 0;
- printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
- }
- if (spaceball->idx < JS_SBALL_MAX_LENGTH)
- spaceball->data[spaceball->idx++] = data;
- return;
- }
-}
-
-/*
- * spaceball_disconnect() is the opposite of spaceball_connect()
- */
-
-static void spaceball_disconnect(struct serio *serio)
-{
- struct spaceball* spaceball = serio->private;
- input_unregister_device(&spaceball->dev);
- serio_close(serio);
- kfree(spaceball);
-}
-
-/*
- * spaceball_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Magellan, and if found, registers
- * it as an input device.
- */
-
-static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct spaceball *spaceball;
- int i, t;
-
- if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
- return;
-
- if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
- return;
- memset(spaceball, 0, sizeof(struct spaceball));
-
- spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
-
- for (i = 0; i < 6; i++) {
- t = spaceball_axes[i];
- set_bit(t, spaceball->dev.absbit);
- spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
- spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600;
- spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
- spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
- }
-
- spaceball->serio = serio;
- spaceball->dev.private = spaceball;
-
- spaceball->dev.name = spaceball_name;
- spaceball->dev.idbus = BUS_RS232;
- spaceball->dev.idvendor = SERIO_SPACEBALL;
- spaceball->dev.idproduct = 0x0001;
- spaceball->dev.idversion = 0x0100;
-
- serio->private = spaceball;
-
- if (serio_open(serio, dev)) {
- kfree(spaceball);
- return;
- }
-
- input_register_device(&spaceball->dev);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev spaceball_dev = {
- interrupt: spaceball_interrupt,
- connect: spaceball_connect,
- disconnect: spaceball_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init spaceball_init(void)
-{
- serio_register_device(&spaceball_dev);
- return 0;
-}
-
-void __exit spaceball_exit(void)
-{
- serio_unregister_device(&spaceball_dev);
-}
-
-module_init(spaceball_init);
-module_exit(spaceball_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Based on the work of:
- * David Thompson
- *
- * Sponsored by SuSE
- */
-
-/*
- * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
- */
-
-/*
- * 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/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-
-/*
- * Constants.
- */
-
-#define SPACEORB_MAX_LENGTH 64
-
-static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
-static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
-static char *spaceorb_name = "SpaceTec SpaceOrb 360";
-
-/*
- * Per-Orb data.
- */
-
-struct spaceorb {
- struct input_dev dev;
- struct serio *serio;
- int idx;
- unsigned char data[SPACEORB_MAX_LENGTH];
-};
-
-static unsigned char spaceorb_xor[] = "SpaceWare";
-
-static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
- "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
-
-/*
- * spaceorb_process_packet() decodes packets the driver receives from the
- * SpaceOrb.
- */
-
-static void spaceorb_process_packet(struct spaceorb *spaceorb)
-{
- struct input_dev *dev = &spaceorb->dev;
- unsigned char *data = spaceorb->data;
- unsigned char c = 0;
- int axes[6];
- int i;
-
- if (spaceorb->idx < 2) return;
- for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
- if (c) return;
-
- switch (data[0]) {
-
- case 'R': /* Reset packet */
- spaceorb->data[spaceorb->idx - 1] = 0;
- for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
- printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
- spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
- break;
-
- case 'D': /* Ball + button data */
- if (spaceorb->idx != 12) return;
- for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i];
- axes[0] = ( data[2] << 3) | (data[ 3] >> 4);
- axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
- axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
- axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
- axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
- axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
- for (i = 0; i < 6; i++)
- input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
- for (i = 0; i < 8; i++)
- input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
- break;
-
- case 'K': /* Button data */
- if (spaceorb->idx != 5) return;
- for (i = 0; i < 7; i++)
- input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
-
- break;
-
- case 'E': /* Error packet */
- if (spaceorb->idx != 4) return;
- printk(KERN_ERR "joy-spaceorb: Device error. [ ");
- for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
- printk("]\n");
- break;
- }
-}
-
-static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct spaceorb* spaceorb = serio->private;
-
- if (~data & 0x80) {
- if (spaceorb->idx) spaceorb_process_packet(spaceorb);
- spaceorb->idx = 0;
- }
- if (spaceorb->idx < SPACEORB_MAX_LENGTH)
- spaceorb->data[spaceorb->idx++] = data & 0x7f;
-}
-
-/*
- * spaceorb_disconnect() is the opposite of spaceorb_connect()
- */
-
-static void spaceorb_disconnect(struct serio *serio)
-{
- struct spaceorb* spaceorb = serio->private;
- input_unregister_device(&spaceorb->dev);
- serio_close(serio);
- kfree(spaceorb);
-}
-
-/*
- * spaceorb_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
- * it as an input device.
- */
-
-static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct spaceorb *spaceorb;
- int i, t;
-
- if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
- return;
-
- if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
- return;
- memset(spaceorb, 0, sizeof(struct spaceorb));
-
- spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = 0; i < 7; i++)
- set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
-
- for (i = 0; i < 6; i++) {
- t = spaceorb_axes[i];
- set_bit(t, spaceorb->dev.absbit);
- spaceorb->dev.absmin[t] = -508;
- spaceorb->dev.absmax[t] = 508;
- }
-
- spaceorb->serio = serio;
- spaceorb->dev.private = spaceorb;
-
- spaceorb->dev.name = spaceorb_name;
- spaceorb->dev.idbus = BUS_RS232;
- spaceorb->dev.idvendor = SERIO_SPACEORB;
- spaceorb->dev.idproduct = 0x0001;
- spaceorb->dev.idversion = 0x0100;
-
- serio->private = spaceorb;
-
- if (serio_open(serio, dev)) {
- kfree(spaceorb);
- return;
- }
-
- input_register_device(&spaceorb->dev);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev spaceorb_dev = {
- interrupt: spaceorb_interrupt,
- connect: spaceorb_connect,
- disconnect: spaceorb_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init spaceorb_init(void)
-{
- serio_register_device(&spaceorb_dev);
- return 0;
-}
-
-void __exit spaceorb_exit(void)
-{
- serio_unregister_device(&spaceorb_dev);
-}
-
-module_init(spaceorb_init);
-module_exit(spaceorb_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
- *
- * Copyright (c) 2000-2001 Vojtech Pavlik
- * Copyright (c) 2000 Mark Fletcher
- *
- * Sponsored by SuSE
- */
-
-/*
- * Gravis Stinger gamepad driver for Linux
- */
-
-/*
- * This program is free warftware; 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define STINGER_MAX_LENGTH 8
-
-static char *stinger_name = "Gravis Stinger";
-
-/*
- * Per-Stinger data.
- */
-
-struct stinger {
- struct input_dev dev;
- int idx;
- unsigned char data[STINGER_MAX_LENGTH];
-};
-
-/*
- * stinger_process_packet() decodes packets the driver receives from the
- * Stinger. It updates the data accordingly.
- */
-
-static void stinger_process_packet(struct stinger *stinger)
-{
- struct input_dev *dev = &stinger->dev;
- unsigned char *data = stinger->data;
-
- if (!stinger->idx) return;
-
- input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5));
- input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4));
- input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3));
- input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2));
- input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5));
- input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4));
- input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3));
- input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2));
- input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
- input_report_key(dev, BTN_START, (data[3] & 0x01));
-
- input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
- input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
-
- return;
-}
-
-/*
- * stinger_interrupt() is called by the low level driver when characters
- * are ready for us. We then buffer them for further processing, or call the
- * packet processing routine.
- */
-
-static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct stinger* stinger = serio->private;
-
- /* All Stinger packets are 4 bytes */
-
- if (stinger->idx < STINGER_MAX_LENGTH)
- stinger->data[stinger->idx++] = data;
-
- if (stinger->idx == 4) {
- stinger_process_packet(stinger);
- stinger->idx = 0;
- }
-
- return;
-}
-
-/*
- * stinger_disconnect() is the opposite of stinger_connect()
- */
-
-static void stinger_disconnect(struct serio *serio)
-{
- struct stinger* stinger = serio->private;
- input_unregister_device(&stinger->dev);
- serio_close(serio);
- kfree(stinger);
-}
-
-/*
- * stinger_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Stinger, and if found, registers
- * it as an input device.
- */
-
-static void stinger_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct stinger *stinger;
- int i;
-
- if (serio->type != (SERIO_RS232 | SERIO_STINGER))
- return;
-
- if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
- return;
-
- memset(stinger, 0, sizeof(struct stinger));
-
- stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
- BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
- BIT(BTN_START) | BIT(BTN_SELECT);
- stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
- stinger->dev.name = stinger_name;
- stinger->dev.idbus = BUS_RS232;
- stinger->dev.idvendor = SERIO_STINGER;
- stinger->dev.idproduct = 0x0001;
- stinger->dev.idversion = 0x0100;
-
- for (i = 0; i < 2; i++) {
- stinger->dev.absmax[ABS_X+i] = 64;
- stinger->dev.absmin[ABS_X+i] = -64;
- stinger->dev.absflat[ABS_X+i] = 4;
- }
-
- stinger->dev.private = stinger;
-
- serio->private = stinger;
-
- if (serio_open(serio, dev)) {
- kfree(stinger);
- return;
- }
-
- input_register_device(&stinger->dev);
-
- printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev stinger_dev = {
- interrupt: stinger_interrupt,
- connect: stinger_connect,
- disconnect: stinger_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init stinger_init(void)
-{
- serio_register_device(&stinger_dev);
- return 0;
-}
-
-void __exit stinger_exit(void)
-{
- serio_unregister_device(&stinger_dev);
-}
-
-module_init(stinger_init);
-module_exit(stinger_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- *
- * Based on the work of:
- * Trystan Larey-Williams
- *
- */
-
-/*
- * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
- */
-
-/*
- * 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/delay.h>
-#include <linux/kernel.h>
-#include <linux/slab.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/gameport.h>
-#include <linux/input.h>
-
-#define TMDC_MAX_START 400 /* 400 us */
-#define TMDC_MAX_STROBE 45 /* 45 us */
-#define TMDC_MAX_LENGTH 13
-#define TMDC_REFRESH_TIME HZ/50 /* 20 ms */
-
-#define TMDC_MODE_M3DI 1
-#define TMDC_MODE_3DRP 3
-#define TMDC_MODE_AT 4
-#define TMDC_MODE_FM 8
-#define TMDC_MODE_FGP 163
-
-#define TMDC_BYTE_ID 10
-#define TMDC_BYTE_REV 11
-#define TMDC_BYTE_DEF 12
-
-#define TMDC_ABS 7
-#define TMDC_ABS_HAT 4
-#define TMDC_BTN 16
-
-static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
-static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
-
-static signed char tmdc_abs[TMDC_ABS] =
- { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
-static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
- { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
-static signed char tmdc_abs_at[TMDC_ABS] =
- { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
-static signed char tmdc_abs_fm[TMDC_ABS] =
- { ABS_RX, ABS_RY, ABS_X, ABS_Y };
-
-static short tmdc_btn_pad[TMDC_BTN] =
- { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
-static short tmdc_btn_joy[TMDC_BTN] =
- { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
- BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
-static short tmdc_btn_fm[TMDC_BTN] =
- { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
-static short tmdc_btn_at[TMDC_BTN] =
- { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
- BTN_BASE3, BTN_BASE2, BTN_BASE };
-
-static struct {
- int x;
- int y;
-} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
-
-struct tmdc {
- struct gameport *gameport;
- struct timer_list timer;
- struct input_dev dev[2];
- char name[2][64];
- int mode[2];
- signed char *abs[2];
- short *btn[2];
- unsigned char absc[2];
- unsigned char btnc[2][4];
- unsigned char btno[2][4];
- int used;
- int reads;
- int bads;
- unsigned char exists;
-};
-
-/*
- * tmdc_read_packet() reads a ThrustMaster packet.
- */
-
-static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
-{
- unsigned char u, v, w, x;
- unsigned long flags;
- int i[2], j[2], t[2], p, k;
-
- p = gameport_time(gameport, TMDC_MAX_STROBE);
-
- for (k = 0; k < 2; k++) {
- t[k] = gameport_time(gameport, TMDC_MAX_START);
- i[k] = j[k] = 0;
- }
-
- __save_flags(flags);
- __cli();
- gameport_trigger(gameport);
-
- w = gameport_read(gameport) >> 4;
-
- do {
- x = w;
- w = gameport_read(gameport) >> 4;
-
- for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
- if (~v & u & 2) {
- if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
- t[k] = p;
- if (j[k] == 0) { /* Start bit */
- if (~v & 1) t[k] = 0;
- data[k][i[k]] = 0; j[k]++; continue;
- }
- if (j[k] == 9) { /* Stop bit */
- if (v & 1) t[k] = 0;
- j[k] = 0; i[k]++; continue;
- }
- data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */
- }
- t[k]--;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
- return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
-}
-
-/*
- * tmdc_read() reads and analyzes ThrustMaster joystick data.
- */
-
-static void tmdc_timer(unsigned long private)
-{
- unsigned char data[2][TMDC_MAX_LENGTH];
- struct tmdc *tmdc = (void *) private;
- struct input_dev *dev;
- unsigned char r, bad = 0;
- int i, j, k, l;
-
- tmdc->reads++;
-
- if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
- bad = 1;
-
- for (j = 0; j < 2; j++)
- if (r & (1 << j) & tmdc->exists) {
-
- if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
- bad = 1;
- continue;
- }
-
- dev = tmdc->dev + j;
-
- for (i = 0; i < tmdc->absc[j]; i++) {
- if (tmdc->abs[j][i] < 0) continue;
- input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
- }
-
- switch (tmdc->mode[j]) {
-
- case TMDC_MODE_M3DI:
-
- i = tmdc_byte_d[0];
- input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
- input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1));
- break;
-
- case TMDC_MODE_AT:
-
- i = tmdc_byte_a[3];
- input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
- input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
- break;
-
- }
-
- for (k = l = 0; k < 4; k++) {
- for (i = 0; i < tmdc->btnc[j][k]; i++)
- input_report_key(dev, tmdc->btn[j][i + l],
- ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
- l += tmdc->btnc[j][k];
- }
- }
-
- tmdc->bads += bad;
-
- mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
-}
-
-static int tmdc_open(struct input_dev *dev)
-{
- struct tmdc *tmdc = dev->private;
- if (!tmdc->used++)
- mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
- return 0;
-}
-
-static void tmdc_close(struct input_dev *dev)
-{
- struct tmdc *tmdc = dev->private;
- if (!--tmdc->used)
- del_timer(&tmdc->timer);
-}
-
-/*
- * tmdc_probe() probes for ThrustMaster type joysticks.
- */
-
-static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
-{
- struct models {
- unsigned char id;
- char *name;
- char abs;
- char hats;
- char btnc[4];
- char btno[4];
- signed char *axes;
- short *buttons;
- } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
- { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
- { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
- { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
- { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
- { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
-
- unsigned char data[2][TMDC_MAX_LENGTH];
- struct tmdc *tmdc;
- int i, j, k, l, m;
-
- if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
- return;
- memset(tmdc, 0, sizeof(struct tmdc));
-
- gameport->private = tmdc;
-
- tmdc->gameport = gameport;
- init_timer(&tmdc->timer);
- tmdc->timer.data = (long) tmdc;
- tmdc->timer.function = tmdc_timer;
-
- if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
- goto fail1;
-
- if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
- goto fail2;
-
- for (j = 0; j < 2; j++)
- if (tmdc->exists & (1 << j)) {
-
- tmdc->mode[j] = data[j][TMDC_BYTE_ID];
-
- for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
-
- tmdc->abs[j] = models[m].axes;
- tmdc->btn[j] = models[m].buttons;
-
- if (!models[m].id) {
- models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
- for (k = 0; k < 4; k++)
- models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
- }
-
- tmdc->absc[j] = models[m].abs;
- for (k = 0; k < 4; k++) {
- tmdc->btnc[j][k] = models[m].btnc[k];
- tmdc->btno[j][k] = models[m].btno[k];
- }
-
- sprintf(tmdc->name[j], models[m].name, models[m].abs,
- (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
-
- tmdc->dev[j].private = tmdc;
- tmdc->dev[j].open = tmdc_open;
- tmdc->dev[j].close = tmdc_close;
-
- tmdc->dev[j].name = tmdc->name[j];
- tmdc->dev[j].idbus = BUS_GAMEPORT;
- tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
- tmdc->dev[j].idproduct = models[m].id;
- tmdc->dev[j].idversion = 0x0100;
-
- tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
-
- for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
- if (tmdc->abs[i] < 0) continue;
- set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
- tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
- tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
- tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
- tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
- }
-
- for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
- set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
- tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
- tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
- }
-
- for (k = l = 0; k < 4; k++) {
- for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
- set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
- l += models[m].btnc[k];
- }
-
- input_register_device(tmdc->dev + j);
- printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
- tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
- }
-
- return;
-fail2: gameport_close(gameport);
-fail1: kfree(tmdc);
-}
-
-static void tmdc_disconnect(struct gameport *gameport)
-{
- struct tmdc *tmdc = gameport->private;
- int i;
- for (i = 0; i < 2; i++)
- if (tmdc->exists & (1 << i))
- input_unregister_device(tmdc->dev + i);
- gameport_close(gameport);
- kfree(tmdc);
-}
-
-static struct gameport_dev tmdc_dev = {
- connect: tmdc_connect,
- disconnect: tmdc_disconnect,
-};
-
-int __init tmdc_init(void)
-{
- gameport_register_device(&tmdc_dev);
- return 0;
-}
-
-void __exit tmdc_exit(void)
-{
- gameport_unregister_device(&tmdc_dev);
-}
-
-module_init(tmdc_init);
-module_exit(tmdc_exit);
-
-MODULE_LICENSE("GPL");
+++ /dev/null
-/*
- * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
- *
- * Copyright (c) 1998-2000 Vojtech Pavlik
- *
- * Based on the work of:
- * Steffen Schwenke
- *
- * Sponsored by SuSE
- */
-
-/*
- * TurboGraFX parallel port interface driver for Linux.
- */
-
-/*
- * 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/kernel.h>
-#include <linux/parport.h>
-#include <linux/input.h>
-#include <linux/module.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_LICENSE("GPL");
-MODULE_PARM(tgfx, "2-8i");
-MODULE_PARM(tgfx_2, "2-8i");
-MODULE_PARM(tgfx_3, "2-8i");
-
-#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
-
-#define TGFX_TRIGGER 0x08
-#define TGFX_UP 0x10
-#define TGFX_DOWN 0x20
-#define TGFX_LEFT 0x40
-#define TGFX_RIGHT 0x80
-
-#define TGFX_THUMB 0x02
-#define TGFX_THUMB2 0x04
-#define TGFX_TOP 0x01
-#define TGFX_TOP2 0x08
-
-static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-
-static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
-static char *tgfx_name = "TurboGraFX Multisystem joystick";
-
-struct tgfx {
- struct pardevice *pd;
- struct timer_list timer;
- struct input_dev dev[7];
- int sticks;
- int used;
-} *tgfx_base[3];
-
-/*
- * tgfx_timer() reads and analyzes TurboGraFX joystick data.
- */
-
-static void tgfx_timer(unsigned long private)
-{
- struct tgfx *tgfx = (void *) private;
- struct input_dev *dev;
- int data1, data2, i;
-
- for (i = 0; i < 7; i++)
- if (tgfx->sticks & (1 << i)) {
-
- dev = tgfx->dev + i;
-
- parport_write_data(tgfx->pd->port, ~(1 << i));
- data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
- data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */
-
- input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT));
- input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP ));
-
- input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER));
- input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB ));
- input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 ));
- input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP ));
- input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 ));
- }
-
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
-}
-
-static int tgfx_open(struct input_dev *dev)
-{
- struct tgfx *tgfx = dev->private;
- if (!tgfx->used++) {
- parport_claim(tgfx->pd);
- parport_write_control(tgfx->pd->port, 0x04);
- mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
- }
- return 0;
-}
-
-static void tgfx_close(struct input_dev *dev)
-{
- struct tgfx *tgfx = dev->private;
- if (!--tgfx->used) {
- del_timer(&tgfx->timer);
- parport_write_control(tgfx->pd->port, 0x00);
- parport_release(tgfx->pd);
- }
-}
-
-/*
- * tgfx_probe() probes for tg gamepads.
- */
-
-static struct tgfx __init *tgfx_probe(int *config)
-{
- struct tgfx *tgfx;
- struct parport *pp;
- int i, j;
-
- if (config[0] < 0)
- return NULL;
-
- for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
- config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "turbografx.c: no such parport\n");
- return NULL;
- }
-
- if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL)))
- return NULL;
- memset(tgfx, 0, sizeof(struct tgfx));
-
- tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
-
- if (!tgfx->pd) {
- printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
- kfree(tgfx);
- return NULL;
- }
-
- init_timer(&tgfx->timer);
- tgfx->timer.data = (long) tgfx;
- tgfx->timer.function = tgfx_timer;
-
- tgfx->sticks = 0;
-
- for (i = 0; i < 7; i++)
- if (config[i+1] > 0 && config[i+1] < 6) {
-
- tgfx->sticks |= (1 << i);
-
- tgfx->dev[i].private = tgfx;
- tgfx->dev[i].open = tgfx_open;
- tgfx->dev[i].close = tgfx_close;
-
- tgfx->dev[i].name = tgfx_name;
- tgfx->dev[i].idbus = BUS_PARPORT;
- tgfx->dev[i].idvendor = 0x0003;
- tgfx->dev[i].idproduct = config[i+1];
- tgfx->dev[i].idversion = 0x0100;
-
- tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
- tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
-
- for (j = 0; j < config[i+1]; j++)
- set_bit(tgfx_buttons[j], tgfx->dev[i].keybit);
-
- tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
- tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
-
- input_register_device(tgfx->dev + i);
- printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n",
- tgfx->dev[i].number, config[i+1], tgfx->pd->port->name);
- }
-
- if (!tgfx->sticks) {
- parport_unregister_device(tgfx->pd);
- kfree(tgfx);
- return NULL;
- }
-
- return tgfx;
-}
-
-#ifndef MODULE
-int __init tgfx_setup(char *str)
-{
- int i, ints[9];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1];
- return 1;
-}
-int __init tgfx_setup_2(char *str)
-{
- int i, ints[9];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1];
- return 1;
-}
-int __init tgfx_setup_3(char *str)
-{
- int i, ints[9];
- get_options(str, ARRAY_SIZE(ints), ints);
- for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1];
- return 1;
-}
-__setup("tgfx=", tgfx_setup);
-__setup("tgfx_2=", tgfx_setup_2);
-__setup("tgfx_3=", tgfx_setup_3);
-#endif
-
-int __init tgfx_init(void)
-{
- tgfx_base[0] = tgfx_probe(tgfx);
- tgfx_base[1] = tgfx_probe(tgfx_2);
- tgfx_base[2] = tgfx_probe(tgfx_3);
-
- if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
- return 0;
-
- return -ENODEV;
-}
-
-void __exit tgfx_exit(void)
-{
- int i, j;
-
- for (i = 0; i < 3; i++)
- if (tgfx_base[i]) {
- for (j = 0; j < 7; j++)
- if (tgfx_base[i]->sticks & (1 << j))
- input_unregister_device(tgfx_base[i]->dev + j);
- parport_unregister_device(tgfx_base[i]->pd);
- }
-}
-
-module_init(tgfx_init);
-module_exit(tgfx_exit);
+++ /dev/null
-/*
- * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
- *
- * Copyright (c) 1999-2000 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * Logitech WingMan Warrior joystick driver for Linux
- */
-
-/*
- * This program is free warftware; 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@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/slab.h>
-#include <linux/input.h>
-#include <linux/serio.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define WARRIOR_MAX_LENGTH 16
-static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
-static char *warrior_name = "Logitech WingMan Warrior";
-
-/*
- * Per-Warrior data.
- */
-
-struct warrior {
- struct input_dev dev;
- int idx, len;
- unsigned char data[WARRIOR_MAX_LENGTH];
-};
-
-/*
- * warrior_process_packet() decodes packets the driver receives from the
- * Warrior. It updates the data accordingly.
- */
-
-static void warrior_process_packet(struct warrior *warrior)
-{
- struct input_dev *dev = &warrior->dev;
- unsigned char *data = warrior->data;
-
- if (!warrior->idx) return;
-
- switch ((data[0] >> 4) & 7) {
- case 1: /* Button data */
- input_report_key(dev, BTN_TRIGGER, data[3] & 1);
- input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1);
- input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1);
- input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1);
- return;
- case 3: /* XY-axis info->data */
- input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
- input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
- return;
- case 5: /* Throttle, spinner, hat info->data */
- input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
- input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
- input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
- input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
- return;
- }
-}
-
-/*
- * warrior_interrupt() is called by the low level driver when characters
- * are ready for us. We then buffer them for further processing, or call the
- * packet processing routine.
- */
-
-static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
-{
- struct warrior* warrior = serio->private;
-
- if (data & 0x80) {
- if (warrior->idx) warrior_process_packet(warrior);
- warrior->idx = 0;
- warrior->len = warrior_lengths[(data >> 4) & 7];
- }
-
- if (warrior->idx < warrior->len)
- warrior->data[warrior->idx++] = data;
-
- if (warrior->idx == warrior->len) {
- if (warrior->idx) warrior_process_packet(warrior);
- warrior->idx = 0;
- warrior->len = 0;
- }
-}
-
-/*
- * warrior_disconnect() is the opposite of warrior_connect()
- */
-
-static void warrior_disconnect(struct serio *serio)
-{
- struct warrior* warrior = serio->private;
- input_unregister_device(&warrior->dev);
- serio_close(serio);
- kfree(warrior);
-}
-
-/*
- * warrior_connect() is the routine that is called when someone adds a
- * new serio device. It looks for the Warrior, and if found, registers
- * it as an input device.
- */
-
-static void warrior_connect(struct serio *serio, struct serio_dev *dev)
-{
- struct warrior *warrior;
- int i;
-
- if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
- return;
-
- if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
- return;
-
- memset(warrior, 0, sizeof(struct warrior));
-
- warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
- warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
- warrior->dev.relbit[0] = BIT(REL_DIAL);
- warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
-
- warrior->dev.name = warrior_name;
- warrior->dev.idbus = BUS_RS232;
- warrior->dev.idvendor = SERIO_WARRIOR;
- warrior->dev.idproduct = 0x0001;
- warrior->dev.idversion = 0x0100;
-
- for (i = 0; i < 2; i++) {
- warrior->dev.absmax[ABS_X+i] = -64;
- warrior->dev.absmin[ABS_X+i] = 64;
- warrior->dev.absflat[ABS_X+i] = 8;
- }
-
- warrior->dev.absmax[ABS_THROTTLE] = -112;
- warrior->dev.absmin[ABS_THROTTLE] = 112;
-
- for (i = 0; i < 2; i++) {
- warrior->dev.absmax[ABS_HAT0X+i] = -1;
- warrior->dev.absmin[ABS_HAT0X+i] = 1;
- }
-
- warrior->dev.private = warrior;
-
- serio->private = warrior;
-
- if (serio_open(serio, dev)) {
- kfree(warrior);
- return;
- }
-
- input_register_device(&warrior->dev);
-
- printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
-}
-
-/*
- * The serio device structure.
- */
-
-static struct serio_dev warrior_dev = {
- interrupt: warrior_interrupt,
- connect: warrior_connect,
- disconnect: warrior_disconnect,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-int __init warrior_init(void)
-{
- serio_register_device(&warrior_dev);
- return 0;
-}
-
-void __exit warrior_exit(void)
-{
- serio_unregister_device(&warrior_dev);
-}
-
-module_init(warrior_init);
-module_exit(warrior_exit);
-
-MODULE_LICENSE("GPL");
CONFIG_INPUT
- Say Y here if you want to enable any of the following options for
- USB Human Interface Device (HID) support.
+ Say Y here if you have any input device (mouse, keyboard, tablet,
+ joystick, steering wheel ...) connected to your system and want
+ it to be available to applications. This includes standard PS/2
+ keyboard and mouse.
- Say Y here if you want to enable any of the USB HID options in the
- USB support section which require Input core support.
+ Say N here if you have a headless (no monitor, no keyboard) system.
- Otherwise, say N.
+ More information is available: <file:Documentation/input/input.txt>
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called input.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_KEYBDEV
- Say Y here if you want your USB HID keyboard (or an ADB keyboard
- handled by the input layer) to be able to serve as a system
- keyboard.
+ Say Y here if you want your keyboard to be able to serve as a system
+ keyboard. This is needed in most cases. The only exceptions are
+ headless and embedded systems.
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
- The module will be called keybdev.o. If you want to compile it as a
+ The module will be called keybdev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_MOUSEDEV
- Say Y here if you want your USB HID mouse (or ADB mouse handled by
- the input layer) to be accessible as char devices 13:32+ -
- /dev/input/mouseX and 13:63 - /dev/input/mice as an emulated ImPS/2
- mouse. That way, all user space programs will be able to use your
+ Say Y here if you want your mouse to be accessible as char devices
+ 13:32+ - /dev/input/mouseX and 13:63 - /dev/input/mice as an
+ emulated IntelliMouse Explorer PS/2 mouse. That way, all user space
+ programs (includung SVGAlib, GPM and X) will be able to use your
mouse.
If unsure, say Y.
you're not using a digitizer, this value is ignored.
CONFIG_INPUT_JOYDEV
- Say Y here if you want your USB HID joystick or gamepad to be
+ Say Y here if you want your joystick or gamepad to be
accessible as char device 13:0+ - /dev/input/jsX device.
+ If unsure, say Y.
+
+ More information is available: <file:Documentation/input/joystick.txt>
+
This driver is also available as a module ( = code which can be
inserted in and removed from the running kernel whenever you want).
The module will be called joydev.o. If you want to compile it as a
module, say M here and read <file:Documentation/modules.txt>.
CONFIG_INPUT_EVDEV
- Say Y here if you want your USB or ADB HID device events be
- accessible under char device 13:64+ - /dev/input/eventX in a generic
- way. This is the future ...
+ Say Y here if you want your input device events be accessible
+ under char device 13:64+ - /dev/input/eventX in a generic way.
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called evdev.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
#
-# Input core configuration
+# Input device configuration
#
mainmenu_option next_comment
-comment 'Input core support'
+comment 'Input device support'
tristate 'Input core support' CONFIG_INPUT
-dep_tristate ' Keyboard support' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
-dep_tristate ' Mouse support' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
+dep_tristate ' Keyboard interface' CONFIG_INPUT_KEYBDEV $CONFIG_INPUT
+dep_tristate ' Mouse interface' CONFIG_INPUT_MOUSEDEV $CONFIG_INPUT
if [ "$CONFIG_INPUT_MOUSEDEV" != "n" ]; then
int ' Horizontal screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_X 1024
int ' Vertical screen resolution' CONFIG_INPUT_MOUSEDEV_SCREEN_Y 768
fi
-dep_tristate ' Joystick support' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
-dep_tristate ' Event interface support' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+dep_tristate ' Joystick interface' CONFIG_INPUT_JOYDEV $CONFIG_INPUT
+dep_tristate ' Event interface' CONFIG_INPUT_EVDEV $CONFIG_INPUT
+
+source drivers/input/gameport/Config.in
+source drivers/input/serio/Config.in
+
+if [ "$CONFIG_INPUT" != "n" ]; then
+ source drivers/input/joystick/Config.in
+fi
endmenu
# Objects that export symbols.
+mod-subdirs := joystick
export-objs := input.o
-# Object file lists.
-
-obj-y :=
-obj-m :=
-obj-n :=
-obj- :=
-
# Each configuration option enables a list of files.
obj-$(CONFIG_INPUT) += input.o
obj-$(CONFIG_INPUT_JOYDEV) += joydev.o
obj-$(CONFIG_INPUT_EVDEV) += evdev.o
+subdir-$(CONFIG_INPUT_JOYSTICK) += joystick
+
+ifeq ($(CONFIG_INPUT_JOYSTICK),y)
+ obj-y += joystick/joydrv.o
+endif
+
# The global Rules.make.
include $(TOPDIR)/Rules.make
--- /dev/null
+CONFIG_GAMEPORT
+ Gameport support is for the standard 15-pin PC gameport. If you
+ have a joystick, gamepad, gameport card, a soundcard with a gameport
+ or anything else that uses the gameport, say Y or M here and also to
+ at least one of the hardware specific drivers.
+
+ For Ensoniq AudioPCI (ES1370), AudioPCI 97 (ES1371), ESS Solo1,
+ S3 SonicVibes, Trident 4DWave, SiS7018, and ALi 5451 gameport
+ support is provided by the sound drivers, so you won't need any
+ from the below listed modules. You still need to say Y here.
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called gameport.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_NS558
+ Say Y here if you have an ISA or PnP gameport.
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called ns558.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_L4
+ Say Y here if you have a PDPI Lightning 4 gamecard.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called lightning.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_EMU10K1
+ Say Y here if you have a SoundBlaster Live! or SoundBlaster
+ Audigy card and want to use its gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called emu10k1-gp.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_PCIGAME
+ Say Y here if you have an Aureal Vortex 1 or 2 or a Trident
+ 4DWave NX or DX card and want to use its gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called pcigame.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_GAMEPORT_CS461X
+ Say Y here if you have a Cirrus CS461x aka "Crystal SoundFusion"
+ PCI audio accelerator and want to use its gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called cs461x.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
--- /dev/null
+#
+# Gameport configuration
+#
+
+tristate 'Gameport support' CONFIG_GAMEPORT
+
+if [ "$CONFIG_GAMEPORT" = "m" ]; then
+ define_tristate CONFIG_SOUND_GAMEPORT m
+fi
+if [ "$CONFIG_GAMEPORT" != "m" ]; then
+ define_tristate CONFIG_SOUND_GAMEPORT y
+fi
+
+dep_tristate ' Classic ISA and PnP gameport support' CONFIG_GAMEPORT_NS558 $CONFIG_GAMEPORT
+dep_tristate ' PDPI Lightning 4 gamecard support' CONFIG_GAMEPORT_L4 $CONFIG_GAMEPORT
+dep_tristate ' SB Live and Audigy gameport support' CONFIG_INPUT_EMU10K1 $CONFIG_GAMEPORT
+dep_tristate ' Aureal Vortex, Vortex 2 and Trident 4DWave NX/DX gameport support' CONFIG_GAMEPORT_PCIGAME $CONFIG_GAMEPORT
+dep_tristate ' ForteMedia FM801 gameport support' CONFIG_GAMEPORT_FM801 $CONFIG_GAMEPORT
+dep_tristate ' Crystal SoundFusion gameport support' CONFIG_GAMEPORT_CS461x $CONFIG_GAMEPORT
--- /dev/null
+#
+# Makefile for the gameport drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET := gamedrv.o
+
+# Objects that export symbols.
+
+export-objs := gameport.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_GAMEPORT) += gameport.o
+obj-$(CONFIG_GAMEPORT_CS461X) += cs461x.o
+obj-$(CONFIG_GAMEPORT_EMU10K1) += emu10k1-gp.o
+obj-$(CONFIG_GAMEPORT_L4) += lightning.o
+obj-$(CONFIG_GAMEPORT_NS558) += ns558.o
+obj-$(CONFIG_GAMEPORT_PCIGAME) += pcigame.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ The all defines and part of code (such as cs461x_*) are
+ contributed from ALSA 0.5.8 sources.
+ See http://www.alsa-project.org/ for sources
+
+ Tested on Linux 686 2.4.0-test9, ALSA 0.5.8a and CS4610
+*/
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Victor Krapivin <vik@belcaf.minsk.by>");
+MODULE_LICENSE("GPL");
+
+/*
+ These options are experimental
+
+#define CS461X_FULL_MAP
+*/
+
+#define COOKED_MODE
+
+
+#ifndef PCI_VENDOR_ID_CIRRUS
+#define PCI_VENDOR_ID_CIRRUS 0x1013
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4610
+#define PCI_DEVICE_ID_CIRRUS_4610 0x6001
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4612
+#define PCI_DEVICE_ID_CIRRUS_4612 0x6003
+#endif
+#ifndef PCI_DEVICE_ID_CIRRUS_4615
+#define PCI_DEVICE_ID_CIRRUS_4615 0x6004
+#endif
+
+/* Registers */
+
+#define BA0_JSPT 0x00000480
+#define BA0_JSCTL 0x00000484
+#define BA0_JSC1 0x00000488
+#define BA0_JSC2 0x0000048C
+#define BA0_JSIO 0x000004A0
+
+/* Bits for JSPT */
+
+#define JSPT_CAX 0x00000001
+#define JSPT_CAY 0x00000002
+#define JSPT_CBX 0x00000004
+#define JSPT_CBY 0x00000008
+#define JSPT_BA1 0x00000010
+#define JSPT_BA2 0x00000020
+#define JSPT_BB1 0x00000040
+#define JSPT_BB2 0x00000080
+
+/* Bits for JSCTL */
+
+#define JSCTL_SP_MASK 0x00000003
+#define JSCTL_SP_SLOW 0x00000000
+#define JSCTL_SP_MEDIUM_SLOW 0x00000001
+#define JSCTL_SP_MEDIUM_FAST 0x00000002
+#define JSCTL_SP_FAST 0x00000003
+#define JSCTL_ARE 0x00000004
+
+/* Data register pairs masks */
+
+#define JSC1_Y1V_MASK 0x0000FFFF
+#define JSC1_X1V_MASK 0xFFFF0000
+#define JSC1_Y1V_SHIFT 0
+#define JSC1_X1V_SHIFT 16
+#define JSC2_Y2V_MASK 0x0000FFFF
+#define JSC2_X2V_MASK 0xFFFF0000
+#define JSC2_Y2V_SHIFT 0
+#define JSC2_X2V_SHIFT 16
+
+/* JS GPIO */
+
+#define JSIO_DAX 0x00000001
+#define JSIO_DAY 0x00000002
+#define JSIO_DBX 0x00000004
+#define JSIO_DBY 0x00000008
+#define JSIO_AXOE 0x00000010
+#define JSIO_AYOE 0x00000020
+#define JSIO_BXOE 0x00000040
+#define JSIO_BYOE 0x00000080
+
+/*
+ The card initialization code is obfuscated; the module cs461x
+ need to be loaded after ALSA modules initialized and something
+ played on the CS 4610 chip (see sources for details of CS4610
+ initialization code from ALSA)
+*/
+
+/* Card specific definitions */
+
+#define CS461X_BA0_SIZE 0x2000
+#define CS461X_BA1_DATA0_SIZE 0x3000
+#define CS461X_BA1_DATA1_SIZE 0x3800
+#define CS461X_BA1_PRG_SIZE 0x7000
+#define CS461X_BA1_REG_SIZE 0x0100
+
+#define BA1_SP_DMEM0 0x00000000
+#define BA1_SP_DMEM1 0x00010000
+#define BA1_SP_PMEM 0x00020000
+#define BA1_SP_REG 0x00030000
+
+#define BA1_DWORD_SIZE (13 * 1024 + 512)
+#define BA1_MEMORY_COUNT 3
+
+/*
+ Only one CS461x card is still suppoted; the code requires
+ redesign to avoid this limitatuion.
+*/
+
+static unsigned long ba0_addr;
+static unsigned int *ba0;
+
+#ifdef CS461X_FULL_MAP
+static unsigned long ba1_addr;
+static union ba1_t {
+ struct {
+ unsigned int *data0;
+ unsigned int *data1;
+ unsigned int *pmem;
+ unsigned int *reg;
+ } name;
+ unsigned int *idx[4];
+} ba1;
+
+static void cs461x_poke(unsigned long reg, unsigned int val)
+{
+ ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff] = val;
+}
+
+static unsigned int cs461x_peek(unsigned long reg)
+{
+ return ba1.idx[(reg >> 16) & 3][(reg >> 2) & 0x3fff];
+}
+
+#endif
+
+static void cs461x_pokeBA0(unsigned long reg, unsigned int val)
+{
+ ba0[reg >> 2] = val;
+}
+
+static unsigned int cs461x_peekBA0(unsigned long reg)
+{
+ return ba0[reg >> 2];
+}
+
+static int cs461x_free(struct pci_dev *pdev)
+{
+ struct gameport *port = pci_get_drvdata(pdev);
+ if(port){
+ gameport_unregister_port(port);
+ kfree(port);
+ }
+ if (ba0) iounmap(ba0);
+#ifdef CS461X_FULL_MAP
+ if (ba1.name.data0) iounmap(ba1.name.data0);
+ if (ba1.name.data1) iounmap(ba1.name.data1);
+ if (ba1.name.pmem) iounmap(ba1.name.pmem);
+ if (ba1.name.reg) iounmap(ba1.name.reg);
+#endif
+ return 0;
+}
+
+static void cs461x_gameport_trigger(struct gameport *gameport)
+{
+ cs461x_pokeBA0(BA0_JSPT, 0xFF); //outb(gameport->io, 0xFF);
+}
+
+static unsigned char cs461x_gameport_read(struct gameport *gameport)
+{
+ return cs461x_peekBA0(BA0_JSPT); //inb(gameport->io);
+}
+
+static int cs461x_gameport_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ unsigned js1, js2, jst;
+
+ js1 = cs461x_peekBA0(BA0_JSC1);
+ js2 = cs461x_peekBA0(BA0_JSC2);
+ jst = cs461x_peekBA0(BA0_JSPT);
+
+ *buttons = (~jst >> 4) & 0x0F;
+
+ axes[0] = ((js1 & JSC1_Y1V_MASK) >> JSC1_Y1V_SHIFT) & 0xFFFF;
+ axes[1] = ((js1 & JSC1_X1V_MASK) >> JSC1_X1V_SHIFT) & 0xFFFF;
+ axes[2] = ((js2 & JSC2_Y2V_MASK) >> JSC2_Y2V_SHIFT) & 0xFFFF;
+ axes[3] = ((js2 & JSC2_X2V_MASK) >> JSC2_X2V_SHIFT) & 0xFFFF;
+
+ for(jst=0;jst<4;++jst)
+ if(axes[jst]==0xFFFF) axes[jst] = -1;
+ return 0;
+}
+
+static int cs461x_gameport_open(struct gameport *gameport, int mode)
+{
+ switch (mode) {
+#ifdef COOKED_MODE
+ case GAMEPORT_MODE_COOKED:
+ return 0;
+#endif
+ case GAMEPORT_MODE_RAW:
+ return 0;
+ default:
+ return -1;
+ }
+ return 0;
+}
+
+static struct pci_device_id cs461x_pci_tbl[] __devinitdata = {
+ { PCI_VENDOR_ID_CIRRUS, 0x6001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4610 */
+ { PCI_VENDOR_ID_CIRRUS, 0x6003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4612 */
+ { PCI_VENDOR_ID_CIRRUS, 0x6005, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* Cirrus CS4615 */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, cs461x_pci_tbl);
+
+static int __devinit cs461x_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int rc;
+ struct gameport* port;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR "cs461x: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
+ pdev->bus->number, pdev->devfn, rc);
+ return rc;
+ }
+
+ ba0_addr = pci_resource_start(pdev, 0);
+#ifdef CS461X_FULL_MAP
+ ba1_addr = pci_resource_start(pdev, 1);
+#endif
+ if (ba0_addr == 0 || ba0_addr == ~0
+#ifdef CS461X_FULL_MAP
+ || ba1_addr == 0 || ba1_addr == ~0
+#endif
+ ) {
+ printk(KERN_ERR "cs461x: wrong address - ba0 = 0x%lx\n", ba0_addr);
+#ifdef CS461X_FULL_MAP
+ printk(KERN_ERR "cs461x: wrong address - ba1 = 0x%lx\n", ba1_addr);
+#endif
+ cs461x_free(pdev);
+ return -ENOMEM;
+ }
+
+ ba0 = ioremap(ba0_addr, CS461X_BA0_SIZE);
+#ifdef CS461X_FULL_MAP
+ ba1.name.data0 = ioremap(ba1_addr + BA1_SP_DMEM0, CS461X_BA1_DATA0_SIZE);
+ ba1.name.data1 = ioremap(ba1_addr + BA1_SP_DMEM1, CS461X_BA1_DATA1_SIZE);
+ ba1.name.pmem = ioremap(ba1_addr + BA1_SP_PMEM, CS461X_BA1_PRG_SIZE);
+ ba1.name.reg = ioremap(ba1_addr + BA1_SP_REG, CS461X_BA1_REG_SIZE);
+
+ if (ba0 == NULL || ba1.name.data0 == NULL ||
+ ba1.name.data1 == NULL || ba1.name.pmem == NULL ||
+ ba1.name.reg == NULL) {
+ cs461x_free(pdev);
+ return -ENOMEM;
+ }
+#else
+ if (ba0 == NULL){
+ cs461x_free(pdev);
+ return -ENOMEM;
+ }
+#endif
+ printk(KERN_INFO "CS461x PCI: %lx[%d]\n",
+ ba0_addr, CS461X_BA0_SIZE);
+
+ if (!(port = kmalloc(sizeof(struct gameport), GFP_KERNEL))) {
+ printk(KERN_ERR "Memory allocation failed.\n");
+ cs461x_free(pdev);
+ return -ENOMEM;
+ }
+ memset(port, 0, sizeof(struct gameport));
+
+ pci_set_drvdata(pdev, port);
+
+ port->open = cs461x_gameport_open;
+ port->read = cs461x_gameport_read;
+ port->trigger = cs461x_gameport_trigger;
+#ifdef COOKED_MODE
+ port->cooked_read = cs461x_gameport_cooked_read;
+#endif
+
+ cs461x_pokeBA0(BA0_JSIO, 0xFF); // ?
+ cs461x_pokeBA0(BA0_JSCTL, JSCTL_SP_MEDIUM_SLOW);
+
+ gameport_register_port(port);
+
+ printk(KERN_INFO "gameport%d: CS461x Gameport speed %d kHz\n",
+ port->number, port->speed);
+
+ return 0;
+}
+
+static void __devexit cs461x_pci_remove(struct pci_dev *pdev)
+{
+ cs461x_free(pdev);
+}
+
+static struct pci_driver cs461x_pci_driver = {
+ name: "PCI Gameport",
+ id_table: cs461x_pci_tbl,
+ probe: cs461x_pci_probe,
+ remove: cs461x_pci_remove,
+};
+
+int __init js_cs461x_init(void)
+{
+ return pci_module_init(&cs461x_pci_driver);
+}
+
+void __exit js_cs461x_exit(void)
+{
+ pci_unregister_driver(&cs461x_pci_driver);
+}
+
+module_init(js_cs461x_init);
+module_exit(js_cs461x_exit);
+
--- /dev/null
+/*
+ * $Id: emu10k1-gp.c,v 1.2 2001/04/24 07:48:56 vojtech Exp $
+ *
+ * Copyright (c) 2001 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * EMU10k1 - SB Live! - gameport driver for Linux
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/pci.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+struct emu {
+ struct pci_dev *dev;
+ struct emu *next;
+ struct gameport gameport;
+ int size;
+};
+
+static struct pci_device_id emu_tbl[] __devinitdata = {
+ { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID }, /* SB Live! gameport */
+ { 0, }
+};
+
+MODULE_DEVICE_TABLE(pci, emu_tbl);
+
+static int __devinit emu_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ioport, iolen;
+ int rc;
+ struct emu *port;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR "emu10k1-gp: Cannot enable emu10k1 gameport (bus %d, devfn %d) error=%d\n",
+ pdev->bus->number, pdev->devfn, rc);
+ return rc;
+ }
+
+ ioport = pci_resource_start(pdev, 0);
+ iolen = pci_resource_len(pdev, 0);
+
+ if (!request_region(ioport, iolen, "emu10k1-gp"))
+ return -EBUSY;
+
+ if (!(port = kmalloc(sizeof(struct emu), GFP_KERNEL))) {
+ printk(KERN_ERR "emu10k1-gp: Memory allocation failed.\n");
+ release_region(ioport, iolen);
+ return -ENOMEM;
+ }
+ memset(port, 0, sizeof(struct emu));
+
+ port->gameport.io = ioport;
+ port->size = iolen;
+ port->dev = pdev;
+ pci_set_drvdata(pdev, port);
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: Emu10k1 Gameport at %#x size %d speed %d kHz\n",
+ port->gameport.number, port->gameport.io, iolen, port->gameport.speed);
+
+ return 0;
+}
+
+static void __devexit emu_remove(struct pci_dev *pdev)
+{
+ struct emu *port = pci_get_drvdata(pdev);
+ gameport_unregister_port(&port->gameport);
+ release_region(port->gameport.io, port->size);
+ kfree(port);
+}
+
+static struct pci_driver emu_driver = {
+ name: "Emu10k1 Gameport",
+ id_table: emu_tbl,
+ probe: emu_probe,
+ remove: emu_remove,
+};
+
+int __init emu_init(void)
+{
+ return pci_module_init(&emu_driver);
+}
+
+void __exit emu_exit(void)
+{
+ pci_unregister_driver(&emu_driver);
+}
+
+module_init(emu_init);
+module_exit(emu_exit);
--- /dev/null
+/*
+ * $Id: gameport.c,v 1.5 2000/05/29 10:54:53 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Generic gameport layer
+ */
+
+/*
+ * 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/module.h>
+#include <linux/ioport.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/isapnp.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(gameport_register_port);
+EXPORT_SYMBOL(gameport_unregister_port);
+EXPORT_SYMBOL(gameport_register_device);
+EXPORT_SYMBOL(gameport_unregister_device);
+EXPORT_SYMBOL(gameport_open);
+EXPORT_SYMBOL(gameport_close);
+EXPORT_SYMBOL(gameport_rescan);
+EXPORT_SYMBOL(gameport_cooked_read);
+
+static struct gameport *gameport_list;
+static struct gameport_dev *gameport_dev;
+static int gameport_number;
+
+/*
+ * gameport_measure_speed() measures the gameport i/o speed.
+ */
+
+static int gameport_measure_speed(struct gameport *gameport)
+{
+#if defined(__i386__) || defined(__x86_64__)
+
+#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;
+
+ if (gameport_open(gameport, NULL, GAMEPORT_MODE_RAW))
+ return 0;
+
+ 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++) gameport_read(gameport);
+ 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 / (tx < 1 ? 1 : tx);
+
+#else
+
+ unsigned int j, t = 0;
+
+ j = jiffies; while (j == jiffies);
+ j = jiffies; while (j == jiffies) { t++; gameport_read(gameport); }
+
+ return t * HZ / 1000;
+
+#endif
+
+ gameport_close(gameport);
+}
+
+static void gameport_find_dev(struct gameport *gameport)
+{
+ struct gameport_dev *dev = gameport_dev;
+
+ while (dev && !gameport->dev) {
+ if (dev->connect)
+ dev->connect(gameport, dev);
+ dev = dev->next;
+ }
+}
+
+void gameport_rescan(struct gameport *gameport)
+{
+ gameport_close(gameport);
+ gameport_find_dev(gameport);
+}
+
+void gameport_register_port(struct gameport *gameport)
+{
+ gameport->number = gameport_number++;
+ gameport->next = gameport_list;
+ gameport_list = gameport;
+
+ gameport->speed = gameport_measure_speed(gameport);
+
+ gameport_find_dev(gameport);
+}
+
+void gameport_unregister_port(struct gameport *gameport)
+{
+ struct gameport **gameportptr = &gameport_list;
+
+ while (*gameportptr && (*gameportptr != gameport)) gameportptr = &((*gameportptr)->next);
+ *gameportptr = (*gameportptr)->next;
+
+ if (gameport->dev && gameport->dev->disconnect)
+ gameport->dev->disconnect(gameport);
+
+ gameport_number--;
+}
+
+void gameport_register_device(struct gameport_dev *dev)
+{
+ struct gameport *gameport = gameport_list;
+
+ dev->next = gameport_dev;
+ gameport_dev = dev;
+
+ while (gameport) {
+ if (!gameport->dev && dev->connect)
+ dev->connect(gameport, dev);
+ gameport = gameport->next;
+ }
+}
+
+void gameport_unregister_device(struct gameport_dev *dev)
+{
+ struct gameport_dev **devptr = &gameport_dev;
+ struct gameport *gameport = gameport_list;
+
+ while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
+ *devptr = (*devptr)->next;
+
+ while (gameport) {
+ if (gameport->dev == dev && dev->disconnect)
+ dev->disconnect(gameport);
+ gameport_find_dev(gameport);
+ gameport = gameport->next;
+ }
+}
+
+int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
+{
+ if (gameport->open) {
+ if (gameport->open(gameport, mode))
+ return -1;
+ } else {
+ if (mode != GAMEPORT_MODE_RAW)
+ return -1;
+ }
+
+ if (gameport->dev)
+ return -1;
+
+ gameport->dev = dev;
+
+ return 0;
+}
+
+void gameport_close(struct gameport *gameport)
+{
+ gameport->dev = NULL;
+ if (gameport->close) gameport->close(gameport);
+}
--- /dev/null
+/*
+ * $Id: lightning.c,v 1.13 2001/04/26 10:24:46 vojtech Exp $
+ *
+ * Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * PDPI Lightning 4 gamecard driver for Linux.
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+
+#define L4_PORT 0x201
+#define L4_SELECT_ANALOG 0xa4
+#define L4_SELECT_DIGITAL 0xa5
+#define L4_SELECT_SECONDARY 0xa6
+#define L4_CMD_ID 0x80
+#define L4_CMD_GETCAL 0x92
+#define L4_CMD_SETCAL 0x93
+#define L4_ID 0x04
+#define L4_BUSY 0x01
+#define L4_TIMEOUT 80 /* 80 us */
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+
+struct l4 {
+ struct gameport gameport;
+ unsigned char port;
+} *l4_port[8];
+
+/*
+ * l4_wait_ready() waits for the L4 to become ready.
+ */
+
+static int l4_wait_ready(void)
+{
+ unsigned int t;
+ t = L4_TIMEOUT;
+ while ((inb(L4_PORT) & L4_BUSY) && t > 0) t--;
+ return -(t<=0);
+}
+
+/*
+ * l4_cooked_read() reads data from the Lightning 4.
+ */
+
+static int l4_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct l4 *l4 = gameport->private;
+ unsigned char status;
+ int i, result = -1;
+
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ outb(L4_SELECT_DIGITAL + (l4->port >> 2), L4_PORT);
+
+ if (inb(L4_PORT) & L4_BUSY) goto fail;
+ outb(l4->port & 3, L4_PORT);
+
+ if (l4_wait_ready()) goto fail;
+ status = inb(L4_PORT);
+
+ for (i = 0; i < 4; i++)
+ if (status & (1 << i)) {
+ if (l4_wait_ready()) goto fail;
+ axes[i] = inb(L4_PORT);
+ if (axes[i] > 252) axes[i] = -1;
+ }
+
+ if (status & 0x10) {
+ if (l4_wait_ready()) goto fail;
+ *buttons = inb(L4_PORT) & 0x0f;
+ }
+
+ result = 0;
+
+fail: outb(L4_SELECT_ANALOG, L4_PORT);
+ return result;
+}
+
+static int l4_open(struct gameport *gameport, int mode)
+{
+ struct l4 *l4 = gameport->private;
+ if (l4->port != 0 && mode != GAMEPORT_MODE_COOKED)
+ return -1;
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ return 0;
+}
+
+/*
+ * l4_getcal() reads the L4 with calibration values.
+ */
+
+static int l4_getcal(int port, int *cal)
+{
+ int i, result = -1;
+
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+
+ if (inb(L4_PORT) & L4_BUSY) goto fail;
+ outb(L4_CMD_GETCAL, L4_PORT);
+
+ if (l4_wait_ready()) goto fail;
+ if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+
+ if (l4_wait_ready()) goto fail;
+ outb(port & 3, L4_PORT);
+
+ for (i = 0; i < 4; i++) {
+ if (l4_wait_ready()) goto fail;
+ cal[i] = inb(L4_PORT);
+ }
+
+ result = 0;
+
+fail: outb(L4_SELECT_ANALOG, L4_PORT);
+ return result;
+}
+
+/*
+ * l4_setcal() programs the L4 with calibration values.
+ */
+
+static int l4_setcal(int port, int *cal)
+{
+ int i, result = -1;
+
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ outb(L4_SELECT_DIGITAL + (port >> 2), L4_PORT);
+
+ if (inb(L4_PORT) & L4_BUSY) goto fail;
+ outb(L4_CMD_SETCAL, L4_PORT);
+
+ if (l4_wait_ready()) goto fail;
+ if (inb(L4_PORT) != L4_SELECT_DIGITAL + (port >> 2)) goto fail;
+
+ if (l4_wait_ready()) goto fail;
+ outb(port & 3, L4_PORT);
+
+ for (i = 0; i < 4; i++) {
+ if (l4_wait_ready()) goto fail;
+ outb(cal[i], L4_PORT);
+ }
+
+ result = 0;
+
+fail: outb(L4_SELECT_ANALOG, L4_PORT);
+ return result;
+}
+
+/*
+ * l4_calibrate() calibrates the L4 for the attached device, so
+ * that the device's resistance fits into the L4's 8-bit range.
+ */
+
+static int l4_calibrate(struct gameport *gameport, int *axes, int *max)
+{
+ int i, t;
+ int cal[4];
+ struct l4 *l4 = gameport->private;
+
+ if (l4_getcal(l4->port, cal))
+ return -1;
+
+ for (i = 0; i < 4; i++) {
+ t = (max[i] * cal[i]) / 200;
+ t = (t < 1) ? 1 : ((t > 255) ? 255 : t);
+ axes[i] = (axes[i] < 0) ? -1 : (axes[i] * cal[i]) / t;
+ axes[i] = (axes[i] > 252) ? 252 : axes[i];
+ cal[i] = t;
+ }
+
+ if (l4_setcal(l4->port, cal))
+ return -1;
+
+ return 0;
+}
+
+int __init l4_init(void)
+{
+ int cal[4] = {255,255,255,255};
+ int i, j, rev, cards = 0;
+ struct gameport *gameport;
+ struct l4 *l4;
+
+ if (!request_region(L4_PORT, 1, "lightning"))
+ return -1;
+
+ for (i = 0; i < 2; i++) {
+
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ outb(L4_SELECT_DIGITAL + i, L4_PORT);
+
+ if (inb(L4_PORT) & L4_BUSY) continue;
+ outb(L4_CMD_ID, L4_PORT);
+
+ if (l4_wait_ready()) continue;
+ if (inb(L4_PORT) != L4_SELECT_DIGITAL + i) continue;
+
+ if (l4_wait_ready()) continue;
+ if (inb(L4_PORT) != L4_ID) continue;
+
+ if (l4_wait_ready()) continue;
+ rev = inb(L4_PORT);
+
+ if (!rev) continue;
+
+ if (!(l4_port[i * 4] = kmalloc(sizeof(struct l4) * 4, GFP_KERNEL))) {
+ printk(KERN_ERR "lightning: Out of memory allocating ports.\n");
+ continue;
+ }
+ memset(l4_port[i * 4], 0, sizeof(struct l4) * 4);
+
+ for (j = 0; j < 4; j++) {
+
+ l4 = l4_port[i * 4 + j] = l4_port[i * 4] + j;
+ l4->port = i * 4 + j;
+
+ gameport = &l4->gameport;
+ gameport->private = l4;
+ gameport->open = l4_open;
+ gameport->cooked_read = l4_cooked_read;
+ gameport->calibrate = l4_calibrate;
+
+ if (!i && !j)
+ gameport->io = L4_PORT;
+
+ if (rev > 0x28) /* on 2.9+ the setcal command works correctly */
+ l4_setcal(l4->port, cal);
+
+ gameport_register_port(gameport);
+ }
+
+ printk(KERN_INFO "gameport%d,%d,%d,%d: PDPI Lightning 4 %s card v%d.%d at %#x\n",
+ l4_port[i * 4 + 0]->gameport.number, l4_port[i * 4 + 1]->gameport.number,
+ l4_port[i * 4 + 2]->gameport.number, l4_port[i * 4 + 3]->gameport.number,
+ i ? "secondary" : "primary", rev >> 4, rev, L4_PORT);
+
+ cards++;
+ }
+
+ outb(L4_SELECT_ANALOG, L4_PORT);
+
+ if (!cards) {
+ release_region(L4_PORT, 1);
+ return -1;
+ }
+
+ return 0;
+}
+
+void __init l4_exit(void)
+{
+ int i;
+ int cal[4] = {59, 59, 59, 59};
+
+ for (i = 0; i < 8; i++)
+ if (l4_port[i]) {
+ l4_setcal(l4_port[i]->port, cal);
+ gameport_unregister_port(&l4_port[i]->gameport);
+ }
+ outb(L4_SELECT_ANALOG, L4_PORT);
+ release_region(L4_PORT, 1);
+}
+
+module_init(l4_init);
+module_exit(l4_exit);
--- /dev/null
+/*
+ * $Id: ns558.c,v 1.29 2001/04/24 07:48:56 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ * Copyright (c) 1999 Brian Gerst
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * NS558 based standard IBM game port driver for Linux
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/io.h>
+
+#include <linux/module.h>
+#include <linux/ioport.h>
+#include <linux/config.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/slab.h>
+#include <linux/isapnp.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+#define NS558_ISA 1
+#define NS558_PNP 2
+
+static int ns558_isa_portlist[] = { 0x200, 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+ 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
+
+struct ns558 {
+ int type;
+ int size;
+ struct pci_dev *dev;
+ struct ns558 *next;
+ struct gameport gameport;
+};
+
+static struct ns558 *ns558;
+
+/*
+ * ns558_isa_probe() tries to find an isa gameport at the
+ * specified address, and also checks for mirrors.
+ * A joystick must be attached for this to work.
+ */
+
+static struct ns558* ns558_isa_probe(int io, struct ns558 *next)
+{
+ int i, j, b;
+ unsigned char c, u, v;
+ struct ns558 *port;
+
+/*
+ * No one should be using this address.
+ */
+
+ if (check_region(io, 1))
+ return next;
+
+/*
+ * We must not be able to write arbitrary values to the port.
+ * The lower two axis bits must be 1 after a write.
+ */
+
+ c = inb(io);
+ outb(~c & ~3, io);
+ if (~(u = v = inb(io)) & 3) {
+ outb(c, io);
+ return next;
+ }
+/*
+ * After a trigger, there must be at least some bits changing.
+ */
+
+ for (i = 0; i < 1000; i++) v &= inb(io);
+
+ if (u == v) {
+ outb(c, io);
+ return next;
+ }
+ wait_ms(3);
+/*
+ * After some time (4ms) the axes shouldn't change anymore.
+ */
+
+ u = inb(io);
+ for (i = 0; i < 1000; i++)
+ if ((u ^ inb(io)) & 0xf) {
+ outb(c, io);
+ return next;
+ }
+/*
+ * And now find the number of mirrors of the port.
+ */
+
+ for (i = 1; i < 5; i++) {
+
+ if (check_region(io & (-1 << i), (1 << i))) /* Don't disturb anyone */
+ break;
+
+ outb(0xff, io & (-1 << i));
+ for (j = b = 0; j < 1000; j++)
+ if (inb(io & (-1 << i)) != inb((io & (-1 << i)) + (1 << i) - 1)) b++;
+ wait_ms(3);
+
+ if (b > 300) /* We allow 30% difference */
+ break;
+ }
+
+ i--;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "ns558: Memory allocation failed.\n");
+ return next;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_ISA;
+ port->size = (1 << i);
+ port->gameport.io = io & (-1 << i);
+
+ request_region(port->gameport.io, (1 << i), "ns558-isa");
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
+ if (port->size > 1) printk(" size %d", port->size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return port;
+}
+
+#ifdef __ISAPNP__
+
+static struct isapnp_device_id pnp_devids[] = {
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x0001), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('@','P','@'), ISAPNP_DEVICE(0x2001), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7001), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0010), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0110), 0 },
+ { ISAPNP_ANY_ID, ISAPNP_ANY_ID, ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f), 0 },
+ { 0, },
+};
+
+MODULE_DEVICE_TABLE(isapnp, pnp_devids);
+
+static struct ns558* ns558_pnp_probe(struct pci_dev *dev, struct ns558 *next)
+{
+ int ioport, iolen;
+ struct ns558 *port;
+
+ if (dev->prepare && dev->prepare(dev) < 0)
+ return next;
+
+ if (!(dev->resource[0].flags & IORESOURCE_IO)) {
+ printk(KERN_WARNING "ns558: No i/o ports on a gameport? Weird\n");
+ return next;
+ }
+
+ if (dev->activate && dev->activate(dev) < 0) {
+ printk(KERN_ERR "ns558: PnP resource allocation failed\n");
+ return next;
+ }
+
+ ioport = pci_resource_start(dev, 0);
+ iolen = pci_resource_len(dev, 0);
+
+ if (!request_region(ioport, iolen, "ns558-pnp"))
+ goto deactivate;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "ns558: Memory allocation failed.\n");
+ goto deactivate;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_PNP;
+ port->gameport.io = ioport;
+ port->size = iolen;
+ port->dev = dev;
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 PnP at %#x", port->gameport.number, port->gameport.io);
+ if (iolen > 1) printk(" size %d", iolen);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return port;
+
+deactivate:
+ if (dev->deactivate)
+ dev->deactivate(dev);
+ return next;
+}
+#endif
+
+int __init ns558_init(void)
+{
+ int i = 0;
+#ifdef __ISAPNP__
+ struct isapnp_device_id *devid;
+ struct pci_dev *dev = NULL;
+#endif
+
+/*
+ * Probe for ISA ports.
+ */
+
+ while (ns558_isa_portlist[i])
+ ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
+
+/*
+ * Probe for PnP ports.
+ */
+
+#ifdef __ISAPNP__
+ for (devid = pnp_devids; devid->vendor; devid++) {
+ while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->function, dev))) {
+ ns558 = ns558_pnp_probe(dev, ns558);
+ }
+ }
+#endif
+
+ return ns558 ? 0 : -ENODEV;
+}
+
+void __exit ns558_exit(void)
+{
+ struct ns558 *next, *port = ns558;
+
+ while (port) {
+ gameport_unregister_port(&port->gameport);
+ switch (port->type) {
+
+#ifdef __ISAPNP__
+ case NS558_PNP:
+ if (port->dev->deactivate)
+ port->dev->deactivate(port->dev);
+ /* fall through */
+#endif
+
+ case NS558_ISA:
+ release_region(port->gameport.io, port->size);
+ break;
+
+ default:
+ break;
+ }
+
+ next = port->next;
+ kfree(port);
+ port = next;
+ }
+}
+
+module_init(ns558_init);
+module_exit(ns558_exit);
--- /dev/null
+/*
+ * $Id: pcigame.c,v 1.10 2001/04/26 10:24:46 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Raymond Ingles
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Trident 4DWave and Aureal Vortex gameport driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gameport.h>
+
+#define PCI_VENDOR_ID_AUREAL 0x12eb
+
+#define PCIGAME_DATA_WAIT 20 /* 20 ms */
+
+#define PCIGAME_4DWAVE 0
+#define PCIGAME_VORTEX 1
+#define PCIGAME_VORTEX2 2
+
+struct pcigame_data {
+ int gcr; /* Gameport control register */
+ int legacy; /* Legacy port location */
+ int axes; /* Axes start */
+ int axsize; /* Axis field size */
+ int axmax; /* Axis field max value */
+ int adcmode; /* Value to enable ADC mode in GCR */
+};
+
+static struct pcigame_data pcigame_data[] __devinitdata =
+{{ 0x00030, 0x00031, 0x00034, 2, 0xffff, 0x80 },
+ { 0x1100c, 0x11008, 0x11010, 4, 0x1fff, 0x40 },
+ { 0x2880c, 0x28808, 0x28810, 4, 0x1fff, 0x40 },
+ { 0 }};
+
+struct pcigame {
+ struct gameport gameport;
+ struct pci_dev *dev;
+ unsigned char *base;
+ struct pcigame_data *data;
+};
+
+static unsigned char pcigame_read(struct gameport *gameport)
+{
+ struct pcigame *pcigame = gameport->private;
+ return readb(pcigame->base + pcigame->data->legacy);
+}
+
+static void pcigame_trigger(struct gameport *gameport)
+{
+ struct pcigame *pcigame = gameport->private;
+ writeb(0xff, pcigame->base + pcigame->data->legacy);
+}
+
+static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct pcigame *pcigame = gameport->private;
+ int i;
+
+ *buttons = (~readb(pcigame->base + pcigame->data->legacy) >> 4) & 0xf;
+
+ for (i = 0; i < 4; i++) {
+ axes[i] = readw(pcigame->base + pcigame->data->axes + i * pcigame->data->axsize);
+ if (axes[i] == pcigame->data->axmax) axes[i] = -1;
+ }
+
+ return 0;
+}
+
+static int pcigame_open(struct gameport *gameport, int mode)
+{
+ struct pcigame *pcigame = gameport->private;
+
+ switch (mode) {
+ case GAMEPORT_MODE_COOKED:
+ writeb(pcigame->data->adcmode, pcigame->base + pcigame->data->gcr);
+ wait_ms(PCIGAME_DATA_WAIT);
+ return 0;
+ case GAMEPORT_MODE_RAW:
+ writeb(0, pcigame->base + pcigame->data->gcr);
+ return 0;
+ default:
+ return -1;
+ }
+
+ return 0;
+}
+
+static int __devinit pcigame_probe(struct pci_dev *dev, const struct pci_device_id *id)
+{
+ struct pcigame *pcigame;
+ int i;
+
+ if (!(pcigame = kmalloc(sizeof(struct pcigame), GFP_KERNEL)))
+ return -1;
+ memset(pcigame, 0, sizeof(struct pcigame));
+
+
+ pcigame->data = pcigame_data + id->driver_data;
+
+ pcigame->dev = dev;
+ pci_set_drvdata(dev, pcigame);
+
+ pcigame->gameport.private = pcigame;
+ pcigame->gameport.fuzz = 64;
+
+ pcigame->gameport.read = pcigame_read;
+ pcigame->gameport.trigger = pcigame_trigger;
+ pcigame->gameport.cooked_read = pcigame_cooked_read;
+ pcigame->gameport.open = pcigame_open;
+
+ for (i = 0; i < 6; i++)
+ if (~pci_resource_flags(dev, i) & IORESOURCE_IO)
+ break;
+
+ pci_enable_device(dev);
+
+ pcigame->base = ioremap(pci_resource_start(pcigame->dev, i),
+ pci_resource_len(pcigame->dev, i));
+
+ gameport_register_port(&pcigame->gameport);
+
+ printk(KERN_INFO "gameport%d: %s at pci%02x:%02x.%x speed %d kHz\n",
+ pcigame->gameport.number, dev->name, dev->bus->number,
+ PCI_SLOT(dev->devfn), PCI_FUNC(dev->devfn), pcigame->gameport.speed);
+
+ return 0;
+}
+
+static void __devexit pcigame_remove(struct pci_dev *dev)
+{
+ struct pcigame *pcigame = pci_get_drvdata(dev);
+ gameport_unregister_port(&pcigame->gameport);
+ iounmap(pcigame->base);
+ kfree(pcigame);
+}
+
+static struct pci_device_id pcigame_id_table[] __devinitdata =
+{{ PCI_VENDOR_ID_TRIDENT, 0x2000, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
+ { PCI_VENDOR_ID_TRIDENT, 0x2001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_4DWAVE },
+ { PCI_VENDOR_ID_AUREAL, 0x0001, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX },
+ { PCI_VENDOR_ID_AUREAL, 0x0002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, PCIGAME_VORTEX2 },
+ { 0 }};
+
+static struct pci_driver pcigame_driver = {
+ name: "pcigame",
+ id_table: pcigame_id_table,
+ probe: pcigame_probe,
+ remove: pcigame_remove,
+};
+
+int __init pcigame_init(void)
+{
+ return pci_module_init(&pcigame_driver);
+}
+
+void __exit pcigame_exit(void)
+{
+ pci_unregister_driver(&pcigame_driver);
+}
+
+module_init(pcigame_init);
+module_exit(pcigame_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+CONFIG_JOYSTICK
+ If you have a joystick, 6dof controller, gamepad, steering wheel,
+ weapon control system or something like that you can say Y here
+ and the list of supported devices will be displayed. This option
+ doesn't affect the kernel.
+
+ Please read the file <file:Documentation/input/joystick.txt> which
+ contains more information.
+
+CONFIG_JOYSTICK_ANALOG
+ Say Y here if you have a joystick that connects to the PC
+ gameport. In addition to the usual PC analog joystick, this driver
+ supports many extensions, including joysticks with throttle control,
+ with rudders, additional hats and buttons compatible with CH
+ Flightstick Pro, ThrustMaster FCS, 6 and 8 button gamepads, or
+ Saitek Cyborg joysticks.
+
+ Please read the file <file:Documentation/input/joystick.txt> which
+ contains more information.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called analog.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_A3D
+ Say Y here if you have an FPGaming or MadCatz controller using the
+ A3D protocol over the PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called a3d.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_ADI
+ Say Y here if you have a Logitech controller using the ADI
+ protocol over the PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called adi.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_COBRA
+ Say Y here if you have a Creative Labs Blaster Cobra gamepad.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called cobra.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GF2K
+ Say Y here if you have a Genius Flight2000 or MaxFighter digitally
+ communicating joystick or gamepad.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called gf2k.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GRIP
+ Say Y here if you have a Gravis controller using the GrIP protocol
+ over the PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called grip.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_INTERACT
+ Say Y here if you have an InterAct gameport or joystick
+ communicating digitally over the gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called interact.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SIDEWINDER
+ Say Y here if you have a Microsoft controller using the Digital
+ Overdrive protocol over PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called sidewinder.o. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_TMDC
+ Say Y here if you have a ThrustMaster controller using the
+ DirectConnect (BSP) protocol over the PC gameport.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called tmdc.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_IFORCE_USB
+ Say Y here if you have an I-Force joystick or steering wheel
+ connected to your USB port.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called iforce.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_IFORCE_232
+ Say Y here if you have an I-Force joystick or steering wheel
+ connected to your serial (COM) port.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called iforce.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_WARRIOR
+ Say Y here if you have a Logitech WingMan Warrior joystick connected
+ to your computer's serial port.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called warrior.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_MAGELLAN
+ Say Y here if you have a Magellan or Space Mouse 6DOF controller
+ connected to your computer's serial port.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called magellan.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SPACEORB
+ Say Y here if you have a SpaceOrb 360 or SpaceBall Avenger 6DOF
+ controller connected to your computer's serial port.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called spaceorb.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_SPACEBALL
+ Say Y here if you have a SpaceTec SpaceBall 2003/3003/4000 FLX
+ controller connected to your computer's serial port. For the
+ SpaceBall 4000 USB model, use the USB HID driver.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called spaceball.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_STINGER
+ Say Y here if you have a Gravis Stinger connected to one of your
+ serial ports.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called stinger.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_DB9
+ Say Y here if you have a Sega Master System gamepad, Sega Genesis
+ gamepad, Sega Saturn gamepad, or a Multisystem -- Atari, Amiga,
+ Commodore, Amstrad CPC joystick connected to your parallel port.
+ For more information on how to use the driver please read
+ <file:Documentation/input/joystick-parport.txt>.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called db9.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_GAMECON
+ Say Y here if you have a Nintendo Entertainment System gamepad,
+ Super Nintendo Entertainment System gamepad, Nintendo 64 gamepad,
+ Sony PlayStation gamepad or a Multisystem -- Atari, Amiga,
+ Commodore, Amstrad CPC joystick connected to your parallel port.
+ For more information on how to use the driver please read
+ <file:Documentation/input/joystick-parport.txt>.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called gamecon.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_TURBOGRAFX
+ Say Y here if you have the TurboGraFX interface by Steffen Schwenke,
+ and want to use it with Multisystem -- Atari, Amiga, Commodore,
+ Amstrad CPC joystick. For more information on how to use the driver
+ please read <file:Documentation/input/joystick-parport.txt>.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called turbografx.o. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_JOYSTICK_AMIJOY
+ Say Y here if you have an Amiga with a digital joystick connected
+ to it.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called joy-amiga.o. If you want to compile it as
+ a module, say M here and read <file:Documentation/modules.txt>.
+
--- /dev/null
+#
+# Joystick driver configuration
+#
+
+bool 'Joysticks' CONFIG_INPUT_JOYSTICK
+
+dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOYSTICK_ANALOG $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_JOYSTICK_A3D $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_JOYSTICK_ADI $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_JOYSTICK_COBRA $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_JOYSTICK_GF2K $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOYSTICK_GRIP $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_JOYSTICK_INTERACT $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_JOYSTICK_SIDEWINDER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOYSTICK_TMDC $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_GAMEPORT
+
+dep_tristate ' I-Force USB joysticks and wheels' CONFIG_JOYSTICK_IFORCE_USB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_USB
+dep_tristate ' I-Force Serial joysticks and wheels' CONFIG_JOYSTICK_IFORCE_232 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_JOYSTICK_WARRIOR $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controllers' CONFIG_JOYSTICK_MAGELLAN $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controllers' CONFIG_JOYSTICK_SPACEORB $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' SpaceTec SpaceBall 6dof controllers' CONFIG_JOYSTICK_SPACEBALL $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+dep_tristate ' Gravis Stinger gamepad' CONFIG_JOYSTICK_STINGER $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_SERIO
+
+dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_JOYSTICK_DB9 $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_JOYSTICK_GAMECON $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_JOYSTICK_TURBOGRAFX $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK $CONFIG_PARPORT
+
+if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga joysticks' CONFIG_JOYSTICK_AMIJOY $CONFIG_INPUT $CONFIG_INPUT_JOYSTICK
+fi
--- /dev/null
+#
+# Makefile for the input core drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET := joydrv.o
+
+# I-Force may need both USB and RS-232
+
+CONFIG_JOYSTICK_IFORCE := n
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),y)
+ ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),y)
+ CONFIG_JOYSTICK_IFORCE := y
+ endif
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_232),m)
+ CONFIG_JOYSTICK_IFORCE := m
+endif
+
+ifeq ($(CONFIG_JOYSTICK_IFORCE_USB),m)
+ CONFIG_JOYSTICK_IFORCE := m
+endif
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_JOYSTICK_A3D) += a3d.o
+obj-$(CONFIG_JOYSTICK_ADI) += adi.o
+obj-$(CONFIG_JOYSTICK_AMIGA) += amijoy.o
+obj-$(CONFIG_JOYSTICK_ANALOG) += analog.o
+obj-$(CONFIG_JOYSTICK_COBRA) += cobra.o
+obj-$(CONFIG_JOYSTICK_DB9) += db9.o
+obj-$(CONFIG_JOYSTICK_GAMECON) += gamecon.o
+obj-$(CONFIG_JOYSTICK_GF2K) += gf2k.o
+obj-$(CONFIG_JOYSTICK_GRIP) += grip.o
+obj-$(CONFIG_JOYSTICK_IFORCE) += iforce.o
+obj-$(CONFIG_JOYSTICK_INTERACT) += interact.o
+obj-$(CONFIG_JOYSTICK_MAGELLAN) += magellan.o
+obj-$(CONFIG_JOYSTICK_SIDEWINDER) += sidewinder.o
+obj-$(CONFIG_JOYSTICK_SPACEBALL) += spaceball.o
+obj-$(CONFIG_JOYSTICK_SPACEORB) += spaceorb.o
+obj-$(CONFIG_JOYSTICK_STINGER) += stinger.o
+obj-$(CONFIG_JOYSTICK_TMDC) += tmdc.o
+obj-$(CONFIG_JOYSTICK_TURBOGRAFX) += turbografx.o
+obj-$(CONFIG_JOYSTICK_WARRIOR) += warrior.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * $Id: a3d.c,v 1.14 2001/04/26 10:24:46 vojtech Exp $
+ *
+ * Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * FP-Gaming Assasin 3D joystick driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define A3D_MAX_START 400 /* 400 us */
+#define A3D_MAX_STROBE 60 /* 40 us */
+#define A3D_DELAY_READ 3 /* 3 ms */
+#define A3D_MAX_LENGTH 40 /* 40*3 bits */
+#define A3D_REFRESH_TIME HZ/50 /* 20 ms */
+
+#define A3D_MODE_A3D 1 /* Assassin 3D */
+#define A3D_MODE_PAN 2 /* Panther */
+#define A3D_MODE_OEM 3 /* Panther OEM version */
+#define A3D_MODE_PXL 4 /* Panther XL */
+
+char *a3d_names[] = { NULL, "FP-Gaming Assassin 3D", "MadCatz Panther", "OEM Panther",
+ "MadCatz Panther XL", "MadCatz Panther XL w/ rudder" };
+
+struct a3d {
+ struct gameport *gameport;
+ struct gameport adc;
+ struct input_dev dev;
+ struct timer_list timer;
+ int axes[4];
+ int buttons;
+ int mode;
+ int length;
+ int used;
+ int reads;
+ int bads;
+};
+
+/*
+ * a3d_read_packet() reads an Assassin 3D packet.
+ */
+
+static int a3d_read_packet(struct gameport *gameport, int length, char *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t, s;
+ int i;
+
+ i = 0;
+ t = gameport_time(gameport, A3D_MAX_START);
+ s = gameport_time(gameport, A3D_MAX_STROBE);
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);
+
+ while (t > 0 && i < length) {
+ t--;
+ u = v; v = gameport_read(gameport);
+ if (~v & u & 0x10) {
+ data[i++] = v >> 5;
+ t = s;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * a3d_csum() computes checksum of triplet packet
+ */
+
+static int a3d_csum(char *data, int count)
+{
+ int i, csum = 0;
+ for (i = 0; i < count - 2; i++) csum += data[i];
+ return (csum & 0x3f) != ((data[count - 2] << 3) | data[count - 1]);
+}
+
+static void a3d_read(struct a3d *a3d, unsigned char *data)
+{
+ struct input_dev *dev = &a3d->dev;
+
+ switch (a3d->mode) {
+
+ case A3D_MODE_A3D:
+ case A3D_MODE_OEM:
+ case A3D_MODE_PAN:
+
+ input_report_rel(dev, REL_X, ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7));
+ input_report_rel(dev, REL_Y, ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7));
+
+ input_report_key(dev, BTN_RIGHT, data[2] & 1);
+ input_report_key(dev, BTN_LEFT, data[3] & 2);
+ input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+
+ a3d->axes[0] = ((signed char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
+ a3d->axes[1] = ((signed char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
+ a3d->axes[2] = ((signed char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
+ a3d->axes[3] = ((signed char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
+
+ a3d->buttons = ((data[3] << 3) | data[4]) & 0xf;
+
+ return;
+
+ case A3D_MODE_PXL:
+
+ input_report_rel(dev, REL_X, ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7));
+ input_report_rel(dev, REL_Y, ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7));
+
+ input_report_key(dev, BTN_RIGHT, data[2] & 1);
+ input_report_key(dev, BTN_LEFT, data[3] & 2);
+ input_report_key(dev, BTN_MIDDLE, data[3] & 4);
+ input_report_key(dev, BTN_SIDE, data[7] & 2);
+ input_report_key(dev, BTN_EXTRA, data[7] & 4);
+
+ input_report_abs(dev, ABS_X, ((signed char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128);
+ input_report_abs(dev, ABS_Y, ((signed char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128);
+ input_report_abs(dev, ABS_RUDDER, ((signed char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128);
+ input_report_abs(dev, ABS_THROTTLE, ((signed char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128);
+
+ input_report_abs(dev, ABS_HAT0X, ( data[5] & 1) - ((data[5] >> 2) & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1));
+ input_report_abs(dev, ABS_HAT1X, ((data[4] >> 1) & 1) - ( data[3] & 1));
+ input_report_abs(dev, ABS_HAT1Y, ((data[4] >> 2) & 1) - ( data[4] & 1));
+
+ input_report_key(dev, BTN_TRIGGER, data[8] & 1);
+ input_report_key(dev, BTN_THUMB, data[8] & 2);
+ input_report_key(dev, BTN_TOP, data[8] & 4);
+ input_report_key(dev, BTN_PINKIE, data[7] & 1);
+
+ return;
+ }
+}
+
+
+/*
+ * a3d_timer() reads and analyzes A3D joystick data.
+ */
+
+static void a3d_timer(unsigned long private)
+{
+ struct a3d *a3d = (void *) private;
+ unsigned char data[A3D_MAX_LENGTH];
+ a3d->reads++;
+ if (a3d_read_packet(a3d->gameport, a3d->length, data) != a3d->length
+ || data[0] != a3d->mode || a3d_csum(data, a3d->length))
+ a3d->bads++; else a3d_read(a3d, data);
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+}
+
+/*
+ * a3d_adc_cooked_read() copies the acis and button data to the
+ * callers arrays. It could do the read itself, but the caller could
+ * call this more than 50 times a second, which would use too much CPU.
+ */
+
+int a3d_adc_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct a3d *a3d = gameport->private;
+ int i;
+ for (i = 0; i < 4; i++)
+ axes[i] = (a3d->axes[i] < 254) ? a3d->axes[i] : -1;
+ *buttons = a3d->buttons;
+ return 0;
+}
+
+/*
+ * a3d_adc_open() is the gameport open routine. It refuses to serve
+ * any but cooked data.
+ */
+
+int a3d_adc_open(struct gameport *gameport, int mode)
+{
+ struct a3d *a3d = gameport->private;
+ if (mode != GAMEPORT_MODE_COOKED)
+ return -1;
+ if (!a3d->used++)
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * a3d_adc_close() is a callback from the input close routine.
+ */
+
+static void a3d_adc_close(struct gameport *gameport)
+{
+ struct a3d *a3d = gameport->private;
+ if (!--a3d->used)
+ del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_open() is a callback from the input open routine.
+ */
+
+static int a3d_open(struct input_dev *dev)
+{
+ struct a3d *a3d = dev->private;
+ if (!a3d->used++)
+ mod_timer(&a3d->timer, jiffies + A3D_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * a3d_close() is a callback from the input close routine.
+ */
+
+static void a3d_close(struct input_dev *dev)
+{
+ struct a3d *a3d = dev->private;
+ if (!--a3d->used)
+ del_timer(&a3d->timer);
+}
+
+/*
+ * a3d_connect() probes for A3D joysticks.
+ */
+
+static void a3d_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct a3d *a3d;
+ unsigned char data[A3D_MAX_LENGTH];
+ int i;
+
+ if (!(a3d = kmalloc(sizeof(struct a3d), GFP_KERNEL)))
+ return;
+ memset(a3d, 0, sizeof(struct a3d));
+
+ gameport->private = a3d;
+
+ a3d->gameport = gameport;
+ init_timer(&a3d->timer);
+ a3d->timer.data = (long) a3d;
+ a3d->timer.function = a3d_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ i = a3d_read_packet(gameport, A3D_MAX_LENGTH, data);
+
+ if (!i || a3d_csum(data, i))
+ goto fail2;
+
+ a3d->mode = data[0];
+
+ if (!a3d->mode || a3d->mode > 5) {
+ printk(KERN_WARNING "a3d.c: Unknown A3D device detected "
+ "(gameport%d, id=%d), contact <vojtech@suse.cz>\n", gameport->number, a3d->mode);
+ goto fail2;
+ }
+
+
+ if (a3d->mode == A3D_MODE_PXL) {
+
+ int axes[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER };
+
+ a3d->length = 33;
+
+ a3d->dev.evbit[0] |= BIT(EV_ABS) | BIT(EV_KEY) | BIT(EV_REL);
+ a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+ a3d->dev.absbit[0] |= BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_RUDDER)
+ | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y) | BIT(ABS_HAT1X) | BIT(ABS_HAT1Y);
+
+ a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE)
+ | BIT(BTN_SIDE) | BIT(BTN_EXTRA);
+
+ a3d->dev.keybit[LONG(BTN_JOYSTICK)] |= BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_PINKIE);
+
+ a3d_read(a3d, data);
+
+ for (i = 0; i < 4; i++) {
+ if (i < 2) {
+ a3d->dev.absmin[axes[i]] = 48;
+ a3d->dev.absmax[axes[i]] = a3d->dev.abs[axes[i]] * 2 - 48;
+ a3d->dev.absflat[axes[i]] = 8;
+ } else {
+ a3d->dev.absmin[axes[i]] = 2;
+ a3d->dev.absmax[axes[i]] = 253;
+ }
+ a3d->dev.absmin[ABS_HAT0X + i] = -1;
+ a3d->dev.absmax[ABS_HAT0X + i] = 1;
+ }
+
+ } else {
+ a3d->length = 29;
+
+ a3d->dev.evbit[0] |= BIT(EV_KEY) | BIT(EV_REL);
+ a3d->dev.relbit[0] |= BIT(REL_X) | BIT(REL_Y);
+ a3d->dev.keybit[LONG(BTN_MOUSE)] |= BIT(BTN_RIGHT) | BIT(BTN_LEFT) | BIT(BTN_MIDDLE);
+
+ a3d->adc.private = a3d;
+ a3d->adc.open = a3d_adc_open;
+ a3d->adc.close = a3d_adc_close;
+ a3d->adc.cooked_read = a3d_adc_cooked_read;
+ a3d->adc.fuzz = 1;
+
+ a3d_read(a3d, data);
+
+ gameport_register_port(&a3d->adc);
+ printk(KERN_INFO "gameport%d: %s on gameport%d.0\n",
+ a3d->adc.number, a3d_names[a3d->mode], gameport->number);
+ }
+
+ a3d->dev.private = a3d;
+ a3d->dev.open = a3d_open;
+ a3d->dev.close = a3d_close;
+
+ a3d->dev.name = a3d_names[a3d->mode];
+ a3d->dev.idbus = BUS_GAMEPORT;
+ a3d->dev.idvendor = GAMEPORT_ID_VENDOR_MADCATZ;
+ a3d->dev.idproduct = a3d->mode;
+ a3d->dev.idversion = 0x0100;
+
+ input_register_device(&a3d->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ a3d->dev.number, a3d_names[a3d->mode], gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(a3d);
+}
+
+static void a3d_disconnect(struct gameport *gameport)
+{
+
+ struct a3d *a3d = gameport->private;
+ input_unregister_device(&a3d->dev);
+ if (a3d->mode < A3D_MODE_PXL)
+ gameport_unregister_port(&a3d->adc);
+ gameport_close(gameport);
+ kfree(a3d);
+}
+
+static struct gameport_dev a3d_dev = {
+ connect: a3d_connect,
+ disconnect: a3d_disconnect,
+};
+
+int __init a3d_init(void)
+{
+ gameport_register_device(&a3d_dev);
+ return 0;
+}
+
+void __exit a3d_exit(void)
+{
+ gameport_unregister_device(&a3d_dev);
+}
+
+module_init(a3d_init);
+module_exit(a3d_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: adi.c,v 1.15 2001/01/09 13:32:39 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Logitech ADI joystick family driver for Linux
+ */
+
+/*
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/string.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+#include <linux/init.h>
+
+/*
+ * Times, array sizes, flags, ids.
+ */
+
+#define ADI_MAX_START 200 /* Trigger to packet timeout [200us] */
+#define ADI_MAX_STROBE 40 /* Single bit timeout [40us] */
+#define ADI_REFRESH_TIME HZ/50 /* How often to poll the joystick [20 ms] */
+#define ADI_INIT_DELAY 10 /* Delay after init packet [10ms] */
+#define ADI_DATA_DELAY 4 /* Delay after data packet [4ms] */
+
+#define ADI_MAX_LENGTH 256
+#define ADI_MIN_LENGTH 8
+#define ADI_MIN_LEN_LENGTH 10
+#define ADI_MIN_ID_LENGTH 66
+#define ADI_MAX_NAME_LENGTH 48
+#define ADI_MAX_CNAME_LENGTH 16
+
+#define ADI_FLAG_HAT 0x04
+#define ADI_FLAG_10BIT 0x08
+
+#define ADI_ID_TPD 0x01
+#define ADI_ID_WGP 0x06
+#define ADI_ID_WGPE 0x08
+#define ADI_ID_MAX 0x0a
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *adi_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" };
+
+static char adi_wmgpe_abs[] = { ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y };
+static char adi_wmi_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static char adi_wmed3d_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RZ, ABS_HAT0X, ABS_HAT0Y };
+static char adi_cm2_abs[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+static char adi_wmf_abs[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+
+static short adi_wmgpe_key[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT };
+static short adi_wmi_key[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_EXTRA };
+static short adi_wmed3d_key[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2 };
+static short adi_cm2_key[] = { BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8 };
+
+static char* adi_abs[] = { adi_wmi_abs, adi_wmgpe_abs, adi_wmf_abs, adi_cm2_abs, adi_wmi_abs, adi_wmf_abs,
+ adi_wmgpe_abs, adi_wmed3d_abs, adi_wmgpe_abs, adi_wmgpe_abs, adi_wmi_abs };
+
+static short* adi_key[] = { adi_wmi_key, adi_wmgpe_key, adi_cm2_key, adi_cm2_key, adi_wmi_key, adi_cm2_key,
+ adi_wmgpe_key, adi_wmed3d_key, adi_wmgpe_key, adi_wmgpe_key, adi_wmi_key };
+
+/*
+ * Hat to axis conversion arrays.
+ */
+
+static struct {
+ int x;
+ int y;
+} adi_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 adi {
+ struct input_dev dev;
+ int length;
+ int ret;
+ int idx;
+ unsigned char id;
+ char buttons;
+ char axes10;
+ char axes8;
+ signed char pad;
+ char hats;
+ char *abs;
+ short *key;
+ char name[ADI_MAX_NAME_LENGTH];
+ char cname[ADI_MAX_CNAME_LENGTH];
+ unsigned char data[ADI_MAX_LENGTH];
+};
+
+struct adi_port {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct adi adi[2];
+ int bad;
+ int reads;
+ int used;
+};
+
+/*
+ * adi_read_packet() reads a Logitech ADI packet.
+ */
+
+static void adi_read_packet(struct adi_port *port)
+{
+ struct adi *adi = port->adi;
+ struct gameport *gameport = port->gameport;
+ unsigned char u, v, w, x, z;
+ int t[2], s[2], i;
+ unsigned long flags;
+
+ for (i = 0; i < 2; i++) {
+ adi[i].ret = -1;
+ t[i] = gameport_time(gameport, ADI_MAX_START);
+ s[i] = 0;
+ }
+
+ __save_flags(flags);
+ __cli();
+
+ gameport_trigger(gameport);
+ v = z = gameport_read(gameport);
+
+ do {
+ u = v;
+ w = u ^ (v = x = gameport_read(gameport));
+ for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
+ t[i]--;
+ if ((w & 0x30) && s[i]) {
+ if ((w & 0x30) < 0x30 && adi[i].ret < ADI_MAX_LENGTH && t[i] > 0) {
+ adi[i].data[++adi[i].ret] = w;
+ t[i] = gameport_time(gameport, ADI_MAX_STROBE);
+ } else t[i] = 0;
+ } else if (!(x & 0x30)) s[i] = 1;
+ }
+ } while (t[0] > 0 || t[1] > 0);
+
+ __restore_flags(flags);
+
+ return;
+}
+
+/*
+ * adi_move_bits() detects a possible 2-stream mode, and moves
+ * the bits accordingly.
+ */
+
+static void adi_move_bits(struct adi_port *port, int length)
+{
+ int i;
+ struct adi *adi = port->adi;
+
+ adi[0].idx = adi[1].idx = 0;
+
+ if (adi[0].ret <= 0 || adi[1].ret <= 0) return;
+ if (adi[0].data[0] & 0x20 || ~adi[1].data[0] & 0x20) return;
+
+ for (i = 1; i <= adi[1].ret; i++)
+ adi[0].data[((length - 1) >> 1) + i + 1] = adi[1].data[i];
+
+ adi[0].ret += adi[1].ret;
+ adi[1].ret = -1;
+}
+
+/*
+ * adi_get_bits() gathers bits from the data packet.
+ */
+
+static inline int adi_get_bits(struct adi *adi, int count)
+{
+ int bits = 0;
+ int i;
+ if ((adi->idx += count) > adi->ret) return 0;
+ for (i = 0; i < count; i++)
+ bits |= ((adi->data[adi->idx - i] >> 5) & 1) << i;
+ return bits;
+}
+
+/*
+ * adi_decode() decodes Logitech joystick data into input events.
+ */
+
+static int adi_decode(struct adi *adi)
+{
+ struct input_dev *dev = &adi->dev;
+ char *abs = adi->abs;
+ short *key = adi->key;
+ int i, t;
+
+ if (adi->ret < adi->length || adi->id != (adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4)))
+ return -1;
+
+ for (i = 0; i < adi->axes10; i++)
+ input_report_abs(dev, *abs++, adi_get_bits(adi, 10));
+
+ for (i = 0; i < adi->axes8; i++)
+ input_report_abs(dev, *abs++, adi_get_bits(adi, 8));
+
+ for (i = 0; i < adi->buttons && i < 63; i++) {
+ if (i == adi->pad) {
+ t = adi_get_bits(adi, 4);
+ input_report_abs(dev, *abs++, ((t >> 2) & 1) - ( t & 1));
+ input_report_abs(dev, *abs++, ((t >> 1) & 1) - ((t >> 3) & 1));
+ }
+ input_report_key(dev, *key++, adi_get_bits(adi, 1));
+ }
+
+ for (i = 0; i < adi->hats; i++) {
+ if ((t = adi_get_bits(adi, 4)) > 8) t = 0;
+ input_report_abs(dev, *abs++, adi_hat_to_axis[t].x);
+ input_report_abs(dev, *abs++, adi_hat_to_axis[t].y);
+ }
+
+ for (i = 63; i < adi->buttons; i++)
+ input_report_key(dev, *key++, adi_get_bits(adi, 1));
+
+ return 0;
+}
+
+/*
+ * adi_read() reads the data packet and decodes it.
+ */
+
+static int adi_read(struct adi_port *port)
+{
+ int i;
+ int result = 0;
+
+ adi_read_packet(port);
+ adi_move_bits(port, port->adi[0].length);
+
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length)
+ result |= adi_decode(port->adi + i);
+
+ return result;
+}
+
+/*
+ * adi_timer() repeatedly polls the Logitech joysticks.
+ */
+
+static void adi_timer(unsigned long data)
+{
+ struct adi_port *port = (void *) data;
+ port->bad -= adi_read(port);
+ port->reads++;
+ mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+}
+
+/*
+ * adi_open() is a callback from the input open routine.
+ */
+
+static int adi_open(struct input_dev *dev)
+{
+ struct adi_port *port = dev->private;
+ if (!port->used++)
+ mod_timer(&port->timer, jiffies + ADI_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * adi_close() is a callback from the input close routine.
+ */
+
+static void adi_close(struct input_dev *dev)
+{
+ struct adi_port *port = dev->private;
+ if (!--port->used)
+ del_timer(&port->timer);
+}
+
+/*
+ * adi_init_digital() sends a trigger & delay sequence
+ * to reset and initialize a Logitech joystick into digital mode.
+ */
+
+static void adi_init_digital(struct gameport *gameport)
+{
+ int seq[] = { 3, -2, -3, 10, -6, -11, -7, -9, 11, 0 };
+ int i;
+
+ for (i = 0; seq[i]; i++) {
+ gameport_trigger(gameport);
+ if (seq[i] > 0) wait_ms(seq[i]);
+ if (seq[i] < 0) mdelay(-seq[i]);
+ }
+}
+
+static void adi_id_decode(struct adi *adi, struct adi_port *port)
+{
+ int i, t;
+
+ if (adi->ret < ADI_MIN_ID_LENGTH) /* Minimum ID packet length */
+ return;
+
+ if (adi->ret < (t = adi_get_bits(adi, 10))) {
+ printk(KERN_WARNING "adi: Short ID packet: reported: %d != read: %d\n", t, adi->ret);
+ return;
+ }
+
+ adi->id = adi_get_bits(adi, 4) | (adi_get_bits(adi, 4) << 4);
+
+ if ((t = adi_get_bits(adi, 4)) & ADI_FLAG_HAT) adi->hats++;
+
+ adi->length = adi_get_bits(adi, 10);
+
+ if (adi->length >= ADI_MAX_LENGTH || adi->length < ADI_MIN_LENGTH) {
+ printk(KERN_WARNING "adi: Bad data packet length (%d).\n", adi->length);
+ adi->length = 0;
+ return;
+ }
+
+ adi->axes8 = adi_get_bits(adi, 4);
+ adi->buttons = adi_get_bits(adi, 6);
+
+ if (adi_get_bits(adi, 6) != 8 && adi->hats) {
+ printk(KERN_WARNING "adi: Other than 8-dir POVs not supported yet.\n");
+ adi->length = 0;
+ return;
+ }
+
+ adi->buttons += adi_get_bits(adi, 6);
+ adi->hats += adi_get_bits(adi, 4);
+
+ i = adi_get_bits(adi, 4);
+
+ if (t & ADI_FLAG_10BIT) {
+ adi->axes10 = adi->axes8 - i;
+ adi->axes8 = i;
+ }
+
+ t = adi_get_bits(adi, 4);
+
+ for (i = 0; i < t; i++)
+ adi->cname[i] = adi_get_bits(adi, 8);
+ adi->cname[i] = 0;
+
+ t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4;
+ if (adi->length != t && adi->length != t + (t & 1)) {
+ printk(KERN_WARNING "adi: Expected length %d != data length %d\n", t, adi->length);
+ adi->length = 0;
+ return;
+ }
+
+ switch (adi->id) {
+ case ADI_ID_TPD:
+ adi->pad = 4;
+ adi->buttons -= 4;
+ break;
+ case ADI_ID_WGP:
+ adi->pad = 0;
+ adi->buttons -= 4;
+ break;
+ default:
+ adi->pad = -1;
+ break;
+ }
+}
+
+static void adi_init_input(struct adi *adi, struct adi_port *port)
+{
+ int i, t;
+ char buf[ADI_MAX_NAME_LENGTH];
+
+ if (!adi->length) return;
+
+ t = adi->id < ADI_ID_MAX ? adi->id : ADI_ID_MAX;
+
+ sprintf(buf, adi_names[t], adi->id);
+ sprintf(adi->name, "Logitech %s", buf);
+
+ adi->abs = adi_abs[t];
+ adi->key = adi_key[t];
+
+ adi->dev.open = adi_open;
+ adi->dev.close = adi_close;
+
+ adi->dev.name = adi->name;
+ adi->dev.idbus = BUS_GAMEPORT;
+ adi->dev.idvendor = GAMEPORT_ID_VENDOR_LOGITECH;
+ adi->dev.idproduct = adi->id;
+ adi->dev.idversion = 0x0100;
+
+ adi->dev.private = port;
+ adi->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++)
+ set_bit(adi->abs[i], &adi->dev.absbit);
+
+ for (i = 0; i < adi->buttons; i++)
+ set_bit(adi->key[i], &adi->dev.keybit);
+}
+
+static void adi_init_center(struct adi *adi)
+{
+ int i, t, x;
+
+ if (!adi->length) return;
+
+ for (i = 0; i < adi->axes10 + adi->axes8 + (adi->hats + (adi->pad > 0)) * 2; i++) {
+
+ t = adi->abs[i];
+ x = adi->dev.abs[t];
+
+ if (t == ABS_THROTTLE || t == ABS_RUDDER || adi->id == ADI_ID_WGPE) {
+ if (i < adi->axes10) x = 512; else x = 128;
+ }
+
+ if (i < adi->axes10) {
+ adi->dev.absmax[t] = x * 2 - 64;
+ adi->dev.absmin[t] = 64;
+ adi->dev.absfuzz[t] = 2;
+ adi->dev.absflat[t] = 16;
+ continue;
+ }
+
+ if (i < adi->axes10 + adi->axes8) {
+ adi->dev.absmax[t] = x * 2 - 48;
+ adi->dev.absmin[t] = 48;
+ adi->dev.absfuzz[t] = 1;
+ adi->dev.absflat[t] = 16;
+ continue;
+ }
+
+ adi->dev.absmax[t] = 1;
+ adi->dev.absmin[t] = -1;
+ }
+}
+
+/*
+ * adi_connect() probes for Logitech ADI joysticks.
+ */
+
+static void adi_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct adi_port *port;
+ int i;
+
+ if (!(port = kmalloc(sizeof(struct adi_port), GFP_KERNEL)))
+ return;
+ memset(port, 0, sizeof(struct adi_port));
+
+ gameport->private = port;
+
+ port->gameport = gameport;
+ init_timer(&port->timer);
+ port->timer.data = (long) port;
+ port->timer.function = adi_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+ kfree(port);
+ return;
+ }
+
+ adi_init_digital(gameport);
+ adi_read_packet(port);
+
+ if (port->adi[0].ret >= ADI_MIN_LEN_LENGTH)
+ adi_move_bits(port, adi_get_bits(port->adi, 10));
+
+ for (i = 0; i < 2; i++) {
+ adi_id_decode(port->adi + i, port);
+ adi_init_input(port->adi + i, port);
+ }
+
+ if (!port->adi[0].length && !port->adi[1].length) {
+ gameport_close(gameport);
+ kfree(port);
+ return;
+ }
+
+ wait_ms(ADI_INIT_DELAY);
+ if (adi_read(port)) {
+ wait_ms(ADI_DATA_DELAY);
+ adi_read(port);
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length > 0) {
+ adi_init_center(port->adi + i);
+ input_register_device(&port->adi[i].dev);
+ printk(KERN_INFO "input%d: %s [%s] on gameport%d.%d\n",
+ port->adi[i].dev.number, port->adi[i].name, port->adi[i].cname, gameport->number, i);
+ }
+}
+
+static void adi_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct adi_port *port = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (port->adi[i].length > 0)
+ input_unregister_device(&port->adi[i].dev);
+ gameport_close(gameport);
+ kfree(port);
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev adi_dev = {
+ connect: adi_connect,
+ disconnect: adi_disconnect,
+};
+
+int __init adi_init(void)
+{
+ gameport_register_device(&adi_dev);
+ return 0;
+}
+
+void __exit adi_exit(void)
+{
+ gameport_unregister_device(&adi_dev);
+}
+
+module_init(adi_init);
+module_exit(adi_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: amijoy.c,v 1.5 2000/07/21 22:52:24 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Driver for Amiga joysticks for Linux/m68k
+ */
+
+/*
+ * 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/types.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+
+#include <asm/system.h>
+#include <asm/amigahw.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_PARM(amijoy, "1-2i");
+MODULE_LICENSE("GPL");
+
+static int amijoy[2] = { 0, 1 };
+static int amijoy_used[2] = { 0, 0 };
+static struct input_dev amijoy_dev[2];
+
+static char *amijoy_name = "Amiga joystick";
+
+static void amijoy_interrupt(int irq, void *dummy, struct pt_regs *fp)
+{
+ int i, data = 0, button = 0;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i]) {
+
+ switch (i) {
+ case 0: data = ~custom.joy0dat; button = (~ciaa.pra >> 6) & 1; break;
+ case 1: data = ~custom.joy1dat; button = (~ciaa.pra >> 7) & 1; break;
+ }
+
+ input_report_key(amijoy_dev + i, BTN_TRIGGER, button);
+
+ input_report_abs(amijoy_dev + i, ABS_X, ((data >> 1) & 1) - ((data >> 9) & 1);
+ data = ~(data ^ (data << 1));
+ input_report_abs(amijoy_dev + i, ABS_Y, ((data >> 1) & 1) - ((data >> 9) & 1);
+ }
+}
+
+static int amijoy_open(struct input_dev *dev)
+{
+ int *used = dev->private;
+
+ if ((*used)++)
+ return 0;
+
+ if (request_irq(IRQ_AMIGA_VERTB, amijoy_interrupt, 0, "amijoy", NULL)) {
+ (*used)--;
+ printk(KERN_ERR "amijoy.c: Can't allocate irq %d\n", amijoy_irq);
+ return -EBUSY;
+ }
+
+ return 0;
+}
+
+static void amijoy_close(struct input_dev *dev)
+{
+ int *used = dev->private;
+
+ if (!--(*used))
+ free_irq(IRQ_AMIGA_VERTB, amijoy_interrupt);
+}
+
+static int __init amijoy_setup(char *str)
+{
+ int i;
+ int ints[4]
+ str = get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) amijoy[i] = ints[i+1];
+ return 1;
+}
+__setup("amijoy=", amijoy_setup);
+
+static int __init amijoy_init(void)
+{
+ int i, j;
+
+ init_timer(amijoy_timer);
+ port->timer.function = amijoy_timer;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i]) {
+ if (!request_mem_region(CUSTOM_PHYSADDR+10+i*2, 2,
+ "amijoy [Denise]")) {
+ if (i == 1 && amijoy[0]) {
+ input_unregister_device(amijoy_dev);
+ release_mem_region(CUSTOM_PHYSADDR+10, 2);
+ }
+ return -EBUSY;
+ }
+
+ amijoy_dev[i].open = amijoy_open;
+ amijoy_dev[i].close = amijoy_close;
+ amijoy_dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ amijoy_dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+ amijoy_dev[i].keybit[LONG(BTN_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
+ for (j = 0; j < 2; j++) {
+ amijoy_dev[i].absmin[ABS_X + j] = -1;
+ amijoy_dev[i].absmax[ABS_X + j] = 1;
+ }
+
+ amijoy->dev[i].name = amijoy_name;
+ amijoy->dev[i].idbus = BUS_AMIGA;
+ amijoy->dev[i].idvendor = 0x0001;
+ amijoy->dev[i].idproduct = 0x0003;
+ amijoy->dev[i].version = 0x0100;
+
+ amijoy_dev[i].private = amijoy_used + i;
+
+ input_register_device(amijoy_dev + i);
+ printk(KERN_INFO "input%d: %s at joy%ddat\n", amijoy_dev[i].number, amijoy_name, i);
+ }
+ return 0;
+}
+
+static void _exit amijoy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i]) {
+ input_unregister_device(amijoy_dev + i);
+ release_mem_region(CUSTOM_PHYSADDR+10+i*2, 2);
+ }
+}
+
+module_init(amijoy_init);
+module_exit(amijoy_exit);
--- /dev/null
+/*
+ * $Id: analog.c,v 1.52 2000/06/07 13:07:06 vojtech Exp $
+ *
+ * Copyright (c) 1996-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Analog joystick and gamepad driver for Linux
+ */
+
+/*
+ * 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/config.h>
+#include <linux/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+#include <asm/timex.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_DESCRIPTION("Analog joystick and gamepad driver for Linux");
+MODULE_LICENSE("GPL");
+
+/*
+ * Option parsing.
+ */
+
+#define ANALOG_PORTS 16
+
+static char *js[ANALOG_PORTS];
+static int analog_options[ANALOG_PORTS];
+MODULE_PARM(js, "1-" __MODULE_STRING(ANALOG_PORTS) "s");
+MODULE_PARM_DESC(js, "Analog joystick options");
+
+/*
+ * Times, feature definitions.
+ */
+
+#define ANALOG_RUDDER 0x00004
+#define ANALOG_THROTTLE 0x00008
+#define ANALOG_AXES_STD 0x0000f
+#define ANALOG_BTNS_STD 0x000f0
+
+#define ANALOG_BTNS_CHF 0x00100
+#define ANALOG_HAT1_CHF 0x00200
+#define ANALOG_HAT2_CHF 0x00400
+#define ANALOG_HAT_FCS 0x00800
+#define ANALOG_HATS_ALL 0x00e00
+#define ANALOG_BTN_TL 0x01000
+#define ANALOG_BTN_TR 0x02000
+#define ANALOG_BTN_TL2 0x04000
+#define ANALOG_BTN_TR2 0x08000
+#define ANALOG_BTNS_TLR 0x03000
+#define ANALOG_BTNS_TLR2 0x0c000
+#define ANALOG_BTNS_GAMEPAD 0x0f000
+
+#define ANALOG_HBTN_CHF 0x10000
+#define ANALOG_ANY_CHF 0x10700
+#define ANALOG_SAITEK 0x20000
+#define ANALOG_EXTENSIONS 0x7ff00
+#define ANALOG_GAMEPAD 0x80000
+
+#define ANALOG_MAX_TIME 3 /* 3 ms */
+#define ANALOG_LOOP_TIME 2000 /* 2 * loop */
+#define ANALOG_REFRESH_TIME HZ/100 /* 10 ms */
+#define ANALOG_SAITEK_DELAY 200 /* 200 us */
+#define ANALOG_SAITEK_TIME 2000 /* 2000 us */
+#define ANALOG_AXIS_TIME 2 /* 2 * refresh */
+#define ANALOG_INIT_RETRIES 8 /* 8 times */
+#define ANALOG_FUZZ_BITS 2 /* 2 bit more */
+#define ANALOG_FUZZ_MAGIC 36 /* 36 u*ms/loop */
+
+#define ANALOG_MAX_NAME_LENGTH 128
+
+static short analog_axes[] = { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE };
+static short analog_hats[] = { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, ABS_HAT2X, ABS_HAT2Y };
+static short analog_pads[] = { BTN_Y, BTN_Z, BTN_TL, BTN_TR };
+static short analog_exts[] = { ANALOG_HAT1_CHF, ANALOG_HAT2_CHF, ANALOG_HAT_FCS };
+static short analog_pad_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_TL2, BTN_TR2, BTN_SELECT, BTN_START, BTN_MODE, BTN_BASE };
+static short analog_joy_btn[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2,
+ BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_BASE6 };
+
+static unsigned char analog_chf[] = { 0xf, 0x0, 0x1, 0x9, 0x2, 0x4, 0xc, 0x8, 0x3, 0x5, 0xb, 0x7, 0xd, 0xe, 0xa, 0x6 };
+
+struct analog {
+ struct input_dev dev;
+ int mask;
+ short *buttons;
+ char name[ANALOG_MAX_NAME_LENGTH];
+};
+
+struct analog_port {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct analog analog[2];
+ unsigned char mask;
+ char saitek;
+ char cooked;
+ int bads;
+ int reads;
+ int speed;
+ int loop;
+ int fuzz;
+ int axes[4];
+ int buttons;
+ int initial[4];
+ int used;
+ int axtime;
+};
+
+/*
+ * Time macros.
+ */
+
+#ifdef __i386__
+#define TSC_PRESENT (test_bit(X86_FEATURE_TSC, &boot_cpu_data.x86_capability))
+#define GET_TIME(x) do { if (TSC_PRESENT) rdtscl(x); else { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } } while (0)
+#define DELTA(x,y) (TSC_PRESENT?((y)-(x)):((x)-(y)+((x)<(y)?1193180L/HZ:0)))
+#define TIME_NAME (TSC_PRESENT?"TSC":"PIT")
+#elif __x86_64__
+#define GET_TIME(x) rdtscl(x)
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "TSC"
+#elif __alpha__
+#define GET_TIME(x) ((x) = get_cycles())
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "PCC"
+#else
+#define FAKE_TIME
+static unsigned long analog_faketime = 0;
+#define GET_TIME(x) do { x = analog_faketime++; } while(0)
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "Unreliable"
+#warning Precise timer not defined for this architecture.
+#endif
+
+/*
+ * analog_decode() decodes analog joystick data and reports input events.
+ */
+
+static void analog_decode(struct analog *analog, int *axes, int *initial, int buttons)
+{
+ struct input_dev *dev = &analog->dev;
+ int i, j;
+
+ if (analog->mask & ANALOG_HAT_FCS)
+ for (i = 0; i < 4; i++)
+ if (axes[3] < ((initial[3] * ((i << 1) + 1)) >> 3)) {
+ buttons |= 1 << (i + 14);
+ break;
+ }
+
+ for (i = j = 0; i < 6; i++)
+ if (analog->mask & (0x10 << i))
+ input_report_key(dev, analog->buttons[j++], (buttons >> i) & 1);
+
+ if (analog->mask & ANALOG_HBTN_CHF)
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, analog->buttons[j++], (buttons >> (i + 10)) & 1);
+
+ if (analog->mask & ANALOG_BTN_TL)
+ input_report_key(dev, analog_pads[0], axes[2] < (initial[2] >> 1));
+ if (analog->mask & ANALOG_BTN_TR)
+ input_report_key(dev, analog_pads[1], axes[3] < (initial[3] >> 1));
+ if (analog->mask & ANALOG_BTN_TL2)
+ input_report_key(dev, analog_pads[2], axes[2] > (initial[2] + (initial[2] >> 1)));
+ if (analog->mask & ANALOG_BTN_TR2)
+ input_report_key(dev, analog_pads[3], axes[3] > (initial[3] + (initial[3] >> 1)));
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (1 << i))
+ input_report_abs(dev, analog_axes[j++], axes[i]);
+
+ for (i = j = 0; i < 3; i++)
+ if (analog->mask & analog_exts[i]) {
+ input_report_abs(dev, analog_hats[j++],
+ ((buttons >> ((i << 2) + 7)) & 1) - ((buttons >> ((i << 2) + 9)) & 1));
+ input_report_abs(dev, analog_hats[j++],
+ ((buttons >> ((i << 2) + 8)) & 1) - ((buttons >> ((i << 2) + 6)) & 1));
+ }
+}
+
+/*
+ * analog_cooked_read() reads analog joystick data.
+ */
+
+static int analog_cooked_read(struct analog_port *port)
+{
+ struct gameport *gameport = port->gameport;
+ unsigned int time[4], start, loop, now, loopout, timeout;
+ unsigned char data[4], this, last;
+ unsigned long flags;
+ int i, j;
+
+ loopout = (ANALOG_LOOP_TIME * port->loop) / 1000;
+ timeout = ANALOG_MAX_TIME * port->speed;
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ GET_TIME(now);
+ __restore_flags(flags);
+
+ start = now;
+ this = port->mask;
+ i = 0;
+
+ do {
+ loop = now;
+ last = this;
+
+ __cli();
+ this = gameport_read(gameport) & port->mask;
+ GET_TIME(now);
+ __restore_flags(flags);
+
+ if ((last ^ this) && (DELTA(loop, now) < loopout)) {
+ data[i] = last ^ this;
+ time[i] = now;
+ i++;
+ }
+
+ } while (this && (i < 4) && (DELTA(start, now) < timeout));
+
+ this <<= 4;
+
+ for (--i; i >= 0; i--) {
+ this |= data[i];
+ for (j = 0; j < 4; j++)
+ if (data[i] & (1 << j))
+ port->axes[j] = (DELTA(start, time[i]) << ANALOG_FUZZ_BITS) / port->loop;
+ }
+
+ return -(this != port->mask);
+}
+
+static int analog_button_read(struct analog_port *port, char saitek, char chf)
+{
+ unsigned char u;
+ int t = 1, i = 0;
+ int strobe = gameport_time(port->gameport, ANALOG_SAITEK_TIME);
+
+ u = gameport_read(port->gameport);
+
+ if (!chf) {
+ port->buttons = (~u >> 4) & 0xf;
+ return 0;
+ }
+
+ port->buttons = 0;
+
+ while ((~u & 0xf0) && (i < 16) && t) {
+ port->buttons |= 1 << analog_chf[(~u >> 4) & 0xf];
+ if (!saitek) return 0;
+ udelay(ANALOG_SAITEK_DELAY);
+ t = strobe;
+ gameport_trigger(port->gameport);
+ while (((u = gameport_read(port->gameport)) & port->mask) && t) t--;
+ i++;
+ }
+
+ return -(!t || (i == 16));
+}
+
+/*
+ * analog_timer() repeatedly polls the Analog joysticks.
+ */
+
+static void analog_timer(unsigned long data)
+{
+ struct analog_port *port = (void *) data;
+ int i;
+
+ char saitek = !!(port->analog[0].mask & ANALOG_SAITEK);
+ char chf = !!(port->analog[0].mask & ANALOG_ANY_CHF);
+
+ if (port->cooked) {
+ port->bads -= gameport_cooked_read(port->gameport, port->axes, &port->buttons);
+ if (chf)
+ port->buttons = port->buttons ? (1 << analog_chf[port->buttons]) : 0;
+ port->reads++;
+ } else {
+ if (!port->axtime--) {
+ port->bads -= analog_cooked_read(port);
+ port->bads -= analog_button_read(port, saitek, chf);
+ port->reads++;
+ port->axtime = ANALOG_AXIS_TIME - 1;
+ } else {
+ if (!saitek)
+ analog_button_read(port, saitek, chf);
+ }
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ analog_decode(port->analog + i, port->axes, port->initial, port->buttons);
+
+ mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+}
+
+/*
+ * analog_open() is a callback from the input open routine.
+ */
+
+static int analog_open(struct input_dev *dev)
+{
+ struct analog_port *port = dev->private;
+ if (!port->used++)
+ mod_timer(&port->timer, jiffies + ANALOG_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * analog_close() is a callback from the input close routine.
+ */
+
+static void analog_close(struct input_dev *dev)
+{
+ struct analog_port *port = dev->private;
+ if (!--port->used)
+ del_timer(&port->timer);
+}
+
+/*
+ * analog_calibrate_timer() calibrates the timer and computes loop
+ * and timeout values for a joystick port.
+ */
+
+static void analog_calibrate_timer(struct analog_port *port)
+{
+ struct gameport *gameport = port->gameport;
+ unsigned int i, t, tx, t1, t2, t3;
+ unsigned long flags;
+
+ save_flags(flags);
+ cli();
+ GET_TIME(t1);
+#ifdef FAKE_TIME
+ analog_faketime += 830;
+#endif
+ udelay(1000);
+ GET_TIME(t2);
+ GET_TIME(t3);
+ restore_flags(flags);
+
+ port->speed = DELTA(t1, t2) - DELTA(t2, t3);
+
+ tx = ~0;
+
+ for (i = 0; i < 50; i++) {
+ save_flags(flags);
+ cli();
+ GET_TIME(t1);
+ for (t = 0; t < 50; t++) { gameport_read(gameport); GET_TIME(t2); }
+ GET_TIME(t3);
+ restore_flags(flags);
+ udelay(i);
+ t = DELTA(t1, t2) - DELTA(t2, t3);
+ if (t < tx) tx = t;
+ }
+
+ port->loop = tx / 50;
+}
+
+/*
+ * analog_name() constructs a name for an analog joystick.
+ */
+
+static void analog_name(struct analog *analog)
+{
+ sprintf(analog->name, "Analog %d-axis %d-button",
+ hweight8(analog->mask & ANALOG_AXES_STD),
+ hweight8(analog->mask & ANALOG_BTNS_STD) + !!(analog->mask & ANALOG_BTNS_CHF) * 2 +
+ hweight16(analog->mask & ANALOG_BTNS_GAMEPAD) + !!(analog->mask & ANALOG_HBTN_CHF) * 4);
+
+ if (analog->mask & ANALOG_HATS_ALL)
+ sprintf(analog->name, "%s %d-hat",
+ analog->name, hweight16(analog->mask & ANALOG_HATS_ALL));
+
+ if (analog->mask & ANALOG_HAT_FCS)
+ strcat(analog->name, " FCS");
+ if (analog->mask & ANALOG_ANY_CHF)
+ strcat(analog->name, (analog->mask & ANALOG_SAITEK) ? " Saitek" : " CHF");
+
+ strcat(analog->name, (analog->mask & ANALOG_GAMEPAD) ? " gamepad": " joystick");
+}
+
+/*
+ * analog_init_device()
+ */
+
+static void analog_init_device(struct analog_port *port, struct analog *analog, int index)
+{
+ int i, j, t, v, w, x, y, z;
+
+ analog_name(analog);
+
+ analog->buttons = (analog->mask & ANALOG_GAMEPAD) ? analog_pad_btn : analog_joy_btn;
+
+ analog->dev.name = analog->name;
+ analog->dev.idbus = BUS_GAMEPORT;
+ analog->dev.idvendor = GAMEPORT_ID_VENDOR_ANALOG;
+ analog->dev.idproduct = analog->mask >> 4;
+ analog->dev.idversion = 0x0100;
+
+ analog->dev.open = analog_open;
+ analog->dev.close = analog_close;
+ analog->dev.private = port;
+ analog->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (1 << i)) {
+
+ t = analog_axes[j];
+ x = port->axes[i];
+ y = (port->axes[0] + port->axes[1]) >> 1;
+ z = y - port->axes[i];
+ z = z > 0 ? z : -z;
+ v = (x >> 3);
+ w = (x >> 3);
+
+ set_bit(t, analog->dev.absbit);
+
+ if ((i == 2 || i == 3) && (j == 2 || j == 3) && (z > (y >> 3)))
+ x = y;
+
+ if (analog->mask & ANALOG_SAITEK) {
+ if (i == 2) x = port->axes[i];
+ v = x - (x >> 2);
+ w = (x >> 4);
+ }
+
+ analog->dev.absmax[t] = (x << 1) - v;
+ analog->dev.absmin[t] = v;
+ analog->dev.absfuzz[t] = port->fuzz;
+ analog->dev.absflat[t] = w;
+
+ j++;
+ }
+
+ for (i = j = 0; i < 3; i++)
+ if (analog->mask & analog_exts[i])
+ for (x = 0; x < 2; x++) {
+ t = analog_hats[j++];
+ set_bit(t, analog->dev.absbit);
+ analog->dev.absmax[t] = 1;
+ analog->dev.absmin[t] = -1;
+ }
+
+ for (i = j = 0; i < 4; i++)
+ if (analog->mask & (0x10 << i))
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ if (analog->mask & ANALOG_BTNS_CHF)
+ for (i = 0; i < 2; i++)
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ if (analog->mask & ANALOG_HBTN_CHF)
+ for (i = 0; i < 4; i++)
+ set_bit(analog->buttons[j++], analog->dev.keybit);
+
+ for (i = 0; i < 4; i++)
+ if (analog->mask & (ANALOG_BTN_TL << i))
+ set_bit(analog_pads[i], analog->dev.keybit);
+
+ analog_decode(analog, port->axes, port->initial, port->buttons);
+
+ input_register_device(&analog->dev);
+
+ printk(KERN_INFO "input%d: %s at gameport%d.%d",
+ analog->dev.number, analog->name, port->gameport->number, index);
+
+ if (port->cooked)
+ printk(" [ADC port]\n");
+ else
+ printk(" [%s timer, %d %sHz clock, %d ns res]\n", TIME_NAME,
+ port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
+ port->speed > 10000 ? "M" : "k",
+ port->speed > 10000 ? (port->loop * 1000) / (port->speed / 1000)
+ : (port->loop * 1000000) / port->speed);
+}
+
+/*
+ * analog_init_devices() sets up device-specific values and registers the input devices.
+ */
+
+static int analog_init_masks(struct analog_port *port)
+{
+ int i;
+ struct analog *analog = port->analog;
+ int max[4];
+
+ if (!port->mask)
+ return -1;
+
+ if ((port->mask & 3) != 3 && port->mask != 0xc) {
+ printk(KERN_WARNING "analog.c: Unknown joystick device found "
+ "(data=%#x, gameport%d), probably not analog joystick.\n",
+ port->mask, port->gameport->number);
+ return -1;
+ }
+
+ i = port->gameport->number < ANALOG_PORTS ? analog_options[port->gameport->number] : 0xff;
+
+ analog[0].mask = i & 0xfffff;
+
+ analog[0].mask &= ~(ANALOG_AXES_STD | ANALOG_HAT_FCS | ANALOG_BTNS_GAMEPAD)
+ | port->mask | ((port->mask << 8) & ANALOG_HAT_FCS)
+ | ((port->mask << 10) & ANALOG_BTNS_TLR) | ((port->mask << 12) & ANALOG_BTNS_TLR2);
+
+ analog[0].mask &= ~(ANALOG_HAT2_CHF)
+ | ((analog[0].mask & ANALOG_HBTN_CHF) ? 0 : ANALOG_HAT2_CHF);
+
+ analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_BTN_TR | ANALOG_BTN_TR2)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) >> 8)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) << 2)
+ | ((~analog[0].mask & ANALOG_HAT_FCS) << 4);
+
+ analog[0].mask &= ~(ANALOG_THROTTLE | ANALOG_RUDDER)
+ | (((~analog[0].mask & ANALOG_BTNS_TLR ) >> 10)
+ & ((~analog[0].mask & ANALOG_BTNS_TLR2) >> 12));
+
+ analog[1].mask = ((i >> 20) & 0xff) | ((i >> 12) & 0xf0000);
+
+ analog[1].mask &= (analog[0].mask & ANALOG_EXTENSIONS) ? ANALOG_GAMEPAD
+ : (((ANALOG_BTNS_STD | port->mask) & ~analog[0].mask) | ANALOG_GAMEPAD);
+
+ if (port->cooked) {
+
+ for (i = 0; i < 4; i++) max[i] = port->axes[i] << 1;
+
+ if ((analog[0].mask & 0x7) == 0x7) max[2] = (max[0] + max[1]) >> 1;
+ if ((analog[0].mask & 0xb) == 0xb) max[3] = (max[0] + max[1]) >> 1;
+ if ((analog[0].mask & ANALOG_BTN_TL) && !(analog[0].mask & ANALOG_BTN_TL2)) max[2] >>= 1;
+ if ((analog[0].mask & ANALOG_BTN_TR) && !(analog[0].mask & ANALOG_BTN_TR2)) max[3] >>= 1;
+ if ((analog[0].mask & ANALOG_HAT_FCS)) max[3] >>= 1;
+
+ gameport_calibrate(port->gameport, port->axes, max);
+ }
+
+ for (i = 0; i < 4; i++)
+ port->initial[i] = port->axes[i];
+
+ return -!(analog[0].mask || analog[1].mask);
+}
+
+static int analog_init_port(struct gameport *gameport, struct gameport_dev *dev, struct analog_port *port)
+{
+ int i, t, u, v;
+
+ gameport->private = port;
+ port->gameport = gameport;
+ init_timer(&port->timer);
+ port->timer.data = (long) port;
+ port->timer.function = analog_timer;
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW)) {
+
+ analog_calibrate_timer(port);
+
+ gameport_trigger(gameport);
+ t = gameport_read(gameport);
+ wait_ms(ANALOG_MAX_TIME);
+ port->mask = (gameport_read(gameport) ^ t) & t & 0xf;
+ port->fuzz = (port->speed * ANALOG_FUZZ_MAGIC) / port->loop / 1000 + ANALOG_FUZZ_BITS;
+
+ for (i = 0; i < ANALOG_INIT_RETRIES; i++) {
+ if (!analog_cooked_read(port)) break;
+ wait_ms(ANALOG_MAX_TIME);
+ }
+
+ u = v = 0;
+
+ wait_ms(ANALOG_MAX_TIME);
+ t = gameport_time(gameport, ANALOG_MAX_TIME * 1000);
+ gameport_trigger(gameport);
+ while ((gameport_read(port->gameport) & port->mask) && (u < t)) u++;
+ udelay(ANALOG_SAITEK_DELAY);
+ t = gameport_time(gameport, ANALOG_SAITEK_TIME);
+ gameport_trigger(gameport);
+ while ((gameport_read(port->gameport) & port->mask) && (v < t)) v++;
+
+ if (v < (u >> 1) && port->gameport->number < ANALOG_PORTS) {
+ analog_options[port->gameport->number] |=
+ ANALOG_SAITEK | ANALOG_BTNS_CHF | ANALOG_HBTN_CHF | ANALOG_HAT1_CHF;
+ return 0;
+ }
+
+ gameport_close(gameport);
+ }
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_COOKED)) {
+
+ for (i = 0; i < ANALOG_INIT_RETRIES; i++)
+ if (!gameport_cooked_read(gameport, port->axes, &port->buttons))
+ break;
+ for (i = 0; i < 4; i++)
+ if (port->axes[i] != -1) port->mask |= 1 << i;
+
+ port->fuzz = gameport->fuzz;
+ port->cooked = 1;
+ return 0;
+ }
+
+ if (!gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ return 0;
+
+ return -1;
+}
+
+static void analog_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct analog_port *port;
+ int i;
+
+ if (!(port = kmalloc(sizeof(struct analog_port), GFP_KERNEL)))
+ return;
+ memset(port, 0, sizeof(struct analog_port));
+
+ if (analog_init_port(gameport, dev, port)) {
+ kfree(port);
+ return;
+ }
+
+ if (analog_init_masks(port)) {
+ gameport_close(gameport);
+ kfree(port);
+ return;
+ }
+
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ analog_init_device(port, port->analog + i, i);
+}
+
+static void analog_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct analog_port *port = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (port->analog[i].mask)
+ input_unregister_device(&port->analog[i].dev);
+ gameport_close(gameport);
+ printk(KERN_INFO "analog.c: %d out of %d reads (%d%%) on gameport%d failed\n",
+ port->bads, port->reads, port->reads ? (port->bads * 100 / port->reads) : 0,
+ port->gameport->number);
+ kfree(port);
+}
+
+struct analog_types {
+ char *name;
+ int value;
+};
+
+struct analog_types analog_types[] = {
+ { "none", 0x00000000 },
+ { "auto", 0x000000ff },
+ { "2btn", 0x0000003f },
+ { "y-joy", 0x0cc00033 },
+ { "y-pad", 0x8cc80033 },
+ { "fcs", 0x000008f7 },
+ { "chf", 0x000002ff },
+ { "fullchf", 0x000007ff },
+ { "gamepad", 0x000830f3 },
+ { "gamepad8", 0x0008f0f3 },
+ { NULL, 0 }
+};
+
+static void analog_parse_options(void)
+{
+ int i, j;
+ char *end;
+
+ for (i = 0; i < ANALOG_PORTS && js[i]; i++) {
+
+ for (j = 0; analog_types[j].name; j++)
+ if (!strcmp(analog_types[j].name, js[i])) {
+ analog_options[i] = analog_types[j].value;
+ break;
+ }
+ if (analog_types[j].name) continue;
+
+ analog_options[i] = simple_strtoul(js[i], &end, 0);
+ if (end != js[i]) continue;
+
+ analog_options[i] = 0xff;
+ if (!strlen(js[i])) continue;
+
+ printk(KERN_WARNING "analog.c: Bad config for port %d - \"%s\"\n", i, js[i]);
+ }
+
+ for (; i < ANALOG_PORTS; i++)
+ analog_options[i] = 0xff;
+}
+
+/*
+ * The gameport device structure.
+ */
+
+static struct gameport_dev analog_dev = {
+ connect: analog_connect,
+ disconnect: analog_disconnect,
+};
+
+#ifndef MODULE
+static int __init analog_setup(char *str)
+{
+ char *s = str;
+ int i = 0;
+
+ if (!str || !*str) return 0;
+
+ while ((str = s) && (i < ANALOG_PORTS)) {
+ if ((s = strchr(str,','))) *s++ = 0;
+ js[i++] = str;
+ }
+
+ return 1;
+}
+__setup("js=", analog_setup);
+#endif
+
+int __init analog_init(void)
+{
+ analog_parse_options();
+ gameport_register_device(&analog_dev);
+ return 0;
+}
+
+void __exit analog_exit(void)
+{
+ gameport_unregister_device(&analog_dev);
+}
+
+module_init(analog_init);
+module_exit(analog_exit);
--- /dev/null
+/*
+ * $Id: cobra.c,v 1.10 2000/06/08 10:23:45 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Creative Labd Blaster GamePad Cobra driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define COBRA_MAX_STROBE 45 /* 45 us max wait for first strobe */
+#define COBRA_REFRESH_TIME HZ/50 /* 20 ms between reads */
+#define COBRA_LENGTH 36
+
+static char* cobra_name = "Creative Labs Blaster GamePad Cobra";
+
+static int cobra_btn[] = { BTN_START, BTN_SELECT, BTN_TL, BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL2, BTN_TR2, 0 };
+
+struct cobra {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ int used;
+ int reads;
+ int bads;
+ unsigned char exists;
+};
+
+static unsigned char cobra_read_packet(struct gameport *gameport, unsigned int *data)
+{
+ unsigned long flags;
+ unsigned char u, v, w;
+ __u64 buf[2];
+ int r[2], t[2];
+ int i, j, ret;
+
+ int strobe = gameport_time(gameport, COBRA_MAX_STROBE);
+
+ for (i = 0; i < 2; i++) {
+ r[i] = buf[i] = 0;
+ t[i] = COBRA_MAX_STROBE;
+ }
+
+ __save_flags(flags);
+ __cli();
+
+ u = gameport_read(gameport);
+
+ do {
+ t[0]--; t[1]--;
+ v = gameport_read(gameport);
+ for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
+ if (w & 0x30) {
+ if ((w & 0x30) < 0x30 && r[i] < COBRA_LENGTH && t[i] > 0) {
+ buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
+ t[i] = strobe;
+ u = v;
+ } else t[i] = 0;
+ }
+ } while (t[0] > 0 || t[1] > 0);
+
+ __restore_flags(flags);
+
+ ret = 0;
+
+ for (i = 0; i < 2; i++) {
+
+ if (r[i] != COBRA_LENGTH) continue;
+
+ for (j = 0; j < COBRA_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
+ buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (COBRA_LENGTH - 1));
+
+ if (j < COBRA_LENGTH) ret |= (1 << i);
+
+ data[i] = ((buf[i] >> 7) & 0x000001f) | ((buf[i] >> 8) & 0x00003e0)
+ | ((buf[i] >> 9) & 0x0007c00) | ((buf[i] >> 10) & 0x00f8000)
+ | ((buf[i] >> 11) & 0x1f00000);
+
+ }
+
+ return ret;
+}
+
+static void cobra_timer(unsigned long private)
+{
+ struct cobra *cobra = (void *) private;
+ struct input_dev *dev;
+ unsigned int data[2];
+ int i, j, r;
+
+ cobra->reads++;
+
+ if ((r = cobra_read_packet(cobra->gameport, data)) != cobra->exists)
+ cobra->bads++;
+
+ for (i = 0; i < 2; i++)
+ if (cobra->exists & r & (1 << i)) {
+
+ dev = cobra->dev + i;
+
+ input_report_abs(dev, ABS_X, ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1));
+ input_report_abs(dev, ABS_Y, ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1));
+
+ for (j = 0; cobra_btn[j]; j++)
+ input_report_key(dev, cobra_btn[j], data[i] & (0x20 << j));
+
+ }
+
+ mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+}
+
+static int cobra_open(struct input_dev *dev)
+{
+ struct cobra *cobra = dev->private;
+ if (!cobra->used++)
+ mod_timer(&cobra->timer, jiffies + COBRA_REFRESH_TIME);
+ return 0;
+}
+
+static void cobra_close(struct input_dev *dev)
+{
+ struct cobra *cobra = dev->private;
+ if (!--cobra->used)
+ del_timer(&cobra->timer);
+}
+
+static void cobra_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct cobra *cobra;
+ unsigned int data[2];
+ int i, j;
+
+ if (!(cobra = kmalloc(sizeof(struct cobra), GFP_KERNEL)))
+ return;
+ memset(cobra, 0, sizeof(struct cobra));
+
+ gameport->private = cobra;
+
+ cobra->gameport = gameport;
+ init_timer(&cobra->timer);
+ cobra->timer.data = (long) cobra;
+ cobra->timer.function = cobra_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ cobra->exists = cobra_read_packet(gameport, data);
+
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & data[i] & 1) {
+ printk(KERN_WARNING "cobra.c: Device on gameport%d.%d has the Ext bit set. ID is: %d"
+ " Contact vojtech@suse.cz\n", gameport->number, i, (data[i] >> 2) & 7);
+ cobra->exists &= ~(1 << i);
+ }
+
+ if (!cobra->exists)
+ goto fail2;
+
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & 1) {
+
+ cobra->dev[i].private = cobra;
+ cobra->dev[i].open = cobra_open;
+ cobra->dev[i].close = cobra_close;
+
+ cobra->dev[i].name = cobra_name;
+ cobra->dev[i].idbus = BUS_GAMEPORT;
+ cobra->dev[i].idvendor = GAMEPORT_ID_VENDOR_CREATIVE;
+ cobra->dev[i].idproduct = 0x0008;
+ cobra->dev[i].idversion = 0x0100;
+
+ cobra->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ cobra->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ for (j = 0; cobra_btn[j]; j++)
+ set_bit(cobra_btn[j], cobra->dev[i].keybit);
+
+ cobra->dev[i].absmin[ABS_X] = -1; cobra->dev[i].absmax[ABS_X] = 1;
+ cobra->dev[i].absmin[ABS_Y] = -1; cobra->dev[i].absmax[ABS_Y] = 1;
+
+ input_register_device(cobra->dev + i);
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ cobra->dev[i].number, cobra_name, gameport->number, i);
+ }
+
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(cobra);
+}
+
+static void cobra_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct cobra *cobra = gameport->private;
+ for (i = 0; i < 2; i++)
+ if ((cobra->exists >> i) & 1)
+ input_unregister_device(cobra->dev + i);
+ gameport_close(gameport);
+ kfree(cobra);
+}
+
+static struct gameport_dev cobra_dev = {
+ connect: cobra_connect,
+ disconnect: cobra_disconnect,
+};
+
+int __init cobra_init(void)
+{
+ gameport_register_device(&cobra_dev);
+ return 0;
+}
+
+void __exit cobra_exit(void)
+{
+ gameport_unregister_device(&cobra_dev);
+}
+
+module_init(cobra_init);
+module_exit(cobra_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: db9.c,v 1.6 2000/06/25 10:57:50 vojtech Exp $
+ *
+ * Copyright (c) 1999 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Andree Borrmann Mats Sjövall
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Atari, Amstrad, Commodore, Amiga, Sega, etc. joystick driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(db9, "2i");
+MODULE_PARM(db9_2, "2i");
+MODULE_PARM(db9_3, "2i");
+
+#define DB9_MULTI_STICK 0x01
+#define DB9_MULTI2_STICK 0x02
+#define DB9_GENESIS_PAD 0x03
+#define DB9_GENESIS5_PAD 0x05
+#define DB9_GENESIS6_PAD 0x06
+#define DB9_SATURN_PAD 0x07
+#define DB9_MULTI_0802 0x08
+#define DB9_MULTI_0802_2 0x09
+#define DB9_CD32_PAD 0x0A
+#define DB9_MAX_PAD 0x0B
+
+#define DB9_UP 0x01
+#define DB9_DOWN 0x02
+#define DB9_LEFT 0x04
+#define DB9_RIGHT 0x08
+#define DB9_FIRE1 0x10
+#define DB9_FIRE2 0x20
+#define DB9_FIRE3 0x40
+#define DB9_FIRE4 0x80
+
+#define DB9_NORMAL 0x0a
+#define DB9_NOSELECT 0x08
+
+#define DB9_SATURN0 0x00
+#define DB9_SATURN1 0x02
+#define DB9_SATURN2 0x04
+#define DB9_SATURN3 0x06
+
+#define DB9_GENESIS6_DELAY 14
+#define DB9_REFRESH_TIME HZ/100
+
+static int db9[] __initdata = { -1, 0 };
+static int db9_2[] __initdata = { -1, 0 };
+static int db9_3[] __initdata = { -1, 0 };
+
+struct db9 {
+ struct input_dev dev[2];
+ struct timer_list timer;
+ struct pardevice *pd;
+ int mode;
+ int used;
+};
+
+static struct db9 *db9_base[3];
+
+static short db9_multi_btn[] = { BTN_TRIGGER, BTN_THUMB };
+static short db9_genesis_btn[] = { BTN_START, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_MODE };
+static short db9_cd32_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START };
+
+static char db9_buttons[DB9_MAX_PAD] = { 0, 1, 2, 4, 0, 6, 8, 8, 1, 1, 7 };
+static short *db9_btn[DB9_MAX_PAD] = { NULL, db9_multi_btn, db9_multi_btn, db9_genesis_btn, NULL, db9_genesis_btn,
+ db9_genesis_btn, db9_cd32_btn, db9_multi_btn, db9_multi_btn, db9_cd32_btn };
+static char *db9_name[DB9_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", "Amiga CD-32 pad" };
+
+static void db9_timer(unsigned long private)
+{
+ struct db9 *db9 = (void *) private;
+ struct parport *port = db9->pd->port;
+ struct input_dev *dev = db9->dev;
+ int data, i;
+
+ switch(db9->mode) {
+ case DB9_MULTI_0802_2:
+
+ data = parport_read_data(port) >> 3;
+
+ input_report_abs(dev + 1, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev + 1, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev + 1, BTN_TRIGGER, ~data & DB9_FIRE1);
+
+ case DB9_MULTI_0802:
+
+ data = parport_read_status(port) >> 3;
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_TRIGGER, data & DB9_FIRE1);
+ break;
+
+ case DB9_MULTI_STICK:
+
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
+ break;
+
+ case DB9_MULTI2_STICK:
+
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_TRIGGER, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_THUMB, ~data & DB9_FIRE2);
+ break;
+
+ case DB9_GENESIS_PAD:
+
+ parport_write_control(port, DB9_NOSELECT);
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_START, ~data & DB9_FIRE2);
+ break;
+
+ case DB9_GENESIS5_PAD:
+
+ parport_write_control(port, DB9_NOSELECT);
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
+ input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
+ input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
+ break;
+
+ case DB9_GENESIS6_PAD:
+
+ parport_write_control(port, DB9_NOSELECT); /* 1 */
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+ input_report_key(dev, BTN_B, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_C, ~data & DB9_FIRE2);
+
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data & DB9_FIRE1);
+ input_report_key(dev, BTN_X, ~data & DB9_FIRE2);
+
+ parport_write_control(port, DB9_NOSELECT); /* 2 */
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NOSELECT); /* 3 */
+ udelay(DB9_GENESIS6_DELAY);
+ data=parport_read_data(port);
+
+ input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
+ input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
+ input_report_key(dev, BTN_MODE, ~data & DB9_UP);
+ input_report_key(dev, BTN_START, ~data & DB9_RIGHT);
+
+ parport_write_control(port, DB9_NORMAL);
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NOSELECT); /* 4 */
+ udelay(DB9_GENESIS6_DELAY);
+ parport_write_control(port, DB9_NORMAL);
+ break;
+
+ case DB9_SATURN_PAD:
+
+ parport_write_control(port, DB9_SATURN0);
+ data = parport_read_data(port);
+
+ input_report_key(dev, BTN_Y, ~data & DB9_LEFT);
+ input_report_key(dev, BTN_Z, ~data & DB9_DOWN);
+ input_report_key(dev, BTN_TL, ~data & DB9_UP);
+ input_report_key(dev, BTN_TR, ~data & DB9_RIGHT);
+
+ parport_write_control(port, DB9_SATURN2);
+ data = parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+
+ parport_write_control(port, DB9_NORMAL);
+ data = parport_read_data(port);
+
+ input_report_key(dev, BTN_A, ~data & DB9_LEFT);
+ input_report_key(dev, BTN_B, ~data & DB9_UP);
+ input_report_key(dev, BTN_C, ~data & DB9_DOWN);
+ input_report_key(dev, BTN_X, ~data & DB9_RIGHT);
+ break;
+
+ case DB9_CD32_PAD:
+
+ data=parport_read_data(port);
+
+ input_report_abs(dev, ABS_X, (data & DB9_RIGHT ? 0 : 1) - (data & DB9_LEFT ? 0 : 1));
+ input_report_abs(dev, ABS_Y, (data & DB9_DOWN ? 0 : 1) - (data & DB9_UP ? 0 : 1));
+
+ parport_write_control(port, 0x0a);
+
+ for (i = 0; i < 7; i++) {
+ data = parport_read_data(port);
+ parport_write_control(port, 0x02);
+ parport_write_control(port, 0x0a);
+ input_report_key(dev, db9_cd32_btn[i], ~data & DB9_FIRE2);
+ }
+
+ parport_write_control(port, 0x00);
+ break;
+ }
+
+ mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+}
+
+static int db9_open(struct input_dev *dev)
+{
+ struct db9 *db9 = dev->private;
+ struct parport *port = db9->pd->port;
+
+ if (!db9->used++) {
+ parport_claim(db9->pd);
+ parport_write_data(port, 0xff);
+ parport_data_reverse(port);
+ parport_write_control(port, DB9_NORMAL);
+ mod_timer(&db9->timer, jiffies + DB9_REFRESH_TIME);
+ }
+
+ return 0;
+}
+
+static void db9_close(struct input_dev *dev)
+{
+ struct db9 *db9 = dev->private;
+ struct parport *port = db9->pd->port;
+
+ if (!--db9->used) {
+ del_timer(&db9->timer);
+ parport_write_control(port, 0x00);
+ parport_data_forward(port);
+ parport_release(db9->pd);
+ }
+}
+
+static struct db9 __init *db9_probe(int *config)
+{
+ struct db9 *db9;
+ struct parport *pp;
+ int i, j;
+
+ if (config[0] < 0)
+ return NULL;
+ if (config[1] < 1 || config[1] >= DB9_MAX_PAD || !db9_buttons[config[1]]) {
+ printk(KERN_ERR "db9.c: bad config\n");
+ return NULL;
+ }
+
+ for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+ config[0]--;
+
+ if (!pp) {
+ printk(KERN_ERR "db9.c: no such parport\n");
+ return NULL;
+ }
+
+ if (!(pp->modes & PARPORT_MODE_TRISTATE) && config[1] != DB9_MULTI_0802) {
+ printk(KERN_ERR "db9.c: specified parport is not bidirectional\n");
+ return NULL;
+ }
+
+ if (!(db9 = kmalloc(sizeof(struct db9), GFP_KERNEL)))
+ return NULL;
+ memset(db9, 0, sizeof(struct db9));
+
+ db9->mode = config[1];
+ init_timer(&db9->timer);
+ db9->timer.data = (long) db9;
+ db9->timer.function = db9_timer;
+
+ db9->pd = parport_register_device(pp, "db9", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+ if (!db9->pd) {
+ printk(KERN_ERR "db9.c: parport busy already - lp.o loaded?\n");
+ kfree(db9);
+ return NULL;
+ }
+
+ for (i = 0; i < 1 + (db9->mode == DB9_MULTI_0802_2); i++) {
+
+ db9->dev[i].private = db9;
+ db9->dev[i].open = db9_open;
+ db9->dev[i].close = db9_close;
+
+ db9->dev[i].name = db9_name[db9->mode];
+ db9->dev[i].idbus = BUS_PARPORT;
+ db9->dev[i].idvendor = 0x0002;
+ db9->dev[i].idproduct = config[1];
+ db9->dev[i].idversion = 0x0100;
+
+ db9->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ db9->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ for (j = 0; j < db9_buttons[db9->mode]; j++)
+ set_bit(db9_btn[db9->mode][j], db9->dev[i].keybit);
+
+ db9->dev[i].absmin[ABS_X] = -1; db9->dev[i].absmax[ABS_X] = 1;
+ db9->dev[i].absmin[ABS_Y] = -1; db9->dev[i].absmax[ABS_Y] = 1;
+
+ input_register_device(db9->dev + i);
+ printk(KERN_INFO "input%d: %s on %s\n",
+ db9->dev[i].number, db9_name[db9->mode], db9->pd->port->name);
+ }
+
+ return db9;
+}
+
+#ifndef MODULE
+int __init db9_setup(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9[i] = ints[i + 1];
+ return 1;
+}
+int __init db9_setup_2(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9_2[i] = ints[i + 1];
+ return 1;
+}
+int __init db9_setup_3(char *str)
+{
+ int i, ints[3];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 2; i++) db9_3[i] = ints[i + 1];
+ return 1;
+}
+__setup("db9=", db9_setup);
+__setup("db9_2=", db9_setup_2);
+__setup("db9_3=", db9_setup_3);
+#endif
+
+int __init db9_init(void)
+{
+ db9_base[0] = db9_probe(db9);
+ db9_base[1] = db9_probe(db9_2);
+ db9_base[2] = db9_probe(db9_3);
+
+ if (db9_base[0] || db9_base[1] || db9_base[2])
+ return 0;
+
+ return -ENODEV;
+}
+
+void __exit db9_exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ if (db9_base[i]) {
+ for (j = 0; j < 1 + (db9_base[i]->mode == DB9_MULTI_0802_2); j++)
+ input_unregister_device(db9_base[i]->dev + j);
+ parport_unregister_device(db9_base[i]->pd);
+ }
+}
+
+module_init(db9_init);
+module_exit(db9_exit);
--- /dev/null
+/*
+ * $Id: gamecon.c,v 1.14 2001/04/29 22:42:14 vojtech Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Andree Borrmann John Dahlstrom
+ * David Kuder Nathan Hand
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * NES, SNES, N64, Multi1, Multi2, PSX gamepad driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/delay.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(gc, "2-6i");
+MODULE_PARM(gc_2,"2-6i");
+MODULE_PARM(gc_3,"2-6i");
+
+#define GC_SNES 1
+#define GC_NES 2
+#define GC_NES4 3
+#define GC_MULTI 4
+#define GC_MULTI2 5
+#define GC_N64 6
+#define GC_PSX 7
+
+#define GC_MAX 7
+
+#define GC_REFRESH_TIME HZ/100
+
+struct gc {
+ struct pardevice *pd;
+ struct input_dev dev[5];
+ struct timer_list timer;
+ unsigned char pads[GC_MAX + 1];
+ int used;
+};
+
+static struct gc *gc_base[3];
+
+static int gc[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
+static int gc_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
+
+static int gc_status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
+
+static char *gc_names[] = { NULL, "SNES pad", "NES pad", "NES FourPort", "Multisystem joystick",
+ "Multisystem 2-button joystick", "N64 controller", "PSX controller" };
+/*
+ * N64 support.
+ */
+
+static unsigned char gc_n64_bytes[] = { 0, 1, 13, 15, 14, 12, 10, 11, 2, 3 };
+static short gc_n64_btn[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TRIGGER, BTN_START };
+
+#define GC_N64_LENGTH 32 /* N64 bit length, not including stop bit */
+#define GC_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
+#define GC_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
+#define GC_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
+#define GC_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
+ /* GC_N64_DWS > 24 is known to fail */
+#define GC_N64_POWER_W 0xe2 /* power during write (transmit request) */
+#define GC_N64_POWER_R 0xfd /* power during read */
+#define GC_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 GC_N64_OUT is pulled low on the output port (by any routine) for more */
+ /* than 123 us */
+#define GC_N64_CLOCK 0x02 /* clock bits for read */
+
+/*
+ * gc_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 gc_n64_read_packet(struct gc *gc, unsigned char *data)
+{
+ int i;
+ unsigned long flags;
+
+/*
+ * Request the pad to transmit data
+ */
+
+ __save_flags(flags);
+ __cli();
+ for (i = 0; i < GC_N64_REQUEST_LENGTH; i++) {
+ parport_write_data(gc->pd->port, GC_N64_POWER_W | ((GC_N64_REQUEST >> i) & 1 ? GC_N64_OUT : 0));
+ udelay(GC_N64_DWS);
+ }
+ __restore_flags(flags);
+
+/*
+ * Wait for the pad response to be loaded into the 33-bit register of the adapter
+ */
+
+ udelay(GC_N64_DELAY);
+
+/*
+ * Grab data (ignoring the last bit, which is a stop bit)
+ */
+
+ for (i = 0; i < GC_N64_LENGTH; i++) {
+ parport_write_data(gc->pd->port, GC_N64_POWER_R);
+ data[i] = parport_read_status(gc->pd->port);
+ parport_write_data(gc->pd->port, GC_N64_POWER_R | GC_N64_CLOCK);
+ }
+
+/*
+ * We must wait 200 ms here for the controller to reinitialize before the next read request.
+ * No worries as long as gc_read is polled less frequently than this.
+ */
+
+}
+
+/*
+ * NES/SNES support.
+ */
+
+#define GC_NES_DELAY 6 /* Delay between bits - 6us */
+#define GC_NES_LENGTH 8 /* The NES pads use 8 bits of data */
+#define GC_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
+
+#define GC_NES_POWER 0xfc
+#define GC_NES_CLOCK 0x01
+#define GC_NES_LATCH 0x02
+
+static unsigned char gc_nes_bytes[] = { 0, 1, 2, 3 };
+static unsigned char gc_snes_bytes[] = { 8, 0, 2, 3, 9, 1, 10, 11 };
+static short gc_snes_btn[] = { BTN_A, BTN_B, BTN_SELECT, BTN_START, BTN_X, BTN_Y, BTN_TL, BTN_TR };
+
+/*
+ * gc_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 gc_nes_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i;
+
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK | GC_NES_LATCH);
+ udelay(GC_NES_DELAY * 2);
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+
+ for (i = 0; i < length; i++) {
+ udelay(GC_NES_DELAY);
+ parport_write_data(gc->pd->port, GC_NES_POWER);
+ data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+ udelay(GC_NES_DELAY);
+ parport_write_data(gc->pd->port, GC_NES_POWER | GC_NES_CLOCK);
+ }
+}
+
+/*
+ * Multisystem joystick support
+ */
+
+#define GC_MULTI_LENGTH 5 /* Multi system joystick packet length is 5 */
+#define GC_MULTI2_LENGTH 6 /* One more bit for one more button */
+
+/*
+ * gc_multi_read_packet() reads a Multisystem joystick packet.
+ */
+
+static void gc_multi_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i;
+
+ for (i = 0; i < length; i++) {
+ parport_write_data(gc->pd->port, ~(1 << i));
+ data[i] = parport_read_status(gc->pd->port) ^ 0x7f;
+ }
+}
+
+/*
+ * PSX support
+ *
+ * See documentation at:
+ * http://www.dim.com/~mackys/psxmemcard/ps-eng2.txt
+ * http://www.gamesx.com/controldata/psxcont/psxcont.htm
+ * ftp://milano.usal.es/pablo/
+ *
+ */
+
+#define GC_PSX_DELAY 60 /* 60 usec */
+#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE 1 /* Mouse */
+#define GC_PSX_NEGCON 2 /* NegCon */
+#define GC_PSX_NORMAL 4 /* Digital / Analog or Rumble in Digital mode */
+#define GC_PSX_ANALOG 5 /* Analog in Analog mode / Rumble in Green mode */
+#define GC_PSX_RUMBLE 7 /* Rumble in Red mode */
+
+#define GC_PSX_CLOCK 0x04 /* Pin 4 */
+#define GC_PSX_COMMAND 0x01 /* Pin 1 */
+#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
+#define GC_PSX_SELECT 0x02 /* Pin 3 */
+
+#define GC_PSX_ID(x) ((x) >> 4) /* High nibble is device type */
+#define GC_PSX_LEN(x) ((x) & 0xf) /* Low nibble is length in words */
+
+static short gc_psx_abs[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_HAT0X, ABS_HAT0Y };
+static short gc_psx_btn[] = { BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_A, BTN_B, BTN_X, BTN_Y,
+ BTN_START, BTN_SELECT, BTN_THUMBL, BTN_THUMBR };
+
+/*
+ * gc_psx_command() writes 8bit command and reads 8bit data from
+ * the psx pad.
+ */
+
+static int gc_psx_command(struct gc *gc, int b)
+{
+ int i, cmd, data = 0;
+
+ for (i = 0; i < 8; i++, b >>= 1) {
+ cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+ parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ data |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
+ parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ }
+ return data;
+}
+
+/*
+ * gc_psx_read_packet() reads a whole psx packet and returns
+ * device identifier code.
+ */
+
+static int gc_psx_read_packet(struct gc *gc, unsigned char *data)
+{
+ int i, id;
+ unsigned long flags;
+
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
+ udelay(GC_PSX_DELAY * 2);
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_POWER); /* Deselect, begin command */
+ udelay(GC_PSX_DELAY * 2);
+
+ __save_flags(flags);
+ __cli();
+
+ gc_psx_command(gc, 0x01); /* Access pad */
+ id = gc_psx_command(gc, 0x42); /* Get device id */
+ if (gc_psx_command(gc, 0) == 0x5a) { /* Okay? */
+ for (i = 0; i < GC_PSX_LEN(id) * 2; i++)
+ data[i] = gc_psx_command(gc, 0);
+ } else id = 0;
+
+ __restore_flags(flags);
+
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER);
+
+ return GC_PSX_ID(id);
+}
+
+/*
+ * gc_timer() reads and analyzes console pads data.
+ */
+
+#define GC_MAX_LENGTH GC_N64_LENGTH
+
+static void gc_timer(unsigned long private)
+{
+ struct gc *gc = (void *) private;
+ struct input_dev *dev = gc->dev;
+ unsigned char data[GC_MAX_LENGTH];
+ int i, j, s;
+
+/*
+ * N64 pads - must be read first, any read confuses them for 200 us
+ */
+
+ if (gc->pads[GC_N64]) {
+
+ gc_n64_read_packet(gc, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & gc->pads[GC_N64] & ~(data[8] | data[9])) {
+
+ signed char axes[2];
+ axes[0] = axes[1] = 0;
+
+ for (j = 0; j < 8; j++) {
+ if (data[23 - j] & s) axes[0] |= 1 << j;
+ if (data[31 - j] & s) axes[1] |= 1 << j;
+ }
+
+ input_report_abs(dev + i, ABS_X, axes[0]);
+ input_report_abs(dev + i, ABS_Y, -axes[1]);
+
+ input_report_abs(dev + i, ABS_HAT0X, !(s & data[6]) - !(s & data[7]));
+ input_report_abs(dev + i, ABS_HAT0Y, !(s & data[4]) - !(s & data[5]));
+
+ for (j = 0; j < 10; j++)
+ input_report_key(dev + i, gc_n64_btn[j], s & data[gc_n64_bytes[j]]);
+ }
+ }
+ }
+
+/*
+ * NES and SNES pads
+ */
+
+ if (gc->pads[GC_NES] || gc->pads[GC_SNES]) {
+
+ gc_nes_read_packet(gc, gc->pads[GC_SNES] ? GC_SNES_LENGTH : GC_NES_LENGTH, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & (gc->pads[GC_NES] | gc->pads[GC_SNES])) {
+ input_report_abs(dev + i, ABS_X, !(s & data[6]) - !(s & data[7]));
+ input_report_abs(dev + i, ABS_Y, !(s & data[4]) - !(s & data[5]));
+ }
+
+ if (s & gc->pads[GC_NES])
+ for (j = 0; j < 4; j++)
+ input_report_key(dev + i, gc_snes_btn[j], s & data[gc_nes_bytes[j]]);
+
+ if (s & gc->pads[GC_SNES])
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_snes_btn[j], s & data[gc_snes_bytes[j]]);
+ }
+ }
+
+/*
+ * Multi and Multi2 joysticks
+ */
+
+ if (gc->pads[GC_MULTI] || gc->pads[GC_MULTI2]) {
+
+ gc_multi_read_packet(gc, gc->pads[GC_MULTI2] ? GC_MULTI2_LENGTH : GC_MULTI_LENGTH, data);
+
+ for (i = 0; i < 5; i++) {
+
+ s = gc_status_bit[i];
+
+ if (s & (gc->pads[GC_MULTI] | gc->pads[GC_MULTI2])) {
+ input_report_abs(dev + i, ABS_X, !(s & data[2]) - !(s & data[3]));
+ input_report_abs(dev + i, ABS_Y, !(s & data[0]) - !(s & data[1]));
+ input_report_key(dev + i, BTN_TRIGGER, s & data[4]);
+ }
+
+ if (s & gc->pads[GC_MULTI2])
+ input_report_key(dev + i, BTN_THUMB, s & data[5]);
+ }
+ }
+
+/*
+ * PSX controllers
+ */
+
+ if (gc->pads[GC_PSX]) {
+
+ for (i = 0; i < 5; i++)
+ if (gc->pads[GC_PSX] & gc_status_bit[i])
+ break;
+
+ switch (gc_psx_read_packet(gc, data)) {
+
+ case GC_PSX_RUMBLE:
+
+ input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
+ input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+ case GC_PSX_NEGCON:
+ case GC_PSX_ANALOG:
+
+ for (j = 0; j < 4; j++)
+ input_report_abs(dev + i, gc_psx_abs[j], data[j + 2]);
+
+ input_report_abs(dev + i, ABS_HAT0X, !(data[0] & 0x20) - !(data[0] & 0x80));
+ input_report_abs(dev + i, ABS_HAT0Y, !(data[0] & 0x40) - !(data[0] & 0x10));
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
+
+ input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+ break;
+
+ case GC_PSX_NORMAL:
+
+ input_report_abs(dev + i, ABS_X, 128 + !(data[0] & 0x20) * 127 - !(data[0] & 0x80) * 128);
+ input_report_abs(dev + i, ABS_Y, 128 + !(data[0] & 0x40) * 127 - !(data[0] & 0x10) * 128);
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev + i, gc_psx_btn[j], ~data[1] & (1 << j));
+
+ input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+ break;
+ }
+ }
+
+ mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+}
+
+static int gc_open(struct input_dev *dev)
+{
+ struct gc *gc = dev->private;
+ if (!gc->used++) {
+ parport_claim(gc->pd);
+ parport_write_control(gc->pd->port, 0x04);
+ mod_timer(&gc->timer, jiffies + GC_REFRESH_TIME);
+ }
+ return 0;
+}
+
+static void gc_close(struct input_dev *dev)
+{
+ struct gc *gc = dev->private;
+ if (!--gc->used) {
+ del_timer(&gc->timer);
+ parport_write_control(gc->pd->port, 0x00);
+ parport_release(gc->pd);
+ }
+}
+
+static struct gc __init *gc_probe(int *config)
+{
+ struct gc *gc;
+ struct parport *pp;
+ int i, j, psx;
+ unsigned char data[32];
+
+ if (config[0] < 0)
+ return NULL;
+
+ for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+ config[0]--;
+
+ if (!pp) {
+ printk(KERN_ERR "gamecon.c: no such parport\n");
+ return NULL;
+ }
+
+ if (!(gc = kmalloc(sizeof(struct gc), GFP_KERNEL)))
+ return NULL;
+ memset(gc, 0, sizeof(struct gc));
+
+ gc->pd = parport_register_device(pp, "gamecon", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+ if (!gc->pd) {
+ printk(KERN_ERR "gamecon.c: parport busy already - lp.o loaded?\n");
+ kfree(gc);
+ return NULL;
+ }
+
+ parport_claim(gc->pd);
+
+ init_timer(&gc->timer);
+ gc->timer.data = (long) gc;
+ gc->timer.function = gc_timer;
+
+ for (i = 0; i < 5; i++) {
+
+ if (!config[i + 1])
+ continue;
+
+ if (config[i + 1] < 1 || config[i + 1] > GC_MAX) {
+ printk(KERN_WARNING "gamecon.c: Pad type %d unknown\n", config[i + 1]);
+ continue;
+ }
+
+ gc->dev[i].private = gc;
+ gc->dev[i].open = gc_open;
+ gc->dev[i].close = gc_close;
+
+ gc->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; j < 2; j++) {
+ set_bit(ABS_X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_X + j] = -1;
+ gc->dev[i].absmax[ABS_X + j] = 1;
+ }
+
+ gc->pads[0] |= gc_status_bit[i];
+ gc->pads[config[i + 1]] |= gc_status_bit[i];
+
+ switch(config[i + 1]) {
+
+ case GC_N64:
+ for (j = 0; j < 10; j++)
+ set_bit(gc_n64_btn[j], gc->dev[i].keybit);
+
+ for (j = 0; j < 2; j++) {
+ set_bit(ABS_X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_X + j] = -127;
+ gc->dev[i].absmax[ABS_X + j] = 126;
+ gc->dev[i].absflat[ABS_X + j] = 2;
+ set_bit(ABS_HAT0X + j, gc->dev[i].absbit);
+ gc->dev[i].absmin[ABS_HAT0X + j] = -1;
+ gc->dev[i].absmax[ABS_HAT0X + j] = 1;
+ }
+
+ break;
+
+ case GC_SNES:
+ for (j = 4; j < 8; j++)
+ set_bit(gc_snes_btn[j], gc->dev[i].keybit);
+ case GC_NES:
+ for (j = 0; j < 4; j++)
+ set_bit(gc_snes_btn[j], gc->dev[i].keybit);
+ break;
+
+ case GC_MULTI2:
+ set_bit(BTN_THUMB, gc->dev[i].keybit);
+ case GC_MULTI:
+ set_bit(BTN_TRIGGER, gc->dev[i].keybit);
+ break;
+
+ case GC_PSX:
+
+ psx = gc_psx_read_packet(gc, data);
+
+ switch(psx) {
+ case GC_PSX_NEGCON:
+ case GC_PSX_NORMAL:
+ case GC_PSX_ANALOG:
+ case GC_PSX_RUMBLE:
+
+ for (j = 0; j < 6; j++) {
+ psx = gc_psx_abs[j];
+ set_bit(psx, gc->dev[i].absbit);
+ if (j < 4) {
+ gc->dev[i].absmin[psx] = 4;
+ gc->dev[i].absmax[psx] = 252;
+ gc->dev[i].absflat[psx] = 2;
+ } else {
+ gc->dev[i].absmin[psx] = -1;
+ gc->dev[i].absmax[psx] = 1;
+ }
+ }
+
+ for (j = 0; j < 12; j++)
+ set_bit(gc_psx_btn[j], gc->dev[i].keybit);
+
+ break;
+
+ case 0:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
+ break;
+
+ default:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
+ " please report to <vojtech@suse.cz>.\n", psx);
+ }
+ break;
+ }
+
+ gc->dev[i].name = gc_names[config[i + 1]];
+ gc->dev[i].idbus = BUS_PARPORT;
+ gc->dev[i].idvendor = 0x0001;
+ gc->dev[i].idproduct = config[i + 1];
+ gc->dev[i].idversion = 0x0100;
+ }
+
+ parport_release(gc->pd);
+
+ if (!gc->pads[0]) {
+ parport_unregister_device(gc->pd);
+ kfree(gc);
+ return NULL;
+ }
+
+ for (i = 0; i < 5; i++)
+ if (gc->pads[0] & gc_status_bit[i]) {
+ input_register_device(gc->dev + i);
+ printk(KERN_INFO "input%d: %s on %s\n", gc->dev[i].number, gc->dev[i].name, gc->pd->port->name);
+ }
+
+ return gc;
+}
+
+#ifndef MODULE
+int __init gc_setup(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc[i] = ints[i + 1];
+ return 1;
+}
+int __init gc_setup_2(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc_2[i] = ints[i + 1];
+ return 1;
+}
+int __init gc_setup_3(char *str)
+{
+ int i, ints[7];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 6; i++) gc_3[i] = ints[i + 1];
+ return 1;
+}
+__setup("gc=", gc_setup);
+__setup("gc_2=", gc_setup_2);
+__setup("gc_3=", gc_setup_3);
+#endif
+
+int __init gc_init(void)
+{
+ gc_base[0] = gc_probe(gc);
+ gc_base[1] = gc_probe(gc_2);
+ gc_base[2] = gc_probe(gc_3);
+
+ if (gc_base[0] || gc_base[1] || gc_base[2])
+ return 0;
+
+ return -ENODEV;
+}
+
+void __exit gc_exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ if (gc_base[i]) {
+ for (j = 0; j < 5; j++)
+ if (gc_base[i]->pads[0] & gc_status_bit[j])
+ input_unregister_device(gc_base[i]->dev + j);
+ parport_unregister_device(gc_base[i]->pd);
+ }
+}
+
+module_init(gc_init);
+module_exit(gc_exit);
--- /dev/null
+/*
+ * $Id: gf2k.c,v 1.12 2000/06/04 14:53:44 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Genius Flight 2000 joystick driver for Linux
+ */
+
+/*
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+#define GF2K_START 400 /* The time we wait for the first bit [400 us] */
+#define GF2K_STROBE 40 /* The time we wait for the first bit [40 us] */
+#define GF2K_TIMEOUT 4 /* Wait for everything to settle [4 ms] */
+#define GF2K_LENGTH 80 /* Max number of triplets in a packet */
+#define GF2K_REFRESH HZ/50 /* Time between joystick polls [20 ms] */
+
+/*
+ * Genius joystick ids ...
+ */
+
+#define GF2K_ID_G09 1
+#define GF2K_ID_F30D 2
+#define GF2K_ID_F30 3
+#define GF2K_ID_F31D 4
+#define GF2K_ID_F305 5
+#define GF2K_ID_F23P 6
+#define GF2K_ID_F31 7
+#define GF2K_ID_MAX 7
+
+static char gf2k_length[] = { 40, 40, 40, 40, 40, 40, 40, 40 };
+static char gf2k_hat_to_axis[][2] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+static char *gf2k_names[] = {"", "Genius G-09D", "Genius F-30D", "Genius F-30", "Genius MaxFighter F-31D",
+ "Genius F-30-5", "Genius Flight2000 F-23", "Genius F-31"};
+static unsigned char gf2k_hats[] = { 0, 2, 0, 0, 2, 0, 2, 0 };
+static unsigned char gf2k_axes[] = { 0, 2, 0, 0, 4, 0, 4, 0 };
+static unsigned char gf2k_joys[] = { 0, 0, 0, 0,10, 0, 8, 0 };
+static unsigned char gf2k_pads[] = { 0, 6, 0, 0, 0, 0, 0, 0 };
+static unsigned char gf2k_lens[] = { 0,18, 0, 0,18, 0,18, 0 };
+
+static unsigned char gf2k_abs[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_RUDDER, ABS_GAS, ABS_BRAKE };
+static short gf2k_btn_joy[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 };
+static short gf2k_btn_pad[] = { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_TL2, BTN_TR2, BTN_START, BTN_SELECT };
+
+
+static short gf2k_seq_reset[] = { 240, 340, 0 };
+static short gf2k_seq_digital[] = { 590, 320, 860, 0 };
+
+struct gf2k {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev;
+ int reads;
+ int bads;
+ int used;
+ unsigned char id;
+ unsigned char length;
+};
+
+/*
+ * gf2k_read_packet() reads a Genius Flight2000 packet.
+ */
+
+static int gf2k_read_packet(struct gameport *gameport, int length, char *data)
+{
+ unsigned char u, v;
+ int i;
+ unsigned int t, p;
+ unsigned long flags;
+
+ t = gameport_time(gameport, GF2K_START);
+ p = gameport_time(gameport, GF2K_STROBE);
+
+ i = 0;
+
+ __save_flags(flags);
+ __cli();
+
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);;
+
+ while (t > 0 && i < length) {
+ t--; u = v;
+ v = gameport_read(gameport);
+ if (v & ~u & 0x10) {
+ data[i++] = v >> 5;
+ t = p;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * gf2k_trigger_seq() initializes a Genius Flight2000 joystick
+ * into digital mode.
+ */
+
+static void gf2k_trigger_seq(struct gameport *gameport, short *seq)
+{
+
+ unsigned long flags;
+ int i, t;
+
+ __save_flags(flags);
+ __cli();
+
+ i = 0;
+ do {
+ gameport_trigger(gameport);
+ t = gameport_time(gameport, GF2K_TIMEOUT * 1000);
+ while ((gameport_read(gameport) & 1) && t) t--;
+ udelay(seq[i]);
+ } while (seq[++i]);
+
+ gameport_trigger(gameport);
+
+ __restore_flags(flags);
+}
+
+/*
+ * js_sw_get_bits() composes 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(p,n,s) gf2k_get_bits(data, p, n, s)
+
+static int gf2k_get_bits(unsigned char *buf, int pos, int num, int shift)
+{
+ __u64 data = 0;
+ int i;
+
+ for (i = 0; i < num / 3 + 2; i++)
+ data |= buf[pos / 3 + i] << (i * 3);
+ data >>= pos % 3;
+ data &= (1 << num) - 1;
+ data <<= shift;
+
+ return data;
+}
+
+static void gf2k_read(struct gf2k *gf2k, unsigned char *data)
+{
+ struct input_dev *dev = &gf2k->dev;
+ int i, t;
+
+ for (i = 0; i < 4 && i < gf2k_axes[gf2k->id]; i++)
+ input_report_abs(dev, gf2k_abs[i], GB(i<<3,8,0) | GB(i+46,1,8) | GB(i+50,1,9));
+
+ for (i = 0; i < 2 && i < gf2k_axes[gf2k->id] - 4; i++)
+ input_report_abs(dev, gf2k_abs[i], GB(i*9+60,8,0) | GB(i+54,1,9));
+
+ t = GB(40,4,0);
+
+ for (i = 0; i < gf2k_hats[gf2k->id]; i++)
+ input_report_abs(dev, ABS_HAT0X + i, gf2k_hat_to_axis[t][i]);
+
+ t = GB(44,2,0) | GB(32,8,2) | GB(78,2,10);
+
+ for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+ input_report_key(dev, gf2k_btn_joy[i], (t >> i) & 1);
+
+ for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+ input_report_key(dev, gf2k_btn_pad[i], (t >> i) & 1);
+}
+
+/*
+ * gf2k_timer() reads and analyzes Genius joystick data.
+ */
+
+static void gf2k_timer(unsigned long private)
+{
+ struct gf2k *gf2k = (void *) private;
+ unsigned char data[GF2K_LENGTH];
+
+ gf2k->reads++;
+
+ if (gf2k_read_packet(gf2k->gameport, gf2k_length[gf2k->id], data) < gf2k_length[gf2k->id]) {
+ gf2k->bads++;
+ } else gf2k_read(gf2k, data);
+
+ mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+}
+
+static int gf2k_open(struct input_dev *dev)
+{
+ struct gf2k *gf2k = dev->private;
+ if (!gf2k->used++)
+ mod_timer(&gf2k->timer, jiffies + GF2K_REFRESH);
+ return 0;
+}
+
+static void gf2k_close(struct input_dev *dev)
+{
+ struct gf2k *gf2k = dev->private;
+ if (!--gf2k->used)
+ del_timer(&gf2k->timer);
+}
+
+/*
+ * gf2k_connect() probes for Genius id joysticks.
+ */
+
+static void gf2k_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct gf2k *gf2k;
+ unsigned char data[GF2K_LENGTH];
+ int i;
+
+ if (!(gf2k = kmalloc(sizeof(struct gf2k), GFP_KERNEL)))
+ return;
+ memset(gf2k, 0, sizeof(struct gf2k));
+
+ gameport->private = gf2k;
+
+ gf2k->gameport = gameport;
+ init_timer(&gf2k->timer);
+ gf2k->timer.data = (long) gf2k;
+ gf2k->timer.function = gf2k_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ gf2k_trigger_seq(gameport, gf2k_seq_reset);
+
+ wait_ms(GF2K_TIMEOUT);
+
+ gf2k_trigger_seq(gameport, gf2k_seq_digital);
+
+ wait_ms(GF2K_TIMEOUT);
+
+ if (gf2k_read_packet(gameport, GF2K_LENGTH, data) < 12)
+ goto fail2;
+
+ if (!(gf2k->id = GB(7,2,0) | GB(3,3,2) | GB(0,3,5)))
+ goto fail2;
+
+#ifdef RESET_WORKS
+ if ((gf2k->id != (GB(19,2,0) | GB(15,3,2) | GB(12,3,5))) ||
+ (gf2k->id != (GB(31,2,0) | GB(27,3,2) | GB(24,3,5))))
+ goto fail2;
+#else
+ gf2k->id = 6;
+#endif
+
+ if (gf2k->id > GF2K_ID_MAX || !gf2k_axes[gf2k->id]) {
+ printk(KERN_WARNING "gf2k.c: Not yet supported joystick on gameport%d. [id: %d type:%s]\n",
+ gameport->number, gf2k->id, gf2k->id > GF2K_ID_MAX ? "Unknown" : gf2k_names[gf2k->id]);
+ goto fail2;
+ }
+
+ gf2k->length = gf2k_lens[gf2k->id];
+
+ gf2k->dev.private = gf2k;
+ gf2k->dev.open = gf2k_open;
+ gf2k->dev.close = gf2k_close;
+ gf2k->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ gf2k->dev.name = gf2k_names[gf2k->id];
+ gf2k->dev.idbus = BUS_GAMEPORT;
+ gf2k->dev.idvendor = GAMEPORT_ID_VENDOR_GENIUS;
+ gf2k->dev.idproduct = gf2k->id;
+ gf2k->dev.idversion = 0x0100;
+
+ for (i = 0; i < gf2k_axes[gf2k->id]; i++)
+ set_bit(gf2k_abs[i], gf2k->dev.absbit);
+
+ for (i = 0; i < gf2k_hats[gf2k->id]; i++) {
+ set_bit(ABS_HAT0X + i, gf2k->dev.absbit);
+ gf2k->dev.absmin[ABS_HAT0X + i] = -1;
+ gf2k->dev.absmax[ABS_HAT0X + i] = 1;
+ }
+
+ for (i = 0; i < gf2k_joys[gf2k->id]; i++)
+ set_bit(gf2k_btn_joy[i], gf2k->dev.keybit);
+
+ for (i = 0; i < gf2k_pads[gf2k->id]; i++)
+ set_bit(gf2k_btn_pad[i], gf2k->dev.keybit);
+
+ gf2k_read_packet(gameport, gf2k->length, data);
+ gf2k_read(gf2k, data);
+
+ for (i = 0; i < gf2k_axes[gf2k->id]; i++) {
+ gf2k->dev.absmax[gf2k_abs[i]] = (i < 2) ? gf2k->dev.abs[gf2k_abs[i]] * 2 - 32 :
+ gf2k->dev.abs[gf2k_abs[0]] + gf2k->dev.abs[gf2k_abs[1]] - 32;
+ gf2k->dev.absmin[gf2k_abs[i]] = 32;
+ gf2k->dev.absfuzz[gf2k_abs[i]] = 8;
+ gf2k->dev.absflat[gf2k_abs[i]] = (i < 2) ? 24 : 0;
+ }
+
+ input_register_device(&gf2k->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ gf2k->dev.number, gf2k_names[gf2k->id], gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(gf2k);
+}
+
+static void gf2k_disconnect(struct gameport *gameport)
+{
+ struct gf2k *gf2k = gameport->private;
+ input_unregister_device(&gf2k->dev);
+ gameport_close(gameport);
+ kfree(gf2k);
+}
+
+static struct gameport_dev gf2k_dev = {
+ connect: gf2k_connect,
+ disconnect: gf2k_disconnect,
+};
+
+int __init gf2k_init(void)
+{
+ gameport_register_device(&gf2k_dev);
+ return 0;
+}
+
+void __exit gf2k_exit(void)
+{
+ gameport_unregister_device(&gf2k_dev);
+}
+
+module_init(gf2k_init);
+module_exit(gf2k_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: grip.c,v 1.14 2000/06/06 21:13:36 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Gravis/Kensington GrIP protocol joystick and gamepad driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/slab.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define GRIP_MODE_GPP 1
+#define GRIP_MODE_BD 2
+#define GRIP_MODE_XT 3
+#define GRIP_MODE_DC 4
+
+#define GRIP_LENGTH_GPP 24
+#define GRIP_STROBE_GPP 200 /* 200 us */
+#define GRIP_LENGTH_XT 4
+#define GRIP_STROBE_XT 64 /* 64 us */
+#define GRIP_MAX_CHUNKS_XT 10
+#define GRIP_MAX_BITS_XT 30
+
+#define GRIP_REFRESH_TIME HZ/50 /* 20 ms */
+
+struct grip {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ unsigned char mode[2];
+ int used;
+ int reads;
+ int bads;
+};
+
+static int grip_btn_gpp[] = { BTN_START, BTN_SELECT, BTN_TR2, BTN_Y, 0, BTN_TL2, BTN_A, BTN_B, BTN_X, 0, BTN_TL, BTN_TR, -1 };
+static int grip_btn_bd[] = { BTN_THUMB, BTN_THUMB2, BTN_TRIGGER, BTN_TOP, BTN_BASE, -1 };
+static int grip_btn_xt[] = { BTN_TRIGGER, BTN_THUMB, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_SELECT, BTN_START, BTN_MODE, -1 };
+static int grip_btn_dc[] = { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, -1 };
+
+static int grip_abs_gpp[] = { ABS_X, ABS_Y, -1 };
+static int grip_abs_bd[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static int grip_abs_xt[] = { ABS_X, ABS_Y, ABS_BRAKE, ABS_GAS, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y, -1 };
+static int grip_abs_dc[] = { ABS_X, ABS_Y, ABS_RX, ABS_RY, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+
+static char *grip_name[] = { NULL, "Gravis GamePad Pro", "Gravis Blackhawk Digital",
+ "Gravis Xterminator Digital", "Gravis Xterminator DualControl" };
+static int *grip_abs[] = { 0, grip_abs_gpp, grip_abs_bd, grip_abs_xt, grip_abs_dc };
+static int *grip_btn[] = { 0, grip_btn_gpp, grip_btn_bd, grip_btn_xt, grip_btn_dc };
+static char grip_anx[] = { 0, 0, 3, 5, 5 };
+static char grip_cen[] = { 0, 0, 2, 2, 4 };
+
+/*
+ * grip_gpp_read_packet() reads a Gravis GamePad Pro packet.
+ */
+
+static int grip_gpp_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t;
+ int i;
+
+ int strobe = gameport_time(gameport, GRIP_STROBE_GPP);
+
+ data[0] = 0;
+ t = strobe;
+ i = 0;
+
+ __save_flags(flags);
+ __cli();
+
+ v = gameport_read(gameport) >> shift;
+
+ do {
+ t--;
+ u = v; v = (gameport_read(gameport) >> shift) & 3;
+ if (~v & u & 1) {
+ data[0] |= (v >> 1) << i++;
+ t = strobe;
+ }
+ } while (i < GRIP_LENGTH_GPP && t > 0);
+
+ __restore_flags(flags);
+
+ if (i < GRIP_LENGTH_GPP) return -1;
+
+ for (i = 0; i < GRIP_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
+ data[0] = data[0] >> 1 | (data[0] & 1) << (GRIP_LENGTH_GPP - 1);
+
+ return -(i == GRIP_LENGTH_GPP);
+}
+
+/*
+ * grip_xt_read_packet() reads a Gravis Xterminator packet.
+ */
+
+static int grip_xt_read_packet(struct gameport *gameport, int shift, unsigned int *data)
+{
+ unsigned int i, j, buf, crc;
+ unsigned char u, v, w;
+ unsigned long flags;
+ unsigned int t;
+ char status;
+
+ int strobe = gameport_time(gameport, GRIP_STROBE_XT);
+
+ data[0] = data[1] = data[2] = data[3] = 0;
+ status = buf = i = j = 0;
+ t = strobe;
+
+ __save_flags(flags);
+ __cli();
+
+ v = w = (gameport_read(gameport) >> shift) & 3;
+
+ do {
+ t--;
+ u = (gameport_read(gameport) >> shift) & 3;
+
+ if (u ^ v) {
+
+ if ((u ^ v) & 1) {
+ buf = (buf << 1) | (u >> 1);
+ t = strobe;
+ i++;
+ } else
+
+ if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
+ 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++;
+ }
+ t = strobe;
+ buf = 0;
+ i = 0;
+ }
+ w = v;
+ v = u;
+ }
+
+ } while (status != 0xf && i < GRIP_MAX_BITS_XT && j < GRIP_MAX_CHUNKS_XT && t > 0);
+
+ __restore_flags(flags);
+
+ return -(status != 0xf);
+}
+
+/*
+ * grip_timer() repeatedly polls the joysticks and generates events.
+ */
+
+static void grip_timer(unsigned long private)
+{
+ struct grip *grip = (void*) private;
+ unsigned int data[GRIP_LENGTH_XT];
+ struct input_dev *dev;
+ int i, j;
+
+ for (i = 0; i < 2; i++) {
+
+ dev = grip->dev + i;
+ grip->reads++;
+
+ switch (grip->mode[i]) {
+
+ case GRIP_MODE_GPP:
+
+ if (grip_gpp_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, ((*data >> 15) & 1) - ((*data >> 16) & 1));
+ input_report_abs(dev, ABS_Y, ((*data >> 13) & 1) - ((*data >> 12) & 1));
+
+ for (j = 0; j < 12; j++)
+ if (grip_btn_gpp[j])
+ input_report_key(dev, grip_btn_gpp[j], (*data >> j) & 1);
+
+ break;
+
+ case GRIP_MODE_BD:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+ for (j = 0; j < 5; j++)
+ input_report_key(dev, grip_btn_bd[j], (data[3] >> (j + 4)) & 1);
+
+ break;
+
+ case GRIP_MODE_XT:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, 63 - ((data[0] >> 8) & 0x3f));
+ input_report_abs(dev, ABS_BRAKE, (data[1] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_GAS, (data[1] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+ input_report_abs(dev, ABS_HAT1X, ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1));
+ input_report_abs(dev, ABS_HAT1Y, ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1));
+
+ for (j = 0; j < 11; j++)
+ input_report_key(dev, grip_btn_xt[j], (data[3] >> (j + 3)) & 1);
+ break;
+
+ case GRIP_MODE_DC:
+
+ if (grip_xt_read_packet(grip->gameport, (i << 1) + 4, data)) {
+ grip->bads++;
+ break;
+ }
+
+ input_report_abs(dev, ABS_X, (data[0] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_Y, (data[0] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_RX, (data[1] >> 2) & 0x3f);
+ input_report_abs(dev, ABS_RY, (data[1] >> 8) & 0x3f);
+ input_report_abs(dev, ABS_THROTTLE, (data[2] >> 8) & 0x3f);
+
+ input_report_abs(dev, ABS_HAT0X, ((data[2] >> 1) & 1) - ( data[2] & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1));
+
+ for (j = 0; j < 9; j++)
+ input_report_key(dev, grip_btn_dc[j], (data[3] >> (j + 3)) & 1);
+ break;
+
+
+ }
+ }
+
+ mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+}
+
+static int grip_open(struct input_dev *dev)
+{
+ struct grip *grip = dev->private;
+ if (!grip->used++)
+ mod_timer(&grip->timer, jiffies + GRIP_REFRESH_TIME);
+ return 0;
+}
+
+static void grip_close(struct input_dev *dev)
+{
+ struct grip *grip = dev->private;
+ if (!--grip->used)
+ del_timer(&grip->timer);
+}
+
+static void grip_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct grip *grip;
+ unsigned int data[GRIP_LENGTH_XT];
+ int i, j, t;
+
+ if (!(grip = kmalloc(sizeof(struct grip), GFP_KERNEL)))
+ return;
+ memset(grip, 0, sizeof(struct grip));
+
+ gameport->private = grip;
+
+ grip->gameport = gameport;
+ init_timer(&grip->timer);
+ grip->timer.data = (long) grip;
+ grip->timer.function = grip_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ for (i = 0; i < 2; i++) {
+ if (!grip_gpp_read_packet(gameport, (i << 1) + 4, data)) {
+ grip->mode[i] = GRIP_MODE_GPP;
+ continue;
+ }
+ if (!grip_xt_read_packet(gameport, (i << 1) + 4, data)) {
+ if (!(data[3] & 7)) {
+ grip->mode[i] = GRIP_MODE_BD;
+ continue;
+ }
+ if (!(data[2] & 0xf0)) {
+ grip->mode[i] = GRIP_MODE_XT;
+ continue;
+ }
+ grip->mode[i] = GRIP_MODE_DC;
+ continue;
+ }
+ }
+
+ if (!grip->mode[0] && !grip->mode[1])
+ goto fail2;
+
+ for (i = 0; i < 2; i++)
+ if (grip->mode[i]) {
+
+ grip->dev[i].private = grip;
+
+ grip->dev[i].open = grip_open;
+ grip->dev[i].close = grip_close;
+
+ grip->dev[i].name = grip_name[grip->mode[i]];
+ grip->dev[i].idbus = BUS_GAMEPORT;
+ grip->dev[i].idvendor = GAMEPORT_ID_VENDOR_GRAVIS;
+ grip->dev[i].idproduct = grip->mode[i];
+ grip->dev[i].idversion = 0x0100;
+
+ grip->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; (t = grip_abs[grip->mode[i]][j]) >= 0; j++) {
+
+ set_bit(t, grip->dev[i].absbit);
+
+ if (j < grip_cen[grip->mode[i]]) {
+ grip->dev[i].absmin[t] = 14;
+ grip->dev[i].absmax[t] = 52;
+ grip->dev[i].absfuzz[t] = 1;
+ grip->dev[i].absflat[t] = 2;
+ continue;
+ }
+
+ if (j < grip_anx[grip->mode[i]]) {
+ grip->dev[i].absmin[t] = 3;
+ grip->dev[i].absmax[t] = 57;
+ grip->dev[i].absfuzz[t] = 1;
+ continue;
+ }
+
+ grip->dev[i].absmin[t] = -1;
+ grip->dev[i].absmax[t] = 1;
+ }
+
+ for (j = 0; (t = grip_btn[grip->mode[i]][j]) >= 0; j++)
+ if (t > 0)
+ set_bit(t, grip->dev[i].keybit);
+
+ input_register_device(grip->dev + i);
+
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ grip->dev[i].number, grip_name[grip->mode[i]], gameport->number, i);
+ }
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(grip);
+}
+
+static void grip_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct grip *grip = gameport->private;
+ for (i = 0; i < 2; i++)
+ if (grip->mode[i])
+ input_unregister_device(grip->dev + i);
+ gameport_close(gameport);
+ kfree(grip);
+}
+
+static struct gameport_dev grip_dev = {
+ connect: grip_connect,
+ disconnect: grip_disconnect,
+};
+
+int __init grip_init(void)
+{
+ gameport_register_device(&grip_dev);
+ return 0;
+}
+
+void __exit grip_exit(void)
+{
+ gameport_unregister_device(&grip_dev);
+}
+
+module_init(grip_init);
+module_exit(grip_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: iforce.c,v 1.56 2001/05/27 14:41:26 jdeneux Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik <vojtech@suse.cz>
+ * Copyright (c) 2001 Johann Deneux <deneux@ifrance.com>
+ *
+ * USB/RS232 I-Force joysticks and wheels.
+ *
+ * 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 <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/spinlock.h>
+#include <linux/usb.h>
+#include <linux/serio.h>
+#include <linux/config.h>
+
+/* FF: This module provides arbitrary resource management routines.
+ * I use it to manage the device's memory.
+ * Despite the name of this module, I am *not* going to access the ioports.
+ */
+#include <linux/ioport.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>, Johann Deneux <deneux@ifrance.com>");
+MODULE_DESCRIPTION("USB/RS232 I-Force joysticks and wheels driver");
+MODULE_LICENSE("GPL");
+
+#define IFORCE_MAX_LENGTH 16
+
+#if defined(CONFIG_JOYSTICK_IFORCE_232) || defined(CONFIG_JOYSTICK_IFORCE_232_MODULE)
+#define IFORCE_232 1
+#endif
+#if defined(CONFIG_JOYSTICK_IFORCE_USB) || defined(CONFIG_JOYSTICK_IFORCE_USB_MODULE)
+#define IFORCE_USB 2
+#endif
+
+#define FF_EFFECTS_MAX 32
+
+/* Each force feedback effect is made of one core effect, which can be
+ * associated to at most to effect modifiers
+ */
+#define FF_MOD1_IS_USED 0
+#define FF_MOD2_IS_USED 1
+#define FF_CORE_IS_USED 2
+#define FF_CORE_IS_PLAYED 3
+#define FF_MODCORE_MAX 3
+
+struct iforce_core_effect {
+ /* Information about where modifiers are stored in the device's memory */
+ struct resource mod1_chunk;
+ struct resource mod2_chunk;
+ unsigned long flags[NBITS(FF_MODCORE_MAX)];
+};
+
+#define FF_CMD_EFFECT 0x010e
+#define FF_CMD_SHAPE 0x0208
+#define FF_CMD_MAGNITUDE 0x0303
+#define FF_CMD_PERIOD 0x0407
+#define FF_CMD_INTERACT 0x050a
+
+#define FF_CMD_AUTOCENTER 0x4002
+#define FF_CMD_PLAY 0x4103
+#define FF_CMD_ENABLE 0x4201
+#define FF_CMD_GAIN 0x4301
+
+#define FF_CMD_QUERY 0xff01
+
+static signed short btn_joystick[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
+ BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, BTN_DEAD, -1 };
+static signed short btn_wheel[] = { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_TOP2, BTN_BASE,
+ BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_BASE5, BTN_A, BTN_B, BTN_C, -1 };
+static signed short abs_joystick[] = { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short abs_wheel[] = { ABS_WHEEL, ABS_GAS, ABS_BRAKE, ABS_HAT0X, ABS_HAT0Y, -1 };
+static signed short ff_iforce[] = { FF_PERIODIC, FF_CONSTANT, FF_SPRING, FF_FRICTION,
+ FF_SQUARE, FF_TRIANGLE, FF_SINE, FF_SAW_UP, FF_SAW_DOWN, FF_GAIN, FF_AUTOCENTER, -1 };
+
+static struct iforce_device {
+ u16 idvendor;
+ u16 idproduct;
+ char *name;
+ signed short *btn;
+ signed short *abs;
+ signed short *ff;
+} iforce_device[] = {
+ { 0x046d, 0xc281, "Logitech WingMan Force", btn_joystick, abs_joystick, ff_iforce },
+ { 0x046d, 0xc291, "Logitech WingMan Formula Force", btn_wheel, abs_wheel, ff_iforce },
+ { 0x05ef, 0x020a, "AVB Top Shot Pegasus", btn_joystick, abs_joystick, ff_iforce },
+ { 0x05ef, 0x8884, "AVB Mag Turbo Force", btn_wheel, abs_wheel, ff_iforce },
+ { 0x06f8, 0x0001, "Guillemot Race Leader Force Feedback", btn_wheel, abs_wheel, ff_iforce },
+ { 0x0000, 0x0000, "Unknown I-Force Device [%04x:%04x]", btn_joystick, abs_joystick, ff_iforce }
+};
+
+struct iforce {
+ struct input_dev dev; /* Input device interface */
+ struct iforce_device *type;
+ char name[64];
+ int open;
+ int bus;
+
+ unsigned char data[IFORCE_MAX_LENGTH];
+ unsigned char edata[IFORCE_MAX_LENGTH];
+ u16 ecmd;
+ u16 expect_packet;
+
+#ifdef IFORCE_232
+ struct serio *serio; /* RS232 transfer */
+ int idx, pkt, len, id;
+ unsigned char csum;
+#endif
+#ifdef IFORCE_USB
+ struct usb_device *usbdev; /* USB transfer */
+ struct urb *irq, *out, *ctrl;
+ struct usb_ctrlrequest dr;
+#endif
+ /* Force Feedback */
+ wait_queue_head_t wait;
+ struct resource device_memory;
+ struct iforce_core_effect core_effects[FF_EFFECTS_MAX];
+};
+
+static struct {
+ __s32 x;
+ __s32 y;
+} iforce_hat_to_axis[16] = {{ 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+/* Get hi and low bytes of a 16-bits int */
+#define HI(a) ((unsigned char)((a) >> 8))
+#define LO(a) ((unsigned char)((a) & 0xff))
+
+/* Encode a time value */
+#define TIME_SCALE(a) ((a) == 0xffff ? 0xffff : (a) * 1000 / 256)
+
+static void dump_packet(char *msg, u16 cmd, unsigned char *data)
+{
+ int i;
+
+ printk(KERN_DEBUG "iforce.c: %s ( cmd = %04x, data = ", msg, cmd);
+ for (i = 0; i < LO(cmd); i++)
+ printk("%02x ", data[i]);
+ printk(")\n");
+}
+
+/*
+ * Send a packet of bytes to the device
+ */
+static void send_packet(struct iforce *iforce, u16 cmd, unsigned char* data)
+{
+ switch (iforce->bus) {
+
+#ifdef IFORCE_232
+ case IFORCE_232: {
+
+ int i;
+ unsigned char csum = 0x2b ^ HI(cmd) ^ LO(cmd);
+
+ serio_write(iforce->serio, 0x2b);
+ serio_write(iforce->serio, HI(cmd));
+ serio_write(iforce->serio, LO(cmd));
+
+ for (i = 0; i < LO(cmd); i++) {
+ serio_write(iforce->serio, data[i]);
+ csum = csum ^ data[i];
+ }
+
+ serio_write(iforce->serio, csum);
+ return;
+ }
+#endif
+#ifdef IFORCE_USB
+ case IFORCE_USB: {
+
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = HZ; /* 1 second */
+
+ memcpy(iforce->out->transfer_buffer + 1, data, LO(cmd));
+ ((char*)iforce->out->transfer_buffer)[0] = HI(cmd);
+ iforce->out->transfer_buffer_length = LO(cmd) + 2;
+ iforce->out->dev = iforce->usbdev;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&iforce->wait, &wait);
+
+ if (usb_submit_urb(iforce->out)) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&iforce->wait, &wait);
+ return;
+ }
+
+ while (timeout && iforce->out->status == -EINPROGRESS)
+ timeout = schedule_timeout(timeout);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&iforce->wait, &wait);
+
+ if (!timeout)
+ usb_unlink_urb(iforce->out);
+
+ return;
+ }
+#endif
+ }
+}
+
+static void iforce_process_packet(struct iforce *iforce, u16 cmd, unsigned char *data)
+{
+ struct input_dev *dev = &iforce->dev;
+ int i;
+
+#ifdef IFORCE_232
+ if (HI(iforce->expect_packet) == HI(cmd)) {
+ iforce->expect_packet = 0;
+ iforce->ecmd = cmd;
+ memcpy(iforce->edata, data, IFORCE_MAX_LENGTH);
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+ }
+#endif
+
+ if (!iforce->type)
+ return;
+
+ switch (HI(cmd)) {
+
+ case 0x01: /* joystick position data */
+ case 0x03: /* wheel position data */
+
+ if (HI(cmd) == 1) {
+ input_report_abs(dev, ABS_X, (__s16) (((__s16)data[1] << 8) | data[0]));
+ input_report_abs(dev, ABS_Y, (__s16) (((__s16)data[3] << 8) | data[2]));
+ input_report_abs(dev, ABS_THROTTLE, 255 - data[4]);
+ } else {
+ input_report_abs(dev, ABS_WHEEL, (__s16) (((__s16)data[1] << 8) | data[0]));
+ input_report_abs(dev, ABS_GAS, 255 - data[2]);
+ input_report_abs(dev, ABS_BRAKE, 255 - data[3]);
+ }
+
+ input_report_abs(dev, ABS_HAT0X, iforce_hat_to_axis[data[6] >> 4].x);
+ input_report_abs(dev, ABS_HAT0Y, iforce_hat_to_axis[data[6] >> 4].y);
+
+ for (i = 0; iforce->type->btn[i] >= 0; i++)
+ input_report_key(dev, iforce->type->btn[i], data[(i >> 3) + 5] & (1 << (i & 7)));
+
+ break;
+
+ case 0x02: /* status report */
+
+ input_report_key(dev, BTN_DEAD, data[0] & 0x02);
+ break;
+ }
+}
+
+static int get_id_packet(struct iforce *iforce, char *packet)
+{
+ DECLARE_WAITQUEUE(wait, current);
+ int timeout = HZ; /* 1 second */
+
+ switch (iforce->bus) {
+
+#ifdef IFORCE_USB
+ case IFORCE_USB:
+
+ iforce->dr.bRequest = packet[0];
+ iforce->ctrl->dev = iforce->usbdev;
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&iforce->wait, &wait);
+
+ if (usb_submit_urb(iforce->ctrl)) {
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&iforce->wait, &wait);
+ return -1;
+ }
+
+ while (timeout && iforce->ctrl->status == -EINPROGRESS)
+ timeout = schedule_timeout(timeout);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&iforce->wait, &wait);
+
+ if (!timeout) {
+ usb_unlink_urb(iforce->ctrl);
+ return -1;
+ }
+
+ break;
+#endif
+#ifdef IFORCE_232
+ case IFORCE_232:
+
+ iforce->expect_packet = FF_CMD_QUERY;
+ send_packet(iforce, FF_CMD_QUERY, packet);
+
+ set_current_state(TASK_INTERRUPTIBLE);
+ add_wait_queue(&iforce->wait, &wait);
+
+ while (timeout && iforce->expect_packet)
+ timeout = schedule_timeout(timeout);
+
+ set_current_state(TASK_RUNNING);
+ remove_wait_queue(&iforce->wait, &wait);
+
+ if (!timeout) {
+ iforce->expect_packet = 0;
+ return -1;
+ }
+
+ break;
+#endif
+ }
+
+ return -(iforce->edata[0] != packet[0]);
+}
+
+static int iforce_open(struct input_dev *dev)
+{
+ struct iforce *iforce = dev->private;
+
+ switch (iforce->bus) {
+#ifdef IFORCE_USB
+ case IFORCE_USB:
+ if (iforce->open++)
+ break;
+ iforce->irq->dev = iforce->usbdev;
+ if (usb_submit_urb(iforce->irq))
+ return -EIO;
+ break;
+#endif
+ }
+ return 0;
+}
+
+static void iforce_close(struct input_dev *dev)
+{
+ struct iforce *iforce = dev->private;
+
+ switch (iforce->bus) {
+#ifdef IFORCE_USB
+ case IFORCE_USB:
+ if (!--iforce->open)
+ usb_unlink_urb(iforce->irq);
+ break;
+#endif
+ }
+}
+
+/*
+ * Start or stop playing an effect
+ */
+
+static int iforce_input_event(struct input_dev *dev, unsigned int type, unsigned int code, int value)
+{
+ struct iforce* iforce = (struct iforce*)(dev->private);
+ unsigned char data[3];
+
+ printk(KERN_DEBUG "iforce.c: input_event(type = %d, code = %d, value = %d)\n", type, code, value);
+
+ if (type != EV_FF)
+ return -1;
+
+ switch (code) {
+
+ case FF_GAIN:
+
+ data[0] = value >> 9;
+ send_packet(iforce, FF_CMD_GAIN, data);
+
+ return 0;
+
+ case FF_AUTOCENTER:
+
+ data[0] = 0x03;
+ data[1] = value >> 9;
+ send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+ data[0] = 0x04;
+ data[1] = 0x01;
+ send_packet(iforce, FF_CMD_AUTOCENTER, data);
+
+ return 0;
+
+ default: /* Play an effect */
+
+ if (code >= iforce->dev.ff_effects_max)
+ return -1;
+
+ data[0] = LO(code);
+ data[1] = (value > 0) ? ((value > 1) ? 0x41 : 0x01) : 0;
+ data[2] = LO(value);
+ send_packet(iforce, FF_CMD_PLAY, data);
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * Set the magnitude of a constant force effect
+ * Return error code
+ *
+ * Note: caller must ensure exclusive access to device
+ */
+
+static int make_magnitude_modifier(struct iforce* iforce,
+ struct resource* mod_chunk, __s16 level)
+{
+ unsigned char data[3];
+
+ if (allocate_resource(&(iforce->device_memory), mod_chunk, 2,
+ iforce->device_memory.start, iforce->device_memory.end, 2L,
+ NULL, NULL)) {
+ return -ENOMEM;
+ }
+
+ data[0] = LO(mod_chunk->start);
+ data[1] = HI(mod_chunk->start);
+ data[2] = HI(level);
+
+ send_packet(iforce, FF_CMD_MAGNITUDE, data);
+
+ return 0;
+}
+
+/*
+ * Upload the component of an effect dealing with the period, phase and magnitude
+ */
+
+static int make_period_modifier(struct iforce* iforce, struct resource* mod_chunk,
+ __s16 magnitude, __s16 offset, u16 period, u16 phase)
+{
+ unsigned char data[7];
+
+ period = TIME_SCALE(period);
+
+ if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0c,
+ iforce->device_memory.start, iforce->device_memory.end, 2L,
+ NULL, NULL)) {
+ return -ENOMEM;
+ }
+
+ data[0] = LO(mod_chunk->start);
+ data[1] = HI(mod_chunk->start);
+
+ data[2] = HI(magnitude);
+ data[3] = HI(offset);
+ data[4] = HI(phase);
+
+ data[5] = LO(period);
+ data[6] = HI(period);
+
+ send_packet(iforce, FF_CMD_PERIOD, data);
+
+ return 0;
+}
+
+/*
+ * Uploads the part of an effect setting the shape of the force
+ */
+
+static int make_shape_modifier(struct iforce* iforce, struct resource* mod_chunk,
+ u16 attack_duration, __s16 initial_level,
+ u16 fade_duration, __s16 final_level)
+{
+ unsigned char data[8];
+
+ attack_duration = TIME_SCALE(attack_duration);
+ fade_duration = TIME_SCALE(fade_duration);
+
+ if (allocate_resource(&(iforce->device_memory), mod_chunk, 0x0e,
+ iforce->device_memory.start, iforce->device_memory.end, 2L,
+ NULL, NULL)) {
+ return -ENOMEM;
+ }
+
+ data[0] = LO(mod_chunk->start);
+ data[1] = HI(mod_chunk->start);
+
+ data[2] = LO(attack_duration);
+ data[3] = HI(attack_duration);
+ data[4] = HI(initial_level);
+
+ data[5] = LO(fade_duration);
+ data[6] = HI(fade_duration);
+ data[7] = HI(final_level);
+
+ send_packet(iforce, FF_CMD_SHAPE, data);
+
+ return 0;
+}
+
+/*
+ * Component of spring, friction, inertia... effects
+ */
+
+static int make_interactive_modifier(struct iforce* iforce,
+ struct resource* mod_chunk,
+ __s16 rsat, __s16 lsat, __s16 rk, __s16 lk, u16 db, __s16 center)
+{
+ unsigned char data[10];
+
+ if (allocate_resource(&(iforce->device_memory), mod_chunk, 8,
+ iforce->device_memory.start, iforce->device_memory.end, 2L,
+ NULL, NULL)) {
+ return -ENOMEM;
+ }
+
+ data[0] = LO(mod_chunk->start);
+ data[1] = HI(mod_chunk->start);
+
+ data[2] = HI(rk);
+ data[3] = HI(lk);
+
+ data[4] = LO(center);
+ data[5] = HI(center);
+
+ data[6] = LO(db);
+ data[7] = HI(db);
+
+ data[8] = HI(rsat);
+ data[9] = HI(lsat);
+
+ send_packet(iforce, FF_CMD_INTERACT, data);
+
+ return 0;
+}
+
+static unsigned char find_button(struct iforce *iforce, signed short button)
+{
+ int i;
+ for (i = 1; iforce->type->btn[i] >= 0; i++)
+ if (iforce->type->btn[i] == button)
+ return i + 1;
+ return 0;
+}
+
+/*
+ * Send the part common to all effects to the device
+ */
+
+static int make_core(struct iforce* iforce, u16 id, u16 mod_id1, u16 mod_id2,
+ u8 effect_type, u8 axes, u16 duration, u16 delay, u16 button,
+ u16 interval, u16 direction)
+{
+ unsigned char data[14];
+
+ duration = TIME_SCALE(duration);
+ delay = TIME_SCALE(delay);
+ interval = TIME_SCALE(interval);
+
+ data[0] = LO(id);
+ data[1] = effect_type;
+ data[2] = LO(axes) | find_button(iforce, button);
+
+ data[3] = LO(duration);
+ data[4] = HI(duration);
+
+ data[5] = HI(direction);
+
+ data[6] = LO(interval);
+ data[7] = HI(interval);
+
+ data[8] = LO(mod_id1);
+ data[9] = HI(mod_id1);
+ data[10] = LO(mod_id2);
+ data[11] = HI(mod_id2);
+
+ data[12] = LO(delay);
+ data[13] = HI(delay);
+
+ send_packet(iforce, FF_CMD_EFFECT, data);
+
+ return 0;
+}
+
+/*
+ * Upload a periodic effect to the device
+ */
+
+static int iforce_upload_periodic(struct iforce* iforce, struct ff_effect* effect)
+{
+ u8 wave_code;
+ int core_id = effect->id;
+ struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+ struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
+ struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
+ int err = 0;
+
+ err = make_period_modifier(iforce, mod1_chunk,
+ effect->u.periodic.magnitude, effect->u.periodic.offset,
+ effect->u.periodic.period, effect->u.periodic.phase);
+ if (err) return err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+ err = make_shape_modifier(iforce, mod2_chunk,
+ effect->u.periodic.shape.attack_length,
+ effect->u.periodic.shape.attack_level,
+ effect->u.periodic.shape.fade_length,
+ effect->u.periodic.shape.fade_level);
+ if (err) return err;
+ set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+ switch (effect->u.periodic.waveform) {
+ case FF_SQUARE: wave_code = 0x20; break;
+ case FF_TRIANGLE: wave_code = 0x21; break;
+ case FF_SINE: wave_code = 0x22; break;
+ case FF_SAW_UP: wave_code = 0x23; break;
+ case FF_SAW_DOWN: wave_code = 0x24; break;
+ default: wave_code = 0x20; break;
+ }
+
+ err = make_core(iforce, effect->id,
+ mod1_chunk->start,
+ mod2_chunk->start,
+ wave_code,
+ 0x20,
+ effect->replay.length,
+ effect->replay.delay,
+ effect->trigger.button,
+ effect->trigger.interval,
+ effect->u.periodic.direction);
+
+ return err;
+}
+
+/*
+ * Upload a constant force effect
+ */
+static int iforce_upload_constant(struct iforce* iforce, struct ff_effect* effect)
+{
+ int core_id = effect->id;
+ struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+ struct resource* mod1_chunk = &(iforce->core_effects[core_id].mod1_chunk);
+ struct resource* mod2_chunk = &(iforce->core_effects[core_id].mod2_chunk);
+ int err = 0;
+
+ printk(KERN_DEBUG "iforce.c: make constant effect\n");
+
+ err = make_magnitude_modifier(iforce, mod1_chunk, effect->u.constant.level);
+ if (err) return err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+ err = make_shape_modifier(iforce, mod2_chunk,
+ effect->u.constant.shape.attack_length,
+ effect->u.constant.shape.attack_level,
+ effect->u.constant.shape.fade_length,
+ effect->u.constant.shape.fade_level);
+ if (err) return err;
+ set_bit(FF_MOD2_IS_USED, core_effect->flags);
+
+ err = make_core(iforce, effect->id,
+ mod1_chunk->start,
+ mod2_chunk->start,
+ 0x00,
+ 0x20,
+ effect->replay.length,
+ effect->replay.delay,
+ effect->trigger.button,
+ effect->trigger.interval,
+ effect->u.constant.direction);
+
+ return err;
+}
+
+/*
+ * Upload an interactive effect. Those are for example friction, inertia, springs...
+ */
+static int iforce_upload_interactive(struct iforce* iforce, struct ff_effect* effect)
+{
+ int core_id = effect->id;
+ struct iforce_core_effect* core_effect = iforce->core_effects + core_id;
+ struct resource* mod_chunk = &(core_effect->mod1_chunk);
+ u8 type, axes;
+ u16 mod1, mod2, direction;
+ int err = 0;
+
+ printk(KERN_DEBUG "iforce.c: make interactive effect\n");
+
+ switch (effect->type) {
+ case FF_SPRING: type = 0x40; break;
+ case FF_FRICTION: type = 0x41; break;
+ default: return -1;
+ }
+
+ err = make_interactive_modifier(iforce, mod_chunk,
+ effect->u.interactive.right_saturation,
+ effect->u.interactive.left_saturation,
+ effect->u.interactive.right_coeff,
+ effect->u.interactive.left_coeff,
+ effect->u.interactive.deadband,
+ effect->u.interactive.center);
+ if (err) return err;
+ set_bit(FF_MOD1_IS_USED, core_effect->flags);
+
+ switch ((test_bit(ABS_X, &effect->u.interactive.axis) ||
+ test_bit(ABS_WHEEL, &effect->u.interactive.axis)) |
+ (!!test_bit(ABS_Y, &effect->u.interactive.axis) << 1)) {
+
+ case 0: /* Only one axis, choose orientation */
+ mod1 = mod_chunk->start;
+ mod2 = 0xffff;
+ direction = effect->u.interactive.direction;
+ axes = 0x20;
+ break;
+
+ case 1: /* Only X axis */
+ mod1 = mod_chunk->start;
+ mod2 = 0xffff;
+ direction = 0x5a00;
+ axes = 0x40;
+ break;
+
+ case 2: /* Only Y axis */
+ mod1 = 0xffff;
+ mod2 = mod_chunk->start;
+ direction = 0xb400;
+ axes = 0x80;
+ break;
+
+ case 3: /* Both X and Y axes */
+ /* TODO: same setting for both axes is not mandatory */
+ mod1 = mod_chunk->start;
+ mod2 = mod_chunk->start;
+ direction = 0x6000;
+ axes = 0xc0;
+ break;
+
+ default:
+ return -1;
+ }
+
+ err = make_core(iforce, effect->id,
+ mod1, mod2,
+ type, axes,
+ effect->replay.length, effect->replay.delay,
+ effect->trigger.button, effect->trigger.interval,
+ direction);
+
+ return err;
+}
+
+/*
+ * Function called when an ioctl is performed on the event dev entry.
+ * It uploads an effect to the device
+ */
+static int iforce_upload_effect(struct input_dev *dev, struct ff_effect *effect)
+{
+ struct iforce* iforce = (struct iforce*)(dev->private);
+ int id;
+
+ printk(KERN_DEBUG "iforce.c: upload effect\n");
+
+/*
+ * Get a free id
+ */
+
+ for (id=0; id < FF_EFFECTS_MAX; ++id)
+ if (!test_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags)) break;
+
+ if ( id == FF_EFFECTS_MAX || id >= iforce->dev.ff_effects_max)
+ return -ENOMEM;
+
+ effect->id = id;
+ set_bit(FF_CORE_IS_USED, iforce->core_effects[id].flags);
+
+/*
+ * Upload the effect
+ */
+
+ switch (effect->type) {
+
+ case FF_PERIODIC:
+ return iforce_upload_periodic(iforce, effect);
+
+ case FF_CONSTANT:
+ return iforce_upload_constant(iforce, effect);
+
+ case FF_SPRING:
+ case FF_FRICTION:
+ return iforce_upload_interactive(iforce, effect);
+
+ default:
+ return -1;
+ }
+}
+
+/*
+ * Erases an effect: it frees the effect id and mark as unused the memory
+ * allocated for the parameters
+ */
+static int iforce_erase_effect(struct input_dev *dev, int effect_id)
+{
+ struct iforce* iforce = (struct iforce*)(dev->private);
+ int err = 0;
+ struct iforce_core_effect* core_effect;
+
+ printk(KERN_DEBUG "iforce.c: erase effect %d\n", effect_id);
+
+ if (effect_id < 0 || effect_id >= FF_EFFECTS_MAX)
+ return -EINVAL;
+
+ core_effect = iforce->core_effects + effect_id;
+
+ if (test_bit(FF_MOD1_IS_USED, core_effect->flags))
+ err = release_resource(&(iforce->core_effects[effect_id].mod1_chunk));
+
+ if (!err && test_bit(FF_MOD2_IS_USED, core_effect->flags))
+ err = release_resource(&(iforce->core_effects[effect_id].mod2_chunk));
+
+ /*TODO: remember to change that if more FF_MOD* bits are added */
+ core_effect->flags[0] = 0;
+
+ return err;
+}
+static int iforce_init_device(struct iforce *iforce)
+{
+ unsigned char c[] = "CEOV";
+ int i;
+
+ init_waitqueue_head(&iforce->wait);
+ iforce->dev.ff_effects_max = 10;
+
+/*
+ * Input device fields.
+ */
+
+ iforce->dev.idbus = BUS_USB;
+ iforce->dev.private = iforce;
+ iforce->dev.name = iforce->name;
+ iforce->dev.open = iforce_open;
+ iforce->dev.close = iforce_close;
+ iforce->dev.event = iforce_input_event;
+ iforce->dev.upload_effect = iforce_upload_effect;
+ iforce->dev.erase_effect = iforce_erase_effect;
+
+/*
+ * On-device memory allocation.
+ */
+
+ iforce->device_memory.name = "I-Force device effect memory";
+ iforce->device_memory.start = 0;
+ iforce->device_memory.end = 200;
+ iforce->device_memory.flags = IORESOURCE_MEM;
+ iforce->device_memory.parent = NULL;
+ iforce->device_memory.child = NULL;
+ iforce->device_memory.sibling = NULL;
+
+/*
+ * Wait until device ready - until it sends its first response.
+ */
+
+ for (i = 0; i < 20; i++)
+ if (!get_id_packet(iforce, "O"))
+ break;
+
+ if (i == 20) { /* 5 seconds */
+ printk(KERN_ERR "iforce.c: Timeout waiting for response from device.\n");
+ iforce_close(&iforce->dev);
+ return -1;
+ }
+
+/*
+ * Get device info.
+ */
+
+ if (!get_id_packet(iforce, "M"))
+ iforce->dev.idvendor = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!get_id_packet(iforce, "P"))
+ iforce->dev.idproduct = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!get_id_packet(iforce, "B"))
+ iforce->device_memory.end = (iforce->edata[2] << 8) | iforce->edata[1];
+ if (!get_id_packet(iforce, "N"))
+ iforce->dev.ff_effects_max = iforce->edata[1];
+
+/*
+ * Display additional info.
+ */
+
+ for (i = 0; c[i]; i++)
+ if (!get_id_packet(iforce, c + i))
+ dump_packet("info", iforce->ecmd, iforce->edata);
+
+/*
+ * Disable spring, enable force feedback.
+ * FIXME: We should use iforce_set_autocenter() et al here.
+ */
+
+ send_packet(iforce, FF_CMD_AUTOCENTER, "\004\000");
+ send_packet(iforce, FF_CMD_ENABLE, "\004");
+
+/*
+ * Find appropriate device entry
+ */
+
+ for (i = 0; iforce_device[i].idvendor; i++)
+ if (iforce_device[i].idvendor == iforce->dev.idvendor &&
+ iforce_device[i].idproduct == iforce->dev.idproduct)
+ break;
+
+ iforce->type = iforce_device + i;
+
+ sprintf(iforce->name, iforce->type->name,
+ iforce->dev.idproduct, iforce->dev.idvendor);
+
+/*
+ * Set input device bitfields and ranges.
+ */
+
+ iforce->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS) | BIT(EV_FF);
+
+ for (i = 0; iforce->type->btn[i] >= 0; i++) {
+ signed short t = iforce->type->btn[i];
+ set_bit(t, iforce->dev.keybit);
+ if (t != BTN_DEAD)
+ set_bit(FF_BTN(t), iforce->dev.ffbit);
+ }
+
+ for (i = 0; iforce->type->abs[i] >= 0; i++) {
+
+ signed short t = iforce->type->abs[i];
+ set_bit(t, iforce->dev.absbit);
+
+ switch (t) {
+
+ case ABS_X:
+ case ABS_Y:
+ case ABS_WHEEL:
+
+ iforce->dev.absmax[t] = 1920;
+ iforce->dev.absmin[t] = -1920;
+ iforce->dev.absflat[t] = 128;
+ iforce->dev.absfuzz[t] = 16;
+
+ set_bit(FF_ABS(t), iforce->dev.ffbit);
+ break;
+
+ case ABS_THROTTLE:
+ case ABS_GAS:
+ case ABS_BRAKE:
+
+ iforce->dev.absmax[t] = 255;
+ iforce->dev.absmin[t] = 0;
+ break;
+
+ case ABS_HAT0X:
+ case ABS_HAT0Y:
+ iforce->dev.absmax[t] = 1;
+ iforce->dev.absmin[t] = -1;
+ break;
+ }
+ }
+
+ for (i = 0; iforce->type->ff[i] >= 0; i++)
+ set_bit(iforce->type->ff[i], iforce->dev.ffbit);
+
+/*
+ * Register input device.
+ */
+
+ input_register_device(&iforce->dev);
+
+ return 0;
+}
+
+#ifdef IFORCE_USB
+
+static void iforce_usb_irq(struct urb *urb)
+{
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+ iforce_process_packet(iforce,
+ (iforce->data[0] << 8) | (urb->actual_length - 1), iforce->data + 1);
+}
+
+static void iforce_usb_out(struct urb *urb)
+{
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+}
+
+static void iforce_usb_ctrl(struct urb *urb)
+{
+ struct iforce *iforce = urb->context;
+ if (urb->status) return;
+ iforce->ecmd = 0xff00 | urb->actual_length;
+ if (waitqueue_active(&iforce->wait))
+ wake_up(&iforce->wait);
+}
+
+static void *iforce_usb_probe(struct usb_device *dev, unsigned int ifnum,
+ const struct usb_device_id *id)
+{
+ struct usb_endpoint_descriptor *epirq, *epout;
+ struct iforce *iforce;
+
+ epirq = dev->config[0].interface[ifnum].altsetting[0].endpoint + 0;
+ epout = dev->config[0].interface[ifnum].altsetting[0].endpoint + 1;
+
+ if (!(iforce = kmalloc(sizeof(struct iforce) + 32, GFP_KERNEL))) return NULL;
+ memset(iforce, 0, sizeof(struct iforce));
+
+ iforce->irq = usb_alloc_urb(0);
+ if (!iforce->irq) {
+ kfree(iforce);
+ return NULL;
+ }
+ iforce->out = usb_alloc_urb(0);
+ if (!iforce->out) {
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+ return NULL;
+ }
+ iforce->ctrl = usb_alloc_urb(0);
+ if (!iforce->ctrl) {
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+ return NULL;
+ }
+
+ iforce->bus = IFORCE_USB;
+ iforce->usbdev = dev;
+
+ iforce->dr.bRequestType = USB_TYPE_VENDOR | USB_DIR_IN | USB_RECIP_INTERFACE;
+ iforce->dr.wIndex = 0;
+ iforce->dr.wLength = 16;
+
+ FILL_INT_URB(iforce->irq, dev, usb_rcvintpipe(dev, epirq->bEndpointAddress),
+ iforce->data, 16, iforce_usb_irq, iforce, epirq->bInterval);
+
+ FILL_BULK_URB(iforce->out, dev, usb_sndbulkpipe(dev, epout->bEndpointAddress),
+ iforce + 1, 32, iforce_usb_out, iforce);
+
+ FILL_CONTROL_URB(iforce->ctrl, dev, usb_rcvctrlpipe(dev, 0),
+ (void*) &iforce->dr, iforce->edata, 16, iforce_usb_ctrl, iforce);
+
+ if (iforce_init_device(iforce)) {
+ usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+ return NULL;
+ }
+
+ printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on usb%d:%d.%d\n",
+ iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+ iforce->device_memory.end, dev->bus->busnum, dev->devnum, ifnum);
+
+ return iforce;
+}
+
+static void iforce_usb_disconnect(struct usb_device *dev, void *ptr)
+{
+ struct iforce *iforce = ptr;
+ usb_unlink_urb(iforce->irq);
+ input_unregister_device(&iforce->dev);
+ usb_free_urb(iforce->ctrl);
+ usb_free_urb(iforce->out);
+ usb_free_urb(iforce->irq);
+ kfree(iforce);
+}
+
+static struct usb_device_id iforce_usb_ids [] = {
+ { USB_DEVICE(0x046d, 0xc281) }, /* Logitech WingMan Force */
+ { USB_DEVICE(0x046d, 0xc291) }, /* Logitech WingMan Formula Force */
+ { USB_DEVICE(0x05ef, 0x020a) }, /* AVB Top Shot Pegasus */
+ { USB_DEVICE(0x05ef, 0x8884) }, /* AVB Mag Turbo Force */
+ { USB_DEVICE(0x06f8, 0x0001) }, /* Guillemot Race Leader Force Feedback */
+ { } /* Terminating entry */
+};
+
+MODULE_DEVICE_TABLE (usb, iforce_usb_ids);
+
+static struct usb_driver iforce_usb_driver = {
+ name: "iforce",
+ probe: iforce_usb_probe,
+ disconnect: iforce_usb_disconnect,
+ id_table: iforce_usb_ids,
+};
+
+#endif
+
+#ifdef IFORCE_232
+
+static void iforce_serio_irq(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct iforce* iforce = serio->private;
+
+ if (!iforce->pkt) {
+ if (data != 0x2b) {
+ return;
+ }
+ iforce->pkt = 1;
+ return;
+ }
+
+ if (!iforce->id) {
+ if (data > 3 && data != 0xff) {
+ iforce->pkt = 0;
+ return;
+ }
+ iforce->id = data;
+ return;
+ }
+
+ if (!iforce->len) {
+ if (data > IFORCE_MAX_LENGTH) {
+ iforce->pkt = 0;
+ iforce->id = 0;
+ return;
+ }
+ iforce->len = data;
+ return;
+ }
+
+ if (iforce->idx < iforce->len) {
+ iforce->csum += iforce->data[iforce->idx++] = data;
+ return;
+ }
+
+ if (iforce->idx == iforce->len) {
+ iforce_process_packet(iforce, (iforce->id << 8) | iforce->idx, iforce->data);
+ iforce->pkt = 0;
+ iforce->id = 0;
+ iforce->len = 0;
+ iforce->idx = 0;
+ iforce->csum = 0;
+ }
+}
+
+static void iforce_serio_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct iforce *iforce;
+ if (serio->type != (SERIO_RS232 | SERIO_IFORCE))
+ return;
+
+ if (!(iforce = kmalloc(sizeof(struct iforce), GFP_KERNEL))) return;
+ memset(iforce, 0, sizeof(struct iforce));
+
+ iforce->bus = IFORCE_232;
+ iforce->serio = serio;
+ serio->private = iforce;
+
+ if (serio_open(serio, dev)) {
+ kfree(iforce);
+ return;
+ }
+
+ if (iforce_init_device(iforce)) {
+ serio_close(serio);
+ kfree(iforce);
+ return;
+ }
+
+ printk(KERN_INFO "input%d: %s [%d effects, %ld bytes memory] on serio%d\n",
+ iforce->dev.number, iforce->dev.name, iforce->dev.ff_effects_max,
+ iforce->device_memory.end, serio->number);
+}
+
+static void iforce_serio_disconnect(struct serio *serio)
+{
+ struct iforce* iforce = serio->private;
+
+ input_unregister_device(&iforce->dev);
+ serio_close(serio);
+ kfree(iforce);
+}
+
+static struct serio_dev iforce_serio_dev = {
+ interrupt: iforce_serio_irq,
+ connect: iforce_serio_connect,
+ disconnect: iforce_serio_disconnect,
+};
+
+#endif
+
+static int __init iforce_init(void)
+{
+#ifdef IFORCE_USB
+ usb_register(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+ serio_register_device(&iforce_serio_dev);
+#endif
+ return 0;
+}
+
+static void __exit iforce_exit(void)
+{
+#ifdef IFORCE_USB
+ usb_deregister(&iforce_usb_driver);
+#endif
+#ifdef IFORCE_232
+ serio_unregister_device(&iforce_serio_dev);
+#endif
+}
+
+module_init(iforce_init);
+module_exit(iforce_exit);
--- /dev/null
+/*
+ * $Id: interact.c,v 1.8 2000/05/29 11:19:51 vojtech Exp $
+ *
+ * Copyright (c) 2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Toby Deshane
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * InterAct digital gamepad/joystick driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define INTERACT_MAX_START 400 /* 400 us */
+#define INTERACT_MAX_STROBE 40 /* 40 us */
+#define INTERACT_MAX_LENGTH 32 /* 32 bits */
+#define INTERACT_REFRESH_TIME HZ/50 /* 20 ms */
+
+#define INTERACT_TYPE_HHFX 0 /* HammerHead/FX */
+#define INTERACT_TYPE_PP8D 1 /* ProPad 8 */
+
+struct interact {
+ struct gameport *gameport;
+ struct input_dev dev;
+ struct timer_list timer;
+ int used;
+ int bads;
+ int reads;
+ unsigned char type;
+ unsigned char length;
+};
+
+static short interact_abs_hhfx[] =
+ { ABS_RX, ABS_RY, ABS_X, ABS_Y, ABS_HAT0X, ABS_HAT0Y, -1 };
+static short interact_abs_pp8d[] =
+ { ABS_X, ABS_Y, -1 };
+
+static short interact_btn_hhfx[] =
+ { BTN_TR, BTN_X, BTN_Y, BTN_Z, BTN_A, BTN_B, BTN_C, BTN_TL, BTN_TL2, BTN_TR2, BTN_MODE, BTN_SELECT, -1 };
+static short interact_btn_pp8d[] =
+ { BTN_C, BTN_TL, BTN_TR, BTN_A, BTN_B, BTN_Y, BTN_Z, BTN_X, -1 };
+
+struct interact_type {
+ int id;
+ short *abs;
+ short *btn;
+ char *name;
+ unsigned char length;
+ unsigned char b8;
+};
+
+static struct interact_type interact_type[] = {
+ { 0x6202, interact_abs_hhfx, interact_btn_hhfx, "InterAct HammerHead/FX", 32, 4 },
+ { 0x53f8, interact_abs_pp8d, interact_btn_pp8d, "InterAct ProPad 8 Digital", 16, 0 },
+ { 0 }};
+
+/*
+ * interact_read_packet() reads and InterAct joystick data.
+ */
+
+static int interact_read_packet(struct gameport *gameport, int length, u32 *data)
+{
+ unsigned long flags;
+ unsigned char u, v;
+ unsigned int t, s;
+ int i;
+
+ i = 0;
+ data[0] = data[1] = data[2] = 0;
+ t = gameport_time(gameport, INTERACT_MAX_START);
+ s = gameport_time(gameport, INTERACT_MAX_STROBE);
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+ v = gameport_read(gameport);
+
+ while (t > 0 && i < length) {
+ t--;
+ u = v; v = gameport_read(gameport);
+ if (v & ~u & 0x40) {
+ data[0] = (data[0] << 1) | ((v >> 4) & 1);
+ data[1] = (data[1] << 1) | ((v >> 5) & 1);
+ data[2] = (data[2] << 1) | ((v >> 7) & 1);
+ i++;
+ t = s;
+ }
+ }
+
+ __restore_flags(flags);
+
+ return i;
+}
+
+/*
+ * interact_timer() reads and analyzes InterAct joystick data.
+ */
+
+static void interact_timer(unsigned long private)
+{
+ struct interact *interact = (struct interact *) private;
+ struct input_dev *dev = &interact->dev;
+ u32 data[3];
+ int i;
+
+ interact->reads++;
+
+ if (interact_read_packet(interact->gameport, interact->length, data) < interact->length) {
+ interact->bads++;
+ } else
+
+ for (i = 0; i < 3; i++)
+ data[i] <<= INTERACT_MAX_LENGTH - interact->length;
+
+ switch (interact->type) {
+
+ case INTERACT_TYPE_HHFX:
+
+ for (i = 0; i < 4; i++)
+ input_report_abs(dev, interact_abs_hhfx[i], (data[i & 1] >> ((i >> 1) << 3)) & 0xff);
+
+ for (i = 0; i < 2; i++)
+ input_report_abs(dev, ABS_HAT0Y - i,
+ ((data[1] >> ((i << 1) + 17)) & 1) - ((data[1] >> ((i << 1) + 16)) & 1));
+
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, interact_btn_hhfx[i], (data[0] >> (i + 16)) & 1);
+
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, interact_btn_hhfx[i + 8], (data[1] >> (i + 20)) & 1);
+
+ break;
+
+ case INTERACT_TYPE_PP8D:
+
+ for (i = 0; i < 2; i++)
+ input_report_abs(dev, interact_abs_pp8d[i],
+ ((data[0] >> ((i << 1) + 20)) & 1) - ((data[0] >> ((i << 1) + 21)) & 1));
+
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, interact_btn_pp8d[i], (data[1] >> (i + 16)) & 1);
+
+ break;
+ }
+
+ mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+
+}
+
+/*
+ * interact_open() is a callback from the input open routine.
+ */
+
+static int interact_open(struct input_dev *dev)
+{
+ struct interact *interact = dev->private;
+ if (!interact->used++)
+ mod_timer(&interact->timer, jiffies + INTERACT_REFRESH_TIME);
+ return 0;
+}
+
+/*
+ * interact_close() is a callback from the input close routine.
+ */
+
+static void interact_close(struct input_dev *dev)
+{
+ struct interact *interact = dev->private;
+ if (!--interact->used)
+ del_timer(&interact->timer);
+}
+
+/*
+ * interact_connect() probes for InterAct joysticks.
+ */
+
+static void interact_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct interact *interact;
+ __u32 data[3];
+ int i, t;
+
+ if (!(interact = kmalloc(sizeof(struct interact), GFP_KERNEL)))
+ return;
+ memset(interact, 0, sizeof(struct interact));
+
+ gameport->private = interact;
+
+ interact->gameport = gameport;
+ init_timer(&interact->timer);
+ interact->timer.data = (long) interact;
+ interact->timer.function = interact_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ i = interact_read_packet(gameport, INTERACT_MAX_LENGTH * 2, data);
+
+ if (i != 32 || (data[0] >> 24) != 0x0c || (data[1] >> 24) != 0x02) {
+ goto fail2;
+ }
+
+ for (i = 0; interact_type[i].length; i++)
+ if (interact_type[i].id == (data[2] >> 16))
+ break;
+
+ if (!interact_type[i].length) {
+ printk(KERN_WARNING "interact.c: Unknown joystick on gameport%d. [len %d d0 %08x d1 %08x i2 %08x]\n",
+ gameport->number, i, data[0], data[1], data[2]);
+ goto fail2;
+ }
+
+ interact->type = i;
+ interact->length = interact_type[i].length;
+
+ interact->dev.private = interact;
+ interact->dev.open = interact_open;
+ interact->dev.close = interact_close;
+
+ interact->dev.name = interact_type[i].name;
+ interact->dev.idbus = BUS_GAMEPORT;
+ interact->dev.idvendor = GAMEPORT_ID_VENDOR_INTERACT;
+ interact->dev.idproduct = interact_type[i].id;
+ interact->dev.idversion = 0x0100;
+
+ interact->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; (t = interact_type[interact->type].abs[i]) >= 0; i++) {
+ set_bit(t, interact->dev.absbit);
+ if (i < interact_type[interact->type].b8) {
+ interact->dev.absmin[t] = 0;
+ interact->dev.absmax[t] = 255;
+ } else {
+ interact->dev.absmin[t] = -1;
+ interact->dev.absmax[t] = 1;
+ }
+ }
+
+ for (i = 0; (t = interact_type[interact->type].btn[i]) >= 0; i++)
+ set_bit(t, interact->dev.keybit);
+
+ input_register_device(&interact->dev);
+ printk(KERN_INFO "input%d: %s on gameport%d.0\n",
+ interact->dev.number, interact_type[interact->type].name, gameport->number);
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(interact);
+}
+
+static void interact_disconnect(struct gameport *gameport)
+{
+ struct interact *interact = gameport->private;
+ input_unregister_device(&interact->dev);
+ gameport_close(gameport);
+ kfree(interact);
+}
+
+static struct gameport_dev interact_dev = {
+ connect: interact_connect,
+ disconnect: interact_disconnect,
+};
+
+int __init interact_init(void)
+{
+ gameport_register_device(&interact_dev);
+ return 0;
+}
+
+void __exit interact_exit(void)
+{
+ gameport_unregister_device(&interact_dev);
+}
+
+module_init(interact_init);
+module_exit(interact_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: magellan.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Magellan and Space Mouse 6dof controller driver for Linux
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Definitions & global arrays.
+ */
+
+#define MAGELLAN_MAX_LENGTH 32
+
+static int magellan_buttons[] = { BTN_0, BTN_1, BTN_2, BTN_3, BTN_4, BTN_5, BTN_6, BTN_7, BTN_8};
+static int magellan_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *magellan_name = "LogiCad3D Magellan";
+
+/*
+ * Per-Magellan data.
+ */
+
+struct magellan {
+ struct input_dev dev;
+ int idx;
+ unsigned char data[MAGELLAN_MAX_LENGTH];
+};
+
+/*
+ * magellan_crunch_nibbles() verifies that the bytes sent from the Magellan
+ * have correct upper nibbles for the lower ones, if not, the packet will
+ * be thrown away. It also strips these upper halves to simplify further
+ * processing.
+ */
+
+static int magellan_crunch_nibbles(unsigned char *data, int count)
+{
+ static unsigned char nibbles[16] = "0AB3D56GH9:K<MN?";
+
+ do {
+ if (data[count] == nibbles[data[count] & 0xf])
+ data[count] = data[count] & 0xf;
+ else
+ return -1;
+ } while (--count);
+
+ return 0;
+}
+
+static void magellan_process_packet(struct magellan* magellan)
+{
+ struct input_dev *dev = &magellan->dev;
+ unsigned char *data = magellan->data;
+ int i, t;
+
+ if (!magellan->idx) return;
+
+ switch (magellan->data[0]) {
+
+ case 'd': /* Axis data */
+ if (magellan->idx != 25) return;
+ if (magellan_crunch_nibbles(data, 24)) return;
+ for (i = 0; i < 6; i++)
+ input_report_abs(dev, magellan_axes[i],
+ (data[(i << 2) + 1] << 12 | data[(i << 2) + 2] << 8 |
+ data[(i << 2) + 3] << 4 | data[(i << 2) + 4]) - 32768);
+ break;
+
+ case 'k': /* Button data */
+ if (magellan->idx != 4) return;
+ if (magellan_crunch_nibbles(data, 3)) return;
+ t = (data[1] << 1) | (data[2] << 5) | data[3];
+ for (i = 0; i < 9; i++) input_report_key(dev, magellan_buttons[i], (t >> i) & 1);
+ break;
+ }
+}
+
+static void magellan_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct magellan* magellan = serio->private;
+
+ if (data == '\r') {
+ magellan_process_packet(magellan);
+ magellan->idx = 0;
+ } else {
+ if (magellan->idx < MAGELLAN_MAX_LENGTH)
+ magellan->data[magellan->idx++] = data;
+ }
+}
+
+/*
+ * magellan_disconnect() is the opposite of magellan_connect()
+ */
+
+static void magellan_disconnect(struct serio *serio)
+{
+ struct magellan* magellan = serio->private;
+ input_unregister_device(&magellan->dev);
+ serio_close(serio);
+ kfree(magellan);
+}
+
+/*
+ * magellan_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Magellan, and if found, registers
+ * it as an input device.
+ */
+
+static void magellan_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct magellan *magellan;
+ int i, t;
+
+ if (serio->type != (SERIO_RS232 | SERIO_MAGELLAN))
+ return;
+
+ if (!(magellan = kmalloc(sizeof(struct magellan), GFP_KERNEL)))
+ return;
+
+ memset(magellan, 0, sizeof(struct magellan));
+
+ magellan->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < 9; i++)
+ set_bit(magellan_buttons[i], &magellan->dev.keybit);
+
+ for (i = 0; i < 6; i++) {
+ t = magellan_axes[i];
+ set_bit(t, magellan->dev.absbit);
+ magellan->dev.absmin[t] = -360;
+ magellan->dev.absmax[t] = 360;
+ }
+
+ magellan->dev.private = magellan;
+ magellan->dev.name = magellan_name;
+ magellan->dev.idbus = BUS_RS232;
+ magellan->dev.idvendor = SERIO_MAGELLAN;
+ magellan->dev.idproduct = 0x0001;
+ magellan->dev.idversion = 0x0100;
+
+ serio->private = magellan;
+
+ if (serio_open(serio, dev)) {
+ kfree(magellan);
+ return;
+ }
+
+ input_register_device(&magellan->dev);
+
+ printk(KERN_INFO "input%d: %s on serio%d\n", magellan->dev.number, magellan_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev magellan_dev = {
+ interrupt: magellan_interrupt,
+ connect: magellan_connect,
+ disconnect: magellan_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init magellan_init(void)
+{
+ serio_register_device(&magellan_dev);
+ return 0;
+}
+
+void __exit magellan_exit(void)
+{
+ serio_unregister_device(&magellan_dev);
+}
+
+module_init(magellan_init);
+module_exit(magellan_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: sidewinder.c,v 1.20 2001/05/19 08:14:54 vojtech Exp $
+ *
+ * Copyright (c) 1998-2001 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Microsoft SideWinder joystick family driver for Linux
+ */
+
+/*
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+/*
+ * These are really magic values. Changing them can make a problem go away,
+ * as well as break everything.
+ */
+
+#undef SW_DEBUG
+
+#define SW_START 400 /* The time we wait for the first bit [400 us] */
+#define SW_STROBE 45 /* Max time per bit [45 us] */
+#define SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
+#define SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
+#define SW_END 8 /* Number of bits before end of packet to kick */
+#define SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
+#define SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
+#define SW_OK 64 /* Number of packet read successes to switch optimization back on */
+#define SW_LENGTH 512 /* Max number of bits in a packet */
+#define SW_REFRESH HZ/50 /* Time to wait between updates of joystick data [20 ms] */
+
+#ifdef SW_DEBUG
+#define dbg(format, arg...) printk(KERN_DEBUG __FILE__ ": " format "\n" , ## arg)
+#else
+#define dbg(format, arg...) do {} while (0)
+#endif
+
+/*
+ * SideWinder joystick types ...
+ */
+
+#define SW_ID_3DP 0
+#define SW_ID_GP 1
+#define SW_ID_PP 2
+#define SW_ID_FFP 3
+#define SW_ID_FSP 4
+#define SW_ID_FFW 5
+
+/*
+ * Names, buttons, axes ...
+ */
+
+static char *sw_name[] = { "3D Pro", "GamePad", "Precision Pro", "Force Feedback Pro", "FreeStyle Pro",
+ "Force Feedback Wheel" };
+
+static char sw_abs[][7] = {
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y },
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y, ABS_RZ, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_X, ABS_Y, ABS_THROTTLE, ABS_HAT0X, ABS_HAT0Y },
+ { ABS_RX, ABS_RUDDER, ABS_THROTTLE }};
+
+static char sw_bit[][7] = {
+ { 10, 10, 9, 10, 1, 1 },
+ { 1, 1 },
+ { 10, 10, 6, 7, 1, 1 },
+ { 10, 10, 6, 7, 1, 1 },
+ { 10, 10, 6, 1, 1 },
+ { 10, 7, 7, 1, 1 }};
+
+static short sw_btn[][12] = {
+ { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_MODE },
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE },
+ { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+ { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4, BTN_SELECT },
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_TL, BTN_TR, BTN_START, BTN_MODE, BTN_SELECT },
+ { BTN_TRIGGER, BTN_TOP, BTN_THUMB, BTN_THUMB2, BTN_BASE, BTN_BASE2, BTN_BASE3, BTN_BASE4 }};
+
+static struct {
+ int x;
+ int y;
+} sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
+
+struct sw {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[4];
+ char name[64];
+ int length;
+ int type;
+ int bits;
+ int number;
+ int fail;
+ int ok;
+ int reads;
+ int bads;
+ int used;
+};
+
+/*
+ * sw_read_packet() is a function which reads either a data packet, or an
+ * identification packet from a SideWinder joystick. The protocol is very,
+ * very, very braindamaged. Microsoft patented it in US patent #5628686.
+ */
+
+static int sw_read_packet(struct gameport *gameport, 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 ? gameport_time(gameport, SW_TIMEOUT) : 0; /* Set up global timeout for ID packet */
+ kick = id ? gameport_time(gameport, SW_KICK) : 0; /* Set up kick timeout for ID packet */
+ start = gameport_time(gameport, SW_START);
+ strobe = gameport_time(gameport, SW_STROBE);
+ bitout = start;
+ pending = 0;
+ sched = 0;
+
+ __save_flags(flags); /* Quiet, please */
+ __cli();
+
+ gameport_trigger(gameport); /* Trigger */
+ v = gameport_read(gameport);
+
+ do {
+ bitout--;
+ u = v;
+ v = gameport_read(gameport);
+ } 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 = gameport_read(gameport);
+
+ 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 > -SW_END)) { /* Second trigger time */
+ gameport_trigger(gameport); /* Trigger */
+ bitout = start; /* Long bit timeout */
+ pending = 0; /* Unmark schedule */
+ timeout = 0; /* Switch from global to bit timeouts */
+ }
+ }
+
+ __restore_flags(flags); /* Done - relax */
+
+#ifdef SW_DEBUG
+ {
+ int j;
+ printk(KERN_DEBUG "sidewinder.c: Read %d triplets. [", i);
+ for (j = 0; j < i; j++) printk("%d", buf[j]);
+ printk("]\n");
+ }
+#endif
+
+ return i;
+}
+
+/*
+ * 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) sw_get_bits(buf, pos, num, sw->bits)
+
+static __u64 sw_get_bits(unsigned char *buf, int pos, int num, char bits)
+{
+ __u64 data = 0;
+ int tri = pos % bits; /* Start position */
+ int i = pos / bits;
+ int bit = 0;
+
+ while (num--) {
+ data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
+ if (tri == bits) {
+ i++; /* Next triplet */
+ tri = 0;
+ }
+ }
+
+ return data;
+}
+
+/*
+ * sw_init_digital() initializes a SideWinder 3D Pro joystick
+ * into digital mode.
+ */
+
+static void sw_init_digital(struct gameport *gameport)
+{
+ int seq[] = { 140, 140+725, 140+300, 0 };
+ unsigned long flags;
+ int i, t;
+
+ __save_flags(flags);
+ __cli();
+
+ i = 0;
+ do {
+ gameport_trigger(gameport); /* Trigger */
+ t = gameport_time(gameport, SW_TIMEOUT);
+ while ((gameport_read(gameport) & 1) && t) t--; /* Wait for axis to fall back to 0 */
+ udelay(seq[i]); /* Delay magic time */
+ } while (seq[++i]);
+
+ gameport_trigger(gameport); /* Last trigger */
+
+ __restore_flags(flags);
+}
+
+/*
+ * sw_parity() computes parity of __u64
+ */
+
+static int 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;
+}
+
+/*
+ * sw_ccheck() checks synchronization bits and computes checksum of nibbles.
+ */
+
+static int sw_check(__u64 t)
+{
+ unsigned char sum = 0;
+
+ if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
+ return -1;
+
+ while (t) { /* Sum */
+ sum += t & 0xf;
+ t >>= 4;
+ }
+
+ return sum & 0xf;
+}
+
+/*
+ * sw_parse() analyzes SideWinder joystick data, and writes the results into
+ * the axes and buttons arrays.
+ */
+
+static int sw_parse(unsigned char *buf, struct sw *sw)
+{
+ int hat, i, j;
+ struct input_dev *dev = sw->dev;
+
+ switch (sw->type) {
+
+ case SW_ID_3DP:
+
+ if (sw_check(GB(0,64)) || (hat = (GB(6,1) << 3) | GB(60,3)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, (GB( 3,3) << 7) | GB(16,7));
+ input_report_abs(dev, ABS_Y, (GB( 0,3) << 7) | GB(24,7));
+ input_report_abs(dev, ABS_RZ, (GB(35,2) << 7) | GB(40,7));
+ input_report_abs(dev, ABS_THROTTLE, (GB(32,3) << 7) | GB(48,7));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 7; j++)
+ input_report_key(dev, sw_btn[SW_ID_3DP][j], !GB(j+8,1));
+
+ input_report_key(dev, BTN_BASE4, !GB(38,1));
+ input_report_key(dev, BTN_BASE5, !GB(37,1));
+
+ return 0;
+
+ case SW_ID_GP:
+
+ for (i = 0; i < sw->number; i ++) {
+
+ if (sw_parity(GB(i*15,15))) return -1;
+
+ input_report_abs(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
+ input_report_abs(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
+
+ for (j = 0; j < 10; j++)
+ input_report_key(dev + i, sw_btn[SW_ID_GP][j], !GB(i*15+j+4,1));
+ }
+
+ return 0;
+
+ case SW_ID_PP:
+ case SW_ID_FFP:
+
+ if (!sw_parity(GB(0,48)) || (hat = GB(42,4)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, GB( 9,10));
+ input_report_abs(dev, ABS_Y, GB(19,10));
+ input_report_abs(dev, ABS_RZ, GB(36, 6));
+ input_report_abs(dev, ABS_THROTTLE, GB(29, 7));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 9; j++)
+ input_report_key(dev, sw_btn[SW_ID_PP][j], !GB(j,1));
+
+ return 0;
+
+ case SW_ID_FSP:
+
+ if (!sw_parity(GB(0,43)) || (hat = GB(28,4)) > 8) return -1;
+
+ input_report_abs(dev, ABS_X, GB( 0,10));
+ input_report_abs(dev, ABS_Y, GB(16,10));
+ input_report_abs(dev, ABS_THROTTLE, GB(32, 6));
+
+ input_report_abs(dev, ABS_HAT0X, sw_hat_to_axis[hat].x);
+ input_report_abs(dev, ABS_HAT0Y, sw_hat_to_axis[hat].y);
+
+ for (j = 0; j < 6; j++)
+ input_report_key(dev, sw_btn[SW_ID_FSP][j], !GB(j+10,1));
+
+ input_report_key(dev, BTN_TR, GB(26,1));
+ input_report_key(dev, BTN_START, GB(27,1));
+ input_report_key(dev, BTN_MODE, GB(38,1));
+ input_report_key(dev, BTN_SELECT, GB(39,1));
+
+ return 0;
+
+ case SW_ID_FFW:
+
+ if (!sw_parity(GB(0,33))) return -1;
+
+ input_report_abs(dev, ABS_RX, GB( 0,10));
+ input_report_abs(dev, ABS_RUDDER, GB(10, 6));
+ input_report_abs(dev, ABS_THROTTLE, GB(16, 6));
+
+ for (j = 0; j < 8; j++)
+ input_report_key(dev, sw_btn[SW_ID_FFW][j], !GB(j+22,1));
+
+ return 0;
+ }
+
+ return -1;
+}
+
+/*
+ * 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 sw_read(struct sw *sw)
+{
+ unsigned char buf[SW_LENGTH];
+ int i;
+
+ i = sw_read_packet(sw->gameport, buf, sw->length, 0);
+
+ if (sw->type == SW_ID_3DP && sw->length == 66 && i != 66) { /* Broken packet, try to fix */
+
+ if (i == 64 && !sw_check(sw_get_bits(buf,0,64,1))) { /* Last init failed, 1 bit mode */
+ printk(KERN_WARNING "sidewinder.c: Joystick in wrong mode on gameport%d"
+ " - going to reinitialize.\n", sw->gameport->number);
+ sw->fail = SW_FAIL; /* Reinitialize */
+ i = 128; /* Bogus value */
+ }
+
+ if (i < 66 && GB(0,64) == GB(i*3-66,64)) /* 1 == 3 */
+ i = 66; /* Everything is fine */
+
+ if (i < 66 && GB(0,64) == GB(66,64)) /* 1 == 2 */
+ i = 66; /* Everything is fine */
+
+ if (i < 66 && GB(i*3-132,64) == GB(i*3-66,64)) { /* 2 == 3 */
+ memmove(buf, buf + i - 22, 22); /* Move data */
+ i = 66; /* Carry on */
+ }
+ }
+
+ if (i == sw->length && !sw_parse(buf, sw)) { /* Parse data */
+
+ sw->fail = 0;
+ sw->ok++;
+
+ if (sw->type == SW_ID_3DP && sw->length == 66 /* Many packets OK */
+ && sw->ok > SW_OK) {
+
+ printk(KERN_INFO "sidewinder.c: No more trouble on gameport%d"
+ " - enabling optimization again.\n", sw->gameport->number);
+ sw->length = 22;
+ }
+
+ return 0;
+ }
+
+ sw->ok = 0;
+ sw->fail++;
+
+ if (sw->type == SW_ID_3DP && sw->length == 22 && sw->fail > SW_BAD) { /* Consecutive bad packets */
+
+ printk(KERN_INFO "sidewinder.c: Many bit errors on gameport%d"
+ " - disabling optimization.\n", sw->gameport->number);
+ sw->length = 66;
+ }
+
+ if (sw->fail < SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
+
+ printk(KERN_WARNING "sidewinder.c: Too many bit errors on gameport%d"
+ " - reinitializing joystick.\n", sw->gameport->number);
+
+ if (!i && sw->type == SW_ID_3DP) { /* 3D Pro can be in analog mode */
+ udelay(3 * SW_TIMEOUT);
+ sw_init_digital(sw->gameport);
+ }
+
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(sw->gameport, buf, SW_LENGTH, 0); /* Read normal data packet */
+ udelay(SW_TIMEOUT);
+ sw_read_packet(sw->gameport, buf, SW_LENGTH, i); /* Read ID packet, this initializes the stick */
+
+ sw->fail = SW_FAIL;
+
+ return -1;
+}
+
+static void sw_timer(unsigned long private)
+{
+ struct sw *sw = (void *) private;
+
+ sw->reads++;
+ if (sw_read(sw)) sw->bads++;
+ mod_timer(&sw->timer, jiffies + SW_REFRESH);
+}
+
+static int sw_open(struct input_dev *dev)
+{
+ struct sw *sw = dev->private;
+ if (!sw->used++)
+ mod_timer(&sw->timer, jiffies + SW_REFRESH);
+ return 0;
+}
+
+static void sw_close(struct input_dev *dev)
+{
+ struct sw *sw = dev->private;
+ if (!--sw->used)
+ del_timer(&sw->timer);
+}
+
+/*
+ * sw_print_packet() prints the contents of a SideWinder packet.
+ */
+
+static void sw_print_packet(char *name, int length, unsigned char *buf, char bits)
+{
+ int i;
+
+ printk(KERN_INFO "sidewinder.c: %s packet, %d bits. [", name, length);
+ for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
+ printk("%x", (int)sw_get_bits(buf, i << 2, 4, bits));
+ printk("]\n");
+}
+
+/*
+ * 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 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] = sw_get_bits(buf, 24+8*i, 8, 1);
+
+ for (i = 0; i < 8; i++) /* ASCII firmware revision */
+ rev[i] = sw_get_bits(buf, 88+8*i, 8, 1);
+
+ pnp[7] = rev[8] = 0;
+
+ sprintf(comment, " [PnP %d.%02d id %s rev %s]",
+ (int) ((sw_get_bits(buf, 8, 6, 1) << 6) | /* Two 6-bit values */
+ sw_get_bits(buf, 16, 6, 1)) / 100,
+ (int) ((sw_get_bits(buf, 8, 6, 1) << 6) |
+ sw_get_bits(buf, 16, 6, 1)) % 100,
+ pnp, rev);
+}
+
+/*
+ * 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 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;
+}
+
+/*
+ * sw_connect() probes for SideWinder type joysticks.
+ */
+
+static void sw_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct sw *sw;
+ int i, j, k, l;
+ unsigned char buf[SW_LENGTH];
+ unsigned char idbuf[SW_LENGTH];
+ unsigned char m = 1;
+ char comment[40];
+
+ comment[0] = 0;
+
+ if (!(sw = kmalloc(sizeof(struct sw), GFP_KERNEL))) return;
+ memset(sw, 0, sizeof(struct sw));
+
+ gameport->private = sw;
+
+ sw->gameport = gameport;
+ init_timer(&sw->timer);
+ sw->timer.data = (long) sw;
+ sw->timer.function = sw_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ dbg("Init 0: Opened gameport %d, io %#x, speed %d",
+ gameport->number, gameport->io, gameport->speed);
+
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read normal packet */
+ m |= sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
+ udelay(SW_TIMEOUT);
+ dbg("Init 1: Mode %d. Length %d.", m , i);
+
+ if (!i) { /* No data. 3d Pro analog mode? */
+ sw_init_digital(gameport); /* Switch to digital */
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
+ udelay(SW_TIMEOUT);
+ dbg("Init 1b: Length %d.", i);
+ if (!i) goto fail2; /* No data -> FAIL */
+ }
+
+ j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Read ID. This initializes the stick */
+ m |= sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
+ dbg("Init 2: Mode %d. ID Length %d.", m , j);
+
+ if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Retry reading packet */
+ dbg("Init 2b: Mode %d. Length %d.", m, i);
+ if (!i) goto fail2;
+ udelay(SW_TIMEOUT);
+ j = sw_read_packet(gameport, idbuf, SW_LENGTH, i); /* Retry reading ID */
+ dbg("Init 2c: ID Length %d.", j);
+ }
+
+ sw->type = -1;
+ k = SW_FAIL; /* Try SW_FAIL times */
+ l = 0;
+
+ do {
+ k--;
+ udelay(SW_TIMEOUT);
+ i = sw_read_packet(gameport, buf, SW_LENGTH, 0); /* Read data packet */
+ dbg("Init 3: Mode %d. Length %d. Last %d. Tries %d.", m, i, l, k);
+
+ 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 */
+
+ sw->number = 1;
+ sw->gameport = gameport;
+ sw->length = i;
+ sw->bits = m;
+
+ dbg("Init 3a: Case %d.\n", i * m);
+
+ switch (i * m) {
+ case 60:
+ sw->number++;
+ case 45: /* Ambiguous packet length */
+ if (j <= 40) { /* ID length less or eq 40 -> FSP */
+ case 43:
+ sw->type = SW_ID_FSP;
+ break;
+ }
+ sw->number++;
+ case 30:
+ sw->number++;
+ case 15:
+ sw->type = SW_ID_GP;
+ break;
+ case 33:
+ case 31:
+ sw->type = SW_ID_FFW;
+ break;
+ case 48: /* Ambiguous */
+ if (j == 14) { /* ID length 14*3 -> FFP */
+ sw->type = SW_ID_FFP;
+ sprintf(comment, " [AC %s]", sw_get_bits(idbuf,38,1,3) ? "off" : "on");
+ } else
+ sw->type = SW_ID_PP;
+ break;
+ case 198:
+ sw->length = 22;
+ case 64:
+ sw->type = SW_ID_3DP;
+ if (j == 160) sw_3dp_id(idbuf, comment);
+ break;
+ }
+ }
+
+ } while (k && (sw->type == -1));
+
+ if (sw->type == -1) {
+ printk(KERN_WARNING "sidewinder.c: unknown joystick device detected "
+ "on gameport%d, contact <vojtech@suse.cz>\n", gameport->number);
+ sw_print_packet("ID", j * 3, idbuf, 3);
+ sw_print_packet("Data", i * m, buf, m);
+ goto fail2;
+ }
+
+#ifdef SW_DEBUG
+ sw_print_packet("ID", j * 3, idbuf, 3);
+ sw_print_packet("Data", i * m, buf, m);
+#endif
+
+ k = i;
+ l = j;
+
+ for (i = 0; i < sw->number; i++) {
+ int bits, code;
+
+ sprintf(sw->name, "Microsoft SideWinder %s", sw_name[sw->type]);
+
+ sw->dev[i].private = sw;
+
+ sw->dev[i].open = sw_open;
+ sw->dev[i].close = sw_close;
+
+ sw->dev[i].name = sw->name;
+ sw->dev[i].idbus = BUS_GAMEPORT;
+ sw->dev[i].idvendor = GAMEPORT_ID_VENDOR_MICROSOFT;
+ sw->dev[i].idproduct = sw->type;
+ sw->dev[i].idversion = 0x0100;
+
+ sw->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (j = 0; (bits = sw_bit[sw->type][j]); j++) {
+ code = sw_abs[sw->type][j];
+ set_bit(code, sw->dev[i].absbit);
+ sw->dev[i].absmax[code] = (1 << bits) - 1;
+ sw->dev[i].absmin[code] = (bits == 1) ? -1 : 0;
+ sw->dev[i].absfuzz[code] = ((bits >> 1) >= 2) ? (1 << ((bits >> 1) - 2)) : 0;
+ if (code != ABS_THROTTLE)
+ sw->dev[i].absflat[code] = (bits >= 5) ? (1 << (bits - 5)) : 0;
+ }
+
+ for (j = 0; (code = sw_btn[sw->type][j]); j++)
+ set_bit(code, sw->dev[i].keybit);
+
+ input_register_device(sw->dev + i);
+ printk(KERN_INFO "input%d: %s%s on gameport%d.%d [%d-bit id %d data %d]\n",
+ sw->dev[i].number, sw->name, comment, gameport->number, i, m, l, k);
+ }
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(sw);
+}
+
+static void sw_disconnect(struct gameport *gameport)
+{
+ int i;
+
+ struct sw *sw = gameport->private;
+ for (i = 0; i < sw->number; i++)
+ input_unregister_device(sw->dev + i);
+ gameport_close(gameport);
+ kfree(sw);
+}
+
+static struct gameport_dev sw_dev = {
+ connect: sw_connect,
+ disconnect: sw_disconnect,
+};
+
+int __init sw_init(void)
+{
+ gameport_register_device(&sw_dev);
+ return 0;
+}
+
+void __exit sw_exit(void)
+{
+ gameport_unregister_device(&sw_dev);
+}
+
+module_init(sw_init);
+module_exit(sw_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: spaceball.c,v 1.8 2000/11/23 11:42:39 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * David Thompson
+ * Joseph Krahn
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * SpaceTec SpaceBall 4000 FLX driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define JS_SBALL_MAX_LENGTH 128
+static int spaceball_axes[] = { ABS_X, ABS_Z, ABS_Y, ABS_RX, ABS_RZ, ABS_RY };
+static char *spaceball_name = "SpaceTec SpaceBall 4000 FLX";
+
+/*
+ * Per-Ball data.
+ */
+
+struct spaceball {
+ struct input_dev dev;
+ struct serio *serio;
+ int idx;
+ int escape;
+ unsigned char data[JS_SBALL_MAX_LENGTH];
+};
+
+/*
+ * spaceball_process_packet() decodes packets the driver receives from the
+ * SpaceBall.
+ */
+
+static void spaceball_process_packet(struct spaceball* spaceball)
+{
+ struct input_dev *dev = &spaceball->dev;
+ unsigned char *data = spaceball->data;
+ int i;
+
+ if (spaceball->idx < 2) return;
+
+ printk("%c %d\n", spaceball->data[0], spaceball->idx);
+
+ switch (spaceball->data[0]) {
+
+ case '@': /* Reset packet */
+ spaceball->data[spaceball->idx - 1] = 0;
+ for (i = 1; i < spaceball->idx && spaceball->data[i] == ' '; i++);
+ printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
+ spaceball->dev.number, spaceball_name, spaceball->data + i, spaceball->serio->number);
+ break;
+
+ case 'D': /* Ball data */
+ if (spaceball->idx != 15) return;
+ for (i = 0; i < 6; i++) {
+ input_report_abs(dev, spaceball_axes[i],
+ (__s16)((data[2 * i + 3] << 8) | data[2 * i + 2]));
+ }
+ break;
+
+ case '.': /* Button data, part2 */
+ if (spaceball->idx != 3) return;
+ input_report_key(dev, BTN_0, data[2] & 1);
+ input_report_key(dev, BTN_1, data[2] & 2);
+ break;
+
+ case '?': /* Error packet */
+ spaceball->data[spaceball->idx - 1] = 0;
+ printk(KERN_ERR "spaceball: Device error. [%s]\n", spaceball->data + 1);
+ break;
+ }
+}
+
+/*
+ * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
+ * and end in 0x0d. It uses '^' as an escape for CR, XOFF and XON characters which
+ * can occur in the axis values.
+ */
+
+static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct spaceball *spaceball = serio->private;
+
+ switch (data) {
+ case 0xd:
+ spaceball_process_packet(spaceball);
+ spaceball->idx = 0;
+ spaceball->escape = 0;
+ return;
+ case '^':
+ if (!spaceball->escape) {
+ spaceball->escape = 1;
+ return;
+ }
+ spaceball->escape = 0;
+ case 'M':
+ case 'Q':
+ case 'S':
+ if (spaceball->escape) {
+ spaceball->escape = 0;
+ data &= 0x1f;
+ }
+ default:
+ if (spaceball->escape) {
+ spaceball->escape = 0;
+ printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x (%c)\n", data, data);
+ }
+ if (spaceball->idx < JS_SBALL_MAX_LENGTH)
+ spaceball->data[spaceball->idx++] = data;
+ return;
+ }
+}
+
+/*
+ * spaceball_disconnect() is the opposite of spaceball_connect()
+ */
+
+static void spaceball_disconnect(struct serio *serio)
+{
+ struct spaceball* spaceball = serio->private;
+ input_unregister_device(&spaceball->dev);
+ serio_close(serio);
+ kfree(spaceball);
+}
+
+/*
+ * spaceball_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Magellan, and if found, registers
+ * it as an input device.
+ */
+
+static void spaceball_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct spaceball *spaceball;
+ int i, t;
+
+ if (serio->type != (SERIO_RS232 | SERIO_SPACEBALL))
+ return;
+
+ if (!(spaceball = kmalloc(sizeof(struct spaceball), GFP_KERNEL)))
+ return;
+ memset(spaceball, 0, sizeof(struct spaceball));
+
+ spaceball->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ spaceball->dev.keybit[LONG(BTN_0)] = BIT(BTN_0) | BIT(BTN_1);
+
+ for (i = 0; i < 6; i++) {
+ t = spaceball_axes[i];
+ set_bit(t, spaceball->dev.absbit);
+ spaceball->dev.absmin[t] = i < 3 ? -8000 : -1600;
+ spaceball->dev.absmax[t] = i < 3 ? 8000 : 1600;
+ spaceball->dev.absflat[t] = i < 3 ? 40 : 8;
+ spaceball->dev.absfuzz[t] = i < 3 ? 8 : 2;
+ }
+
+ spaceball->serio = serio;
+ spaceball->dev.private = spaceball;
+
+ spaceball->dev.name = spaceball_name;
+ spaceball->dev.idbus = BUS_RS232;
+ spaceball->dev.idvendor = SERIO_SPACEBALL;
+ spaceball->dev.idproduct = 0x0001;
+ spaceball->dev.idversion = 0x0100;
+
+ serio->private = spaceball;
+
+ if (serio_open(serio, dev)) {
+ kfree(spaceball);
+ return;
+ }
+
+ input_register_device(&spaceball->dev);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev spaceball_dev = {
+ interrupt: spaceball_interrupt,
+ connect: spaceball_connect,
+ disconnect: spaceball_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init spaceball_init(void)
+{
+ serio_register_device(&spaceball_dev);
+ return 0;
+}
+
+void __exit spaceball_exit(void)
+{
+ serio_unregister_device(&spaceball_dev);
+}
+
+module_init(spaceball_init);
+module_exit(spaceball_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: spaceorb.c,v 1.7 2000/05/29 11:19:51 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * David Thompson
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * SpaceTec SpaceOrb 360 and Avenger 6dof controller driver for Linux
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+
+/*
+ * Constants.
+ */
+
+#define SPACEORB_MAX_LENGTH 64
+
+static int spaceorb_buttons[] = { BTN_TL, BTN_TR, BTN_Y, BTN_X, BTN_B, BTN_A, BTN_MODE};
+static int spaceorb_axes[] = { ABS_X, ABS_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ};
+static char *spaceorb_name = "SpaceTec SpaceOrb 360";
+
+/*
+ * Per-Orb data.
+ */
+
+struct spaceorb {
+ struct input_dev dev;
+ struct serio *serio;
+ int idx;
+ unsigned char data[SPACEORB_MAX_LENGTH];
+};
+
+static unsigned char spaceorb_xor[] = "SpaceWare";
+
+static unsigned char *spaceorb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
+ "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
+
+/*
+ * spaceorb_process_packet() decodes packets the driver receives from the
+ * SpaceOrb.
+ */
+
+static void spaceorb_process_packet(struct spaceorb *spaceorb)
+{
+ struct input_dev *dev = &spaceorb->dev;
+ unsigned char *data = spaceorb->data;
+ unsigned char c = 0;
+ int axes[6];
+ int i;
+
+ if (spaceorb->idx < 2) return;
+ for (i = 0; i < spaceorb->idx; i++) c ^= data[i];
+ if (c) return;
+
+ switch (data[0]) {
+
+ case 'R': /* Reset packet */
+ spaceorb->data[spaceorb->idx - 1] = 0;
+ for (i = 1; i < spaceorb->idx && spaceorb->data[i] == ' '; i++);
+ printk(KERN_INFO "input%d: %s [%s] on serio%d\n",
+ spaceorb->dev.number, spaceorb_name, spaceorb->data + i, spaceorb->serio->number);
+ break;
+
+ case 'D': /* Ball + button data */
+ if (spaceorb->idx != 12) return;
+ for (i = 0; i < 9; i++) spaceorb->data[i+2] ^= spaceorb_xor[i];
+ axes[0] = ( data[2] << 3) | (data[ 3] >> 4);
+ axes[1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
+ axes[2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
+ axes[3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
+ axes[4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
+ axes[5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
+ for (i = 0; i < 6; i++)
+ input_report_abs(dev, spaceorb_axes[i], axes[i] - ((axes[i] & 0x200) ? 1024 : 0));
+ for (i = 0; i < 8; i++)
+ input_report_key(dev, spaceorb_buttons[i], (data[1] >> i) & 1);
+ break;
+
+ case 'K': /* Button data */
+ if (spaceorb->idx != 5) return;
+ for (i = 0; i < 7; i++)
+ input_report_key(dev, spaceorb_buttons[i], (data[2] >> i) & 1);
+
+ break;
+
+ case 'E': /* Error packet */
+ if (spaceorb->idx != 4) return;
+ printk(KERN_ERR "joy-spaceorb: Device error. [ ");
+ for (i = 0; i < 7; i++) if (data[1] & (1 << i)) printk("%s ", spaceorb_errors[i]);
+ printk("]\n");
+ break;
+ }
+}
+
+static void spaceorb_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct spaceorb* spaceorb = serio->private;
+
+ if (~data & 0x80) {
+ if (spaceorb->idx) spaceorb_process_packet(spaceorb);
+ spaceorb->idx = 0;
+ }
+ if (spaceorb->idx < SPACEORB_MAX_LENGTH)
+ spaceorb->data[spaceorb->idx++] = data & 0x7f;
+}
+
+/*
+ * spaceorb_disconnect() is the opposite of spaceorb_connect()
+ */
+
+static void spaceorb_disconnect(struct serio *serio)
+{
+ struct spaceorb* spaceorb = serio->private;
+ input_unregister_device(&spaceorb->dev);
+ serio_close(serio);
+ kfree(spaceorb);
+}
+
+/*
+ * spaceorb_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the SpaceOrb/Avenger, and if found, registers
+ * it as an input device.
+ */
+
+static void spaceorb_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct spaceorb *spaceorb;
+ int i, t;
+
+ if (serio->type != (SERIO_RS232 | SERIO_SPACEORB))
+ return;
+
+ if (!(spaceorb = kmalloc(sizeof(struct spaceorb), GFP_KERNEL)))
+ return;
+ memset(spaceorb, 0, sizeof(struct spaceorb));
+
+ spaceorb->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < 7; i++)
+ set_bit(spaceorb_buttons[i], &spaceorb->dev.keybit);
+
+ for (i = 0; i < 6; i++) {
+ t = spaceorb_axes[i];
+ set_bit(t, spaceorb->dev.absbit);
+ spaceorb->dev.absmin[t] = -508;
+ spaceorb->dev.absmax[t] = 508;
+ }
+
+ spaceorb->serio = serio;
+ spaceorb->dev.private = spaceorb;
+
+ spaceorb->dev.name = spaceorb_name;
+ spaceorb->dev.idbus = BUS_RS232;
+ spaceorb->dev.idvendor = SERIO_SPACEORB;
+ spaceorb->dev.idproduct = 0x0001;
+ spaceorb->dev.idversion = 0x0100;
+
+ serio->private = spaceorb;
+
+ if (serio_open(serio, dev)) {
+ kfree(spaceorb);
+ return;
+ }
+
+ input_register_device(&spaceorb->dev);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev spaceorb_dev = {
+ interrupt: spaceorb_interrupt,
+ connect: spaceorb_connect,
+ disconnect: spaceorb_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init spaceorb_init(void)
+{
+ serio_register_device(&spaceorb_dev);
+ return 0;
+}
+
+void __exit spaceorb_exit(void)
+{
+ serio_unregister_device(&spaceorb_dev);
+}
+
+module_init(spaceorb_init);
+module_exit(spaceorb_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: stinger.c,v 1.4 2001/05/23 09:25:02 vojtech Exp $
+ *
+ * Copyright (c) 2000-2001 Vojtech Pavlik
+ * Copyright (c) 2000 Mark Fletcher
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Gravis Stinger gamepad driver for Linux
+ */
+
+/*
+ * This program is free warftware; 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define STINGER_MAX_LENGTH 8
+
+static char *stinger_name = "Gravis Stinger";
+
+/*
+ * Per-Stinger data.
+ */
+
+struct stinger {
+ struct input_dev dev;
+ int idx;
+ unsigned char data[STINGER_MAX_LENGTH];
+};
+
+/*
+ * stinger_process_packet() decodes packets the driver receives from the
+ * Stinger. It updates the data accordingly.
+ */
+
+static void stinger_process_packet(struct stinger *stinger)
+{
+ struct input_dev *dev = &stinger->dev;
+ unsigned char *data = stinger->data;
+
+ if (!stinger->idx) return;
+
+ input_report_key(dev, BTN_A, ((data[0] & 0x20) >> 5));
+ input_report_key(dev, BTN_B, ((data[0] & 0x10) >> 4));
+ input_report_key(dev, BTN_C, ((data[0] & 0x08) >> 3));
+ input_report_key(dev, BTN_X, ((data[0] & 0x04) >> 2));
+ input_report_key(dev, BTN_Y, ((data[3] & 0x20) >> 5));
+ input_report_key(dev, BTN_Z, ((data[3] & 0x10) >> 4));
+ input_report_key(dev, BTN_TL, ((data[3] & 0x08) >> 3));
+ input_report_key(dev, BTN_TR, ((data[3] & 0x04) >> 2));
+ input_report_key(dev, BTN_SELECT, ((data[3] & 0x02) >> 1));
+ input_report_key(dev, BTN_START, (data[3] & 0x01));
+
+ input_report_abs(dev, ABS_X, (data[1] & 0x3F) - ((data[0] & 0x01) << 6));
+ input_report_abs(dev, ABS_Y, ((data[0] & 0x02) << 5) - (data[2] & 0x3F));
+
+ return;
+}
+
+/*
+ * stinger_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void stinger_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct stinger* stinger = serio->private;
+
+ /* All Stinger packets are 4 bytes */
+
+ if (stinger->idx < STINGER_MAX_LENGTH)
+ stinger->data[stinger->idx++] = data;
+
+ if (stinger->idx == 4) {
+ stinger_process_packet(stinger);
+ stinger->idx = 0;
+ }
+
+ return;
+}
+
+/*
+ * stinger_disconnect() is the opposite of stinger_connect()
+ */
+
+static void stinger_disconnect(struct serio *serio)
+{
+ struct stinger* stinger = serio->private;
+ input_unregister_device(&stinger->dev);
+ serio_close(serio);
+ kfree(stinger);
+}
+
+/*
+ * stinger_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Stinger, and if found, registers
+ * it as an input device.
+ */
+
+static void stinger_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct stinger *stinger;
+ int i;
+
+ if (serio->type != (SERIO_RS232 | SERIO_STINGER))
+ return;
+
+ if (!(stinger = kmalloc(sizeof(struct stinger), GFP_KERNEL)))
+ return;
+
+ memset(stinger, 0, sizeof(struct stinger));
+
+ stinger->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ stinger->dev.keybit[LONG(BTN_A)] = BIT(BTN_A) | BIT(BTN_B) | BIT(BTN_C) | BIT(BTN_X) | \
+ BIT(BTN_Y) | BIT(BTN_Z) | BIT(BTN_TL) | BIT(BTN_TR) | \
+ BIT(BTN_START) | BIT(BTN_SELECT);
+ stinger->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ stinger->dev.name = stinger_name;
+ stinger->dev.idbus = BUS_RS232;
+ stinger->dev.idvendor = SERIO_STINGER;
+ stinger->dev.idproduct = 0x0001;
+ stinger->dev.idversion = 0x0100;
+
+ for (i = 0; i < 2; i++) {
+ stinger->dev.absmax[ABS_X+i] = 64;
+ stinger->dev.absmin[ABS_X+i] = -64;
+ stinger->dev.absflat[ABS_X+i] = 4;
+ }
+
+ stinger->dev.private = stinger;
+
+ serio->private = stinger;
+
+ if (serio_open(serio, dev)) {
+ kfree(stinger);
+ return;
+ }
+
+ input_register_device(&stinger->dev);
+
+ printk(KERN_INFO "input%d: %s on serio%d\n", stinger->dev.number, stinger_name, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev stinger_dev = {
+ interrupt: stinger_interrupt,
+ connect: stinger_connect,
+ disconnect: stinger_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init stinger_init(void)
+{
+ serio_register_device(&stinger_dev);
+ return 0;
+}
+
+void __exit stinger_exit(void)
+{
+ serio_unregister_device(&stinger_dev);
+}
+
+module_init(stinger_init);
+module_exit(stinger_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: tmdc.c,v 1.23 2000/11/29 19:52:24 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ *
+ * Based on the work of:
+ * Trystan Larey-Williams
+ *
+ */
+
+/*
+ * ThrustMaster DirectConnect (BSP) joystick family driver for Linux
+ */
+
+/*
+ * 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/delay.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/gameport.h>
+#include <linux/input.h>
+
+#define TMDC_MAX_START 400 /* 400 us */
+#define TMDC_MAX_STROBE 45 /* 45 us */
+#define TMDC_MAX_LENGTH 13
+#define TMDC_REFRESH_TIME HZ/50 /* 20 ms */
+
+#define TMDC_MODE_M3DI 1
+#define TMDC_MODE_3DRP 3
+#define TMDC_MODE_AT 4
+#define TMDC_MODE_FM 8
+#define TMDC_MODE_FGP 163
+
+#define TMDC_BYTE_ID 10
+#define TMDC_BYTE_REV 11
+#define TMDC_BYTE_DEF 12
+
+#define TMDC_ABS 7
+#define TMDC_ABS_HAT 4
+#define TMDC_BTN 16
+
+static unsigned char tmdc_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
+static unsigned char tmdc_byte_d[16] = { 2, 5, 8, 9 };
+
+static signed char tmdc_abs[TMDC_ABS] =
+ { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
+static signed char tmdc_abs_hat[TMDC_ABS_HAT] =
+ { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static signed char tmdc_abs_at[TMDC_ABS] =
+ { ABS_X, ABS_Y, ABS_RUDDER, -1, ABS_THROTTLE };
+static signed char tmdc_abs_fm[TMDC_ABS] =
+ { ABS_RX, ABS_RY, ABS_X, ABS_Y };
+
+static short tmdc_btn_pad[TMDC_BTN] =
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
+static short tmdc_btn_joy[TMDC_BTN] =
+ { BTN_TRIGGER, BTN_THUMB, BTN_TOP, BTN_TOP2, BTN_BASE, BTN_BASE2, BTN_THUMB2, BTN_PINKIE,
+ BTN_BASE3, BTN_BASE4, BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z };
+static short tmdc_btn_fm[TMDC_BTN] =
+ { BTN_TRIGGER, BTN_C, BTN_B, BTN_A, BTN_THUMB, BTN_X, BTN_Y, BTN_Z, BTN_TOP, BTN_TOP2 };
+static short tmdc_btn_at[TMDC_BTN] =
+ { BTN_TRIGGER, BTN_THUMB2, BTN_PINKIE, BTN_THUMB, BTN_BASE6, BTN_BASE5, BTN_BASE4,
+ BTN_BASE3, BTN_BASE2, BTN_BASE };
+
+static struct {
+ int x;
+ int y;
+} tmdc_hat_to_axis[] = {{ 0, 0}, { 1, 0}, { 0,-1}, {-1, 0}, { 0, 1}};
+
+struct tmdc {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ char name[2][64];
+ int mode[2];
+ signed char *abs[2];
+ short *btn[2];
+ unsigned char absc[2];
+ unsigned char btnc[2][4];
+ unsigned char btno[2][4];
+ int used;
+ int reads;
+ int bads;
+ unsigned char exists;
+};
+
+/*
+ * tmdc_read_packet() reads a ThrustMaster packet.
+ */
+
+static int tmdc_read_packet(struct gameport *gameport, unsigned char data[2][TMDC_MAX_LENGTH])
+{
+ unsigned char u, v, w, x;
+ unsigned long flags;
+ int i[2], j[2], t[2], p, k;
+
+ p = gameport_time(gameport, TMDC_MAX_STROBE);
+
+ for (k = 0; k < 2; k++) {
+ t[k] = gameport_time(gameport, TMDC_MAX_START);
+ i[k] = j[k] = 0;
+ }
+
+ __save_flags(flags);
+ __cli();
+ gameport_trigger(gameport);
+
+ w = gameport_read(gameport) >> 4;
+
+ do {
+ x = w;
+ w = gameport_read(gameport) >> 4;
+
+ for (k = 0, v = w, u = x; k < 2; k++, v >>= 2, u >>= 2) {
+ if (~v & u & 2) {
+ if (t[k] <= 0 || i[k] >= TMDC_MAX_LENGTH) continue;
+ t[k] = p;
+ if (j[k] == 0) { /* Start bit */
+ if (~v & 1) t[k] = 0;
+ data[k][i[k]] = 0; j[k]++; continue;
+ }
+ if (j[k] == 9) { /* Stop bit */
+ if (v & 1) t[k] = 0;
+ j[k] = 0; i[k]++; continue;
+ }
+ data[k][i[k]] |= (~v & 1) << (j[k]++ - 1); /* Data bit */
+ }
+ t[k]--;
+ }
+ } while (t[0] > 0 || t[1] > 0);
+
+ __restore_flags(flags);
+
+ return (i[0] == TMDC_MAX_LENGTH) | ((i[1] == TMDC_MAX_LENGTH) << 1);
+}
+
+/*
+ * tmdc_read() reads and analyzes ThrustMaster joystick data.
+ */
+
+static void tmdc_timer(unsigned long private)
+{
+ unsigned char data[2][TMDC_MAX_LENGTH];
+ struct tmdc *tmdc = (void *) private;
+ struct input_dev *dev;
+ unsigned char r, bad = 0;
+ int i, j, k, l;
+
+ tmdc->reads++;
+
+ if ((r = tmdc_read_packet(tmdc->gameport, data)) != tmdc->exists)
+ bad = 1;
+
+ for (j = 0; j < 2; j++)
+ if (r & (1 << j) & tmdc->exists) {
+
+ if (data[j][TMDC_BYTE_ID] != tmdc->mode[j]) {
+ bad = 1;
+ continue;
+ }
+
+ dev = tmdc->dev + j;
+
+ for (i = 0; i < tmdc->absc[j]; i++) {
+ if (tmdc->abs[j][i] < 0) continue;
+ input_report_abs(dev, tmdc->abs[j][i], data[j][tmdc_byte_a[i]]);
+ }
+
+ switch (tmdc->mode[j]) {
+
+ case TMDC_MODE_M3DI:
+
+ i = tmdc_byte_d[0];
+ input_report_abs(dev, ABS_HAT0X, ((data[j][i] >> 3) & 1) - ((data[j][i] >> 1) & 1));
+ input_report_abs(dev, ABS_HAT0Y, ((data[j][i] >> 2) & 1) - ( data[j][i] & 1));
+ break;
+
+ case TMDC_MODE_AT:
+
+ i = tmdc_byte_a[3];
+ input_report_abs(dev, ABS_HAT0X, tmdc_hat_to_axis[(data[j][i] - 141) / 25].x);
+ input_report_abs(dev, ABS_HAT0Y, tmdc_hat_to_axis[(data[j][i] - 141) / 25].y);
+ break;
+
+ }
+
+ for (k = l = 0; k < 4; k++) {
+ for (i = 0; i < tmdc->btnc[j][k]; i++)
+ input_report_key(dev, tmdc->btn[j][i + l],
+ ((data[j][tmdc_byte_d[k]] >> (i + tmdc->btno[j][k])) & 1));
+ l += tmdc->btnc[j][k];
+ }
+ }
+
+ tmdc->bads += bad;
+
+ mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
+}
+
+static int tmdc_open(struct input_dev *dev)
+{
+ struct tmdc *tmdc = dev->private;
+ if (!tmdc->used++)
+ mod_timer(&tmdc->timer, jiffies + TMDC_REFRESH_TIME);
+ return 0;
+}
+
+static void tmdc_close(struct input_dev *dev)
+{
+ struct tmdc *tmdc = dev->private;
+ if (!--tmdc->used)
+ del_timer(&tmdc->timer);
+}
+
+/*
+ * tmdc_probe() probes for ThrustMaster type joysticks.
+ */
+
+static void tmdc_connect(struct gameport *gameport, struct gameport_dev *dev)
+{
+ struct models {
+ unsigned char id;
+ char *name;
+ char abs;
+ char hats;
+ char btnc[4];
+ char btno[4];
+ signed char *axes;
+ short *buttons;
+ } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 2, { 4, 2 }, { 4, 6 }, tmdc_abs, tmdc_btn_joy },
+ { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+ { 4, "ThrustMaster Attack Throttle", 5, 2, { 4, 6 }, { 4, 2 }, tmdc_abs_at, tmdc_btn_at },
+ { 8, "ThrustMaster FragMaster", 4, 0, { 8, 2 }, { 0, 0 }, tmdc_abs_fm, tmdc_btn_fm },
+ { 163, "Thrustmaster Fusion GamePad", 2, 0, { 8, 2 }, { 0, 0 }, tmdc_abs, tmdc_btn_pad },
+ { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, { 0, 0 }, { 0, 0 }, tmdc_abs, tmdc_btn_joy }};
+
+ unsigned char data[2][TMDC_MAX_LENGTH];
+ struct tmdc *tmdc;
+ int i, j, k, l, m;
+
+ if (!(tmdc = kmalloc(sizeof(struct tmdc), GFP_KERNEL)))
+ return;
+ memset(tmdc, 0, sizeof(struct tmdc));
+
+ gameport->private = tmdc;
+
+ tmdc->gameport = gameport;
+ init_timer(&tmdc->timer);
+ tmdc->timer.data = (long) tmdc;
+ tmdc->timer.function = tmdc_timer;
+
+ if (gameport_open(gameport, dev, GAMEPORT_MODE_RAW))
+ goto fail1;
+
+ if (!(tmdc->exists = tmdc_read_packet(gameport, data)))
+ goto fail2;
+
+ for (j = 0; j < 2; j++)
+ if (tmdc->exists & (1 << j)) {
+
+ tmdc->mode[j] = data[j][TMDC_BYTE_ID];
+
+ for (m = 0; models[m].id && models[m].id != tmdc->mode[j]; m++);
+
+ tmdc->abs[j] = models[m].axes;
+ tmdc->btn[j] = models[m].buttons;
+
+ if (!models[m].id) {
+ models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
+ for (k = 0; k < 4; k++)
+ models[m].btnc[k] = k < (data[j][TMDC_BYTE_DEF] & 0xf) ? 8 : 0;
+ }
+
+ tmdc->absc[j] = models[m].abs;
+ for (k = 0; k < 4; k++) {
+ tmdc->btnc[j][k] = models[m].btnc[k];
+ tmdc->btno[j][k] = models[m].btno[k];
+ }
+
+ sprintf(tmdc->name[j], models[m].name, models[m].abs,
+ (data[j][TMDC_BYTE_DEF] & 0xf) << 3, tmdc->mode[j]);
+
+ tmdc->dev[j].private = tmdc;
+ tmdc->dev[j].open = tmdc_open;
+ tmdc->dev[j].close = tmdc_close;
+
+ tmdc->dev[j].name = tmdc->name[j];
+ tmdc->dev[j].idbus = BUS_GAMEPORT;
+ tmdc->dev[j].idvendor = GAMEPORT_ID_VENDOR_THRUSTMASTER;
+ tmdc->dev[j].idproduct = models[m].id;
+ tmdc->dev[j].idversion = 0x0100;
+
+ tmdc->dev[j].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+
+ for (i = 0; i < models[m].abs && i < TMDC_ABS; i++) {
+ if (tmdc->abs[i] < 0) continue;
+ set_bit(tmdc->abs[j][i], tmdc->dev[j].absbit);
+ tmdc->dev[j].absmin[tmdc->abs[j][i]] = 8;
+ tmdc->dev[j].absmax[tmdc->abs[j][i]] = 248;
+ tmdc->dev[j].absfuzz[tmdc->abs[j][i]] = 2;
+ tmdc->dev[j].absflat[tmdc->abs[j][i]] = 4;
+ }
+
+ for (i = 0; i < models[m].hats && i < TMDC_ABS_HAT; i++) {
+ set_bit(tmdc_abs_hat[i], tmdc->dev[j].absbit);
+ tmdc->dev[j].absmin[tmdc_abs_hat[i]] = -1;
+ tmdc->dev[j].absmax[tmdc_abs_hat[i]] = 1;
+ }
+
+ for (k = l = 0; k < 4; k++) {
+ for (i = 0; i < models[m].btnc[k] && i < TMDC_BTN; i++)
+ set_bit(tmdc->btn[j][i + l], tmdc->dev[j].keybit);
+ l += models[m].btnc[k];
+ }
+
+ input_register_device(tmdc->dev + j);
+ printk(KERN_INFO "input%d: %s on gameport%d.%d\n",
+ tmdc->dev[j].number, tmdc->name[j], gameport->number, j);
+ }
+
+ return;
+fail2: gameport_close(gameport);
+fail1: kfree(tmdc);
+}
+
+static void tmdc_disconnect(struct gameport *gameport)
+{
+ struct tmdc *tmdc = gameport->private;
+ int i;
+ for (i = 0; i < 2; i++)
+ if (tmdc->exists & (1 << i))
+ input_unregister_device(tmdc->dev + i);
+ gameport_close(gameport);
+ kfree(tmdc);
+}
+
+static struct gameport_dev tmdc_dev = {
+ connect: tmdc_connect,
+ disconnect: tmdc_disconnect,
+};
+
+int __init tmdc_init(void)
+{
+ gameport_register_device(&tmdc_dev);
+ return 0;
+}
+
+void __exit tmdc_exit(void)
+{
+ gameport_unregister_device(&tmdc_dev);
+}
+
+module_init(tmdc_init);
+module_exit(tmdc_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+/*
+ * $Id: turbografx.c,v 1.8 2000/05/29 20:39:38 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Steffen Schwenke
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * TurboGraFX parallel port interface driver for Linux.
+ */
+
+/*
+ * 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/kernel.h>
+#include <linux/parport.h>
+#include <linux/input.h>
+#include <linux/module.h>
+#include <linux/init.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+MODULE_LICENSE("GPL");
+MODULE_PARM(tgfx, "2-8i");
+MODULE_PARM(tgfx_2, "2-8i");
+MODULE_PARM(tgfx_3, "2-8i");
+
+#define TGFX_REFRESH_TIME HZ/100 /* 10 ms */
+
+#define TGFX_TRIGGER 0x08
+#define TGFX_UP 0x10
+#define TGFX_DOWN 0x20
+#define TGFX_LEFT 0x40
+#define TGFX_RIGHT 0x80
+
+#define TGFX_THUMB 0x02
+#define TGFX_THUMB2 0x04
+#define TGFX_TOP 0x01
+#define TGFX_TOP2 0x08
+
+static int tgfx[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+static int tgfx_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
+
+static int tgfx_buttons[] = { BTN_TRIGGER, BTN_THUMB, BTN_THUMB2, BTN_TOP, BTN_TOP2 };
+static char *tgfx_name = "TurboGraFX Multisystem joystick";
+
+struct tgfx {
+ struct pardevice *pd;
+ struct timer_list timer;
+ struct input_dev dev[7];
+ int sticks;
+ int used;
+} *tgfx_base[3];
+
+/*
+ * tgfx_timer() reads and analyzes TurboGraFX joystick data.
+ */
+
+static void tgfx_timer(unsigned long private)
+{
+ struct tgfx *tgfx = (void *) private;
+ struct input_dev *dev;
+ int data1, data2, i;
+
+ for (i = 0; i < 7; i++)
+ if (tgfx->sticks & (1 << i)) {
+
+ dev = tgfx->dev + i;
+
+ parport_write_data(tgfx->pd->port, ~(1 << i));
+ data1 = parport_read_status(tgfx->pd->port) ^ 0x7f;
+ data2 = parport_read_control(tgfx->pd->port) ^ 0x04; /* CAVEAT parport */
+
+ input_report_abs(dev, ABS_X, !!(data1 & TGFX_RIGHT) - !!(data1 & TGFX_LEFT));
+ input_report_abs(dev, ABS_Y, !!(data1 & TGFX_DOWN ) - !!(data1 & TGFX_UP ));
+
+ input_report_key(dev, BTN_TRIGGER, (data1 & TGFX_TRIGGER));
+ input_report_key(dev, BTN_THUMB, (data2 & TGFX_THUMB ));
+ input_report_key(dev, BTN_THUMB2, (data2 & TGFX_THUMB2 ));
+ input_report_key(dev, BTN_TOP, (data2 & TGFX_TOP ));
+ input_report_key(dev, BTN_TOP2, (data2 & TGFX_TOP2 ));
+ }
+
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+}
+
+static int tgfx_open(struct input_dev *dev)
+{
+ struct tgfx *tgfx = dev->private;
+ if (!tgfx->used++) {
+ parport_claim(tgfx->pd);
+ parport_write_control(tgfx->pd->port, 0x04);
+ mod_timer(&tgfx->timer, jiffies + TGFX_REFRESH_TIME);
+ }
+ return 0;
+}
+
+static void tgfx_close(struct input_dev *dev)
+{
+ struct tgfx *tgfx = dev->private;
+ if (!--tgfx->used) {
+ del_timer(&tgfx->timer);
+ parport_write_control(tgfx->pd->port, 0x00);
+ parport_release(tgfx->pd);
+ }
+}
+
+/*
+ * tgfx_probe() probes for tg gamepads.
+ */
+
+static struct tgfx __init *tgfx_probe(int *config)
+{
+ struct tgfx *tgfx;
+ struct parport *pp;
+ int i, j;
+
+ if (config[0] < 0)
+ return NULL;
+
+ for (pp = parport_enumerate(); pp && (config[0] > 0); pp = pp->next)
+ config[0]--;
+
+ if (!pp) {
+ printk(KERN_ERR "turbografx.c: no such parport\n");
+ return NULL;
+ }
+
+ if (!(tgfx = kmalloc(sizeof(struct tgfx), GFP_KERNEL)))
+ return NULL;
+ memset(tgfx, 0, sizeof(struct tgfx));
+
+ tgfx->pd = parport_register_device(pp, "turbografx", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+
+ if (!tgfx->pd) {
+ printk(KERN_ERR "turbografx.c: parport busy already - lp.o loaded?\n");
+ kfree(tgfx);
+ return NULL;
+ }
+
+ init_timer(&tgfx->timer);
+ tgfx->timer.data = (long) tgfx;
+ tgfx->timer.function = tgfx_timer;
+
+ tgfx->sticks = 0;
+
+ for (i = 0; i < 7; i++)
+ if (config[i+1] > 0 && config[i+1] < 6) {
+
+ tgfx->sticks |= (1 << i);
+
+ tgfx->dev[i].private = tgfx;
+ tgfx->dev[i].open = tgfx_open;
+ tgfx->dev[i].close = tgfx_close;
+
+ tgfx->dev[i].name = tgfx_name;
+ tgfx->dev[i].idbus = BUS_PARPORT;
+ tgfx->dev[i].idvendor = 0x0003;
+ tgfx->dev[i].idproduct = config[i+1];
+ tgfx->dev[i].idversion = 0x0100;
+
+ tgfx->dev[i].evbit[0] = BIT(EV_KEY) | BIT(EV_ABS);
+ tgfx->dev[i].absbit[0] = BIT(ABS_X) | BIT(ABS_Y);
+
+ for (j = 0; j < config[i+1]; j++)
+ set_bit(tgfx_buttons[j], tgfx->dev[i].keybit);
+
+ tgfx->dev[i].absmin[ABS_X] = -1; tgfx->dev[i].absmax[ABS_X] = 1;
+ tgfx->dev[i].absmin[ABS_Y] = -1; tgfx->dev[i].absmax[ABS_Y] = 1;
+
+ input_register_device(tgfx->dev + i);
+ printk(KERN_INFO "input%d: %d-button Multisystem joystick on %s\n",
+ tgfx->dev[i].number, config[i+1], tgfx->pd->port->name);
+ }
+
+ if (!tgfx->sticks) {
+ parport_unregister_device(tgfx->pd);
+ kfree(tgfx);
+ return NULL;
+ }
+
+ return tgfx;
+}
+
+#ifndef MODULE
+int __init tgfx_setup(char *str)
+{
+ int i, ints[9];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 8; i++) tgfx[i] = ints[i + 1];
+ return 1;
+}
+int __init tgfx_setup_2(char *str)
+{
+ int i, ints[9];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 8; i++) tgfx_2[i] = ints[i + 1];
+ return 1;
+}
+int __init tgfx_setup_3(char *str)
+{
+ int i, ints[9];
+ get_options(str, ARRAY_SIZE(ints), ints);
+ for (i = 0; i <= ints[0] && i < 8; i++) tgfx_3[i] = ints[i + 1];
+ return 1;
+}
+__setup("tgfx=", tgfx_setup);
+__setup("tgfx_2=", tgfx_setup_2);
+__setup("tgfx_3=", tgfx_setup_3);
+#endif
+
+int __init tgfx_init(void)
+{
+ tgfx_base[0] = tgfx_probe(tgfx);
+ tgfx_base[1] = tgfx_probe(tgfx_2);
+ tgfx_base[2] = tgfx_probe(tgfx_3);
+
+ if (tgfx_base[0] || tgfx_base[1] || tgfx_base[2])
+ return 0;
+
+ return -ENODEV;
+}
+
+void __exit tgfx_exit(void)
+{
+ int i, j;
+
+ for (i = 0; i < 3; i++)
+ if (tgfx_base[i]) {
+ for (j = 0; j < 7; j++)
+ if (tgfx_base[i]->sticks & (1 << j))
+ input_unregister_device(tgfx_base[i]->dev + j);
+ parport_unregister_device(tgfx_base[i]->pd);
+ }
+}
+
+module_init(tgfx_init);
+module_exit(tgfx_exit);
--- /dev/null
+/*
+ * $Id: warrior.c,v 1.8 2000/05/31 13:17:12 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * Logitech WingMan Warrior joystick driver for Linux
+ */
+
+/*
+ * This program is free warftware; 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/slab.h>
+#include <linux/input.h>
+#include <linux/serio.h>
+#include <linux/init.h>
+
+/*
+ * Constants.
+ */
+
+#define WARRIOR_MAX_LENGTH 16
+static char warrior_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
+static char *warrior_name = "Logitech WingMan Warrior";
+
+/*
+ * Per-Warrior data.
+ */
+
+struct warrior {
+ struct input_dev dev;
+ int idx, len;
+ unsigned char data[WARRIOR_MAX_LENGTH];
+};
+
+/*
+ * warrior_process_packet() decodes packets the driver receives from the
+ * Warrior. It updates the data accordingly.
+ */
+
+static void warrior_process_packet(struct warrior *warrior)
+{
+ struct input_dev *dev = &warrior->dev;
+ unsigned char *data = warrior->data;
+
+ if (!warrior->idx) return;
+
+ switch ((data[0] >> 4) & 7) {
+ case 1: /* Button data */
+ input_report_key(dev, BTN_TRIGGER, data[3] & 1);
+ input_report_key(dev, BTN_THUMB, (data[3] >> 1) & 1);
+ input_report_key(dev, BTN_TOP, (data[3] >> 2) & 1);
+ input_report_key(dev, BTN_TOP2, (data[3] >> 3) & 1);
+ return;
+ case 3: /* XY-axis info->data */
+ input_report_abs(dev, ABS_X, ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5)));
+ input_report_abs(dev, ABS_Y, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
+ return;
+ case 5: /* Throttle, spinner, hat info->data */
+ input_report_abs(dev, ABS_THROTTLE, (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7));
+ input_report_abs(dev, ABS_HAT0X, (data[3] & 2 ? 1 : 0) - (data[3] & 1 ? 1 : 0));
+ input_report_abs(dev, ABS_HAT0Y, (data[3] & 8 ? 1 : 0) - (data[3] & 4 ? 1 : 0));
+ input_report_rel(dev, REL_DIAL, (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5));
+ return;
+ }
+}
+
+/*
+ * warrior_interrupt() is called by the low level driver when characters
+ * are ready for us. We then buffer them for further processing, or call the
+ * packet processing routine.
+ */
+
+static void warrior_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct warrior* warrior = serio->private;
+
+ if (data & 0x80) {
+ if (warrior->idx) warrior_process_packet(warrior);
+ warrior->idx = 0;
+ warrior->len = warrior_lengths[(data >> 4) & 7];
+ }
+
+ if (warrior->idx < warrior->len)
+ warrior->data[warrior->idx++] = data;
+
+ if (warrior->idx == warrior->len) {
+ if (warrior->idx) warrior_process_packet(warrior);
+ warrior->idx = 0;
+ warrior->len = 0;
+ }
+}
+
+/*
+ * warrior_disconnect() is the opposite of warrior_connect()
+ */
+
+static void warrior_disconnect(struct serio *serio)
+{
+ struct warrior* warrior = serio->private;
+ input_unregister_device(&warrior->dev);
+ serio_close(serio);
+ kfree(warrior);
+}
+
+/*
+ * warrior_connect() is the routine that is called when someone adds a
+ * new serio device. It looks for the Warrior, and if found, registers
+ * it as an input device.
+ */
+
+static void warrior_connect(struct serio *serio, struct serio_dev *dev)
+{
+ struct warrior *warrior;
+ int i;
+
+ if (serio->type != (SERIO_RS232 | SERIO_WARRIOR))
+ return;
+
+ if (!(warrior = kmalloc(sizeof(struct warrior), GFP_KERNEL)))
+ return;
+
+ memset(warrior, 0, sizeof(struct warrior));
+
+ warrior->dev.evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
+ warrior->dev.keybit[LONG(BTN_TRIGGER)] = BIT(BTN_TRIGGER) | BIT(BTN_THUMB) | BIT(BTN_TOP) | BIT(BTN_TOP2);
+ warrior->dev.relbit[0] = BIT(REL_DIAL);
+ warrior->dev.absbit[0] = BIT(ABS_X) | BIT(ABS_Y) | BIT(ABS_THROTTLE) | BIT(ABS_HAT0X) | BIT(ABS_HAT0Y);
+
+ warrior->dev.name = warrior_name;
+ warrior->dev.idbus = BUS_RS232;
+ warrior->dev.idvendor = SERIO_WARRIOR;
+ warrior->dev.idproduct = 0x0001;
+ warrior->dev.idversion = 0x0100;
+
+ for (i = 0; i < 2; i++) {
+ warrior->dev.absmax[ABS_X+i] = -64;
+ warrior->dev.absmin[ABS_X+i] = 64;
+ warrior->dev.absflat[ABS_X+i] = 8;
+ }
+
+ warrior->dev.absmax[ABS_THROTTLE] = -112;
+ warrior->dev.absmin[ABS_THROTTLE] = 112;
+
+ for (i = 0; i < 2; i++) {
+ warrior->dev.absmax[ABS_HAT0X+i] = -1;
+ warrior->dev.absmin[ABS_HAT0X+i] = 1;
+ }
+
+ warrior->dev.private = warrior;
+
+ serio->private = warrior;
+
+ if (serio_open(serio, dev)) {
+ kfree(warrior);
+ return;
+ }
+
+ input_register_device(&warrior->dev);
+
+ printk(KERN_INFO "input%d: Logitech WingMan Warrior on serio%d\n", warrior->dev.number, serio->number);
+}
+
+/*
+ * The serio device structure.
+ */
+
+static struct serio_dev warrior_dev = {
+ interrupt: warrior_interrupt,
+ connect: warrior_connect,
+ disconnect: warrior_disconnect,
+};
+
+/*
+ * The functions for inserting/removing us as a module.
+ */
+
+int __init warrior_init(void)
+{
+ serio_register_device(&warrior_dev);
+ return 0;
+}
+
+void __exit warrior_exit(void)
+{
+ serio_unregister_device(&warrior_dev);
+}
+
+module_init(warrior_init);
+module_exit(warrior_exit);
+
+MODULE_LICENSE("GPL");
--- /dev/null
+CONFIG_SERIO
+ Say Yes here if you have any input device that uses serial I/O to
+ communicate with the system. This includes the
+ * standard AT keyboard and PS/2 mouse *
+ as well as serial mice, Sun keyboards, some joysticks and 6dof
+ devices and more.
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called serio.o. If you want to compile it
+ as a module, say M here and read <file:Documentation/modules.txt>.
+
+CONFIG_SERIO_SERPORT
+ Say Y here if you plan to use an input device (mouse, joystick,
+ tablet, 6dof) that communicates over the RS232 serial (COM) port.
+
+ More information is available: <file:Documentation/input/input.txt>
+
+ If unsure, say Y.
+
+ This driver is also available as a module ( = code which can be
+ inserted in and removed from the running kernel whenever you want).
+ The module will be called serport.o. If you want to compile it as a
+ module, say M here and read <file:Documentation/modules.txt>.
--- /dev/null
+#
+# Input core configuration
+#
+
+tristate 'Serial i/o support' CONFIG_SERIO
+
+dep_tristate ' Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO
--- /dev/null
+#
+# Makefile for the input core drivers.
+#
+
+# The target object and module list name.
+
+O_TARGET := seriodrv.o
+
+# Objects that export symbols.
+
+export-objs := serio.o
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_SERIO) += serio.o
+obj-$(CONFIG_SERIO_SERPORT) += serport.o
+
+# The global Rules.make.
+
+include $(TOPDIR)/Rules.make
--- /dev/null
+/*
+ * $Id: serio.c,v 1.5 2000/06/04 17:44:59 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * The Serio abstraction module
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/serio.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+MODULE_LICENSE("GPL");
+
+EXPORT_SYMBOL(serio_register_port);
+EXPORT_SYMBOL(serio_unregister_port);
+EXPORT_SYMBOL(serio_register_device);
+EXPORT_SYMBOL(serio_unregister_device);
+EXPORT_SYMBOL(serio_open);
+EXPORT_SYMBOL(serio_close);
+EXPORT_SYMBOL(serio_rescan);
+
+static struct serio *serio_list;
+static struct serio_dev *serio_dev;
+static int serio_number;
+
+static void serio_find_dev(struct serio *serio)
+{
+ struct serio_dev *dev = serio_dev;
+
+ while (dev && !serio->dev) {
+ if (dev->connect)
+ dev->connect(serio, dev);
+ dev = dev->next;
+ }
+}
+
+void serio_rescan(struct serio *serio)
+{
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
+ serio_find_dev(serio);
+}
+
+void serio_register_port(struct serio *serio)
+{
+ serio->number = serio_number++;
+ serio->next = serio_list;
+ serio_list = serio;
+ serio_find_dev(serio);
+}
+
+void serio_unregister_port(struct serio *serio)
+{
+ struct serio **serioptr = &serio_list;
+
+ while (*serioptr && (*serioptr != serio)) serioptr = &((*serioptr)->next);
+ *serioptr = (*serioptr)->next;
+
+ if (serio->dev && serio->dev->disconnect)
+ serio->dev->disconnect(serio);
+
+ serio_number--;
+}
+
+void serio_register_device(struct serio_dev *dev)
+{
+ struct serio *serio = serio_list;
+
+ dev->next = serio_dev;
+ serio_dev = dev;
+
+ while (serio) {
+ if (!serio->dev && dev->connect)
+ dev->connect(serio, dev);
+ serio = serio->next;
+ }
+}
+
+void serio_unregister_device(struct serio_dev *dev)
+{
+ struct serio_dev **devptr = &serio_dev;
+ struct serio *serio = serio_list;
+
+ while (*devptr && (*devptr != dev)) devptr = &((*devptr)->next);
+ *devptr = (*devptr)->next;
+
+ while (serio) {
+ if (serio->dev == dev && dev->disconnect)
+ dev->disconnect(serio);
+ serio_find_dev(serio);
+ serio = serio->next;
+ }
+}
+
+int serio_open(struct serio *serio, struct serio_dev *dev)
+{
+ if (serio->open(serio))
+ return -1;
+ serio->dev = dev;
+ return 0;
+}
+
+void serio_close(struct serio *serio)
+{
+ serio->close(serio);
+ serio->dev = NULL;
+}
--- /dev/null
+/*
+ * $Id: serport.c,v 1.7 2001/05/25 19:00:27 jdeneux Exp $
+ *
+ * Copyright (c) 1999-2001 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
+ */
+
+/*
+ * This is a module that converts a tty line into a much simpler
+ * 'serial io port' abstraction that the input device drivers use.
+ */
+
+/*
+ * 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@ucw.cz>, or by paper mail:
+ * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
+ */
+
+#include <asm/uaccess.h>
+#include <linux/kernel.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/serio.h>
+#include <linux/tty.h>
+
+struct serport {
+ struct tty_struct *tty;
+ wait_queue_head_t wait;
+ struct serio serio;
+};
+
+/*
+ * Callback functions from the serio code.
+ */
+
+static int serport_serio_write(struct serio *serio, unsigned char data)
+{
+ struct serport *serport = serio->driver;
+ return -(serport->tty->driver.write(serport->tty, 0, &data, 1) != 1);
+}
+
+static int serport_serio_open(struct serio *serio)
+{
+ return 0;
+}
+
+static void serport_serio_close(struct serio *serio)
+{
+ struct serport *serport = serio->driver;
+ wake_up_interruptible(&serport->wait);
+}
+
+/*
+ * serport_ldisc_open() is the routine that is called upon setting our line
+ * discipline on a tty. It looks for the Mag, and if found, registers
+ * it as a joystick device.
+ */
+
+static int serport_ldisc_open(struct tty_struct *tty)
+{
+ struct serport *serport;
+
+ MOD_INC_USE_COUNT;
+
+ if (!(serport = kmalloc(sizeof(struct serport), GFP_KERNEL))) {
+ MOD_DEC_USE_COUNT;
+ return -ENOMEM;
+ }
+
+ memset(serport, 0, sizeof(struct serport));
+
+ serport->tty = tty;
+ tty->disc_data = serport;
+
+ serport->serio.type = SERIO_RS232;
+ serport->serio.write = serport_serio_write;
+ serport->serio.open = serport_serio_open;
+ serport->serio.close = serport_serio_close;
+ serport->serio.driver = serport;
+
+ init_waitqueue_head(&serport->wait);
+
+ return 0;
+}
+
+/*
+ * serport_ldisc_close() is the opposite of serport_ldisc_open()
+ */
+
+static void serport_ldisc_close(struct tty_struct *tty)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ kfree(serport);
+ MOD_DEC_USE_COUNT;
+}
+
+/*
+ * serport_ldisc_receive() is called by the low level tty driver when characters
+ * are ready for us. We forward the characters, one by one to the 'interrupt'
+ * routine.
+ */
+
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ int i;
+ for (i = 0; i < count; i++)
+ if (serport->serio.dev)
+ serport->serio.dev->interrupt(&serport->serio, cp[i], 0);
+}
+
+/*
+ * serport_ldisc_room() reports how much room we do have for receiving data.
+ * Although we in fact have infinite room, we need to specify some value
+ * here, and 256 seems to be reasonable.
+ */
+
+static int serport_ldisc_room(struct tty_struct *tty)
+{
+ return 256;
+}
+
+/*
+ * serport_ldisc_read() just waits indefinitely if everything goes well.
+ * However, when the serio driver closes the serio port, it finishes,
+ * returning 0 characters.
+ */
+
+static ssize_t serport_ldisc_read(struct tty_struct * tty, struct file * file, unsigned char * buf, size_t nr)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+ DECLARE_WAITQUEUE(wait, current);
+ char name[32];
+
+#ifdef CONFIG_DEVFS_FS
+ sprintf(name, tty->driver.name, minor(tty->device) - tty->driver.minor_start);
+#else
+ sprintf(name, "%s%d", tty->driver.name, minor(tty->device) - tty->driver.minor_start);
+#endif
+
+ serio_register_port(&serport->serio);
+
+ printk(KERN_INFO "serio%d: Serial port %s\n", serport->serio.number, name);
+
+ add_wait_queue(&serport->wait, &wait);
+ current->state = TASK_INTERRUPTIBLE;
+
+ while(serport->serio.type && !signal_pending(current)) schedule();
+
+ current->state = TASK_RUNNING;
+ remove_wait_queue(&serport->wait, &wait);
+
+ serio_unregister_port(&serport->serio);
+
+ return 0;
+}
+
+/*
+ * serport_ldisc_ioctl() allows to set the port protocol, and device ID
+ */
+
+static int serport_ldisc_ioctl(struct tty_struct * tty, struct file * file, unsigned int cmd, unsigned long arg)
+{
+ struct serport *serport = (struct serport*) tty->disc_data;
+
+ switch (cmd) {
+ case SPIOCSTYPE:
+ return get_user(serport->serio.type, (unsigned long *) arg);
+ }
+
+ return -EINVAL;
+}
+
+/*
+ * The line discipline structure.
+ */
+
+static struct tty_ldisc serport_ldisc = {
+ name: "input",
+ open: serport_ldisc_open,
+ close: serport_ldisc_close,
+ read: serport_ldisc_read,
+ ioctl: serport_ldisc_ioctl,
+ receive_buf: serport_ldisc_receive,
+ receive_room: serport_ldisc_room,
+};
+
+/*
+ * The functions for insering/removing us as a module.
+ */
+
+int __init serport_init(void)
+{
+ if (tty_register_ldisc(N_MOUSE, &serport_ldisc)) {
+ printk(KERN_ERR "serport.c: Error registering line discipline.\n");
+ return -ENODEV;
+ }
+
+ return 0;
+}
+
+void __exit serport_exit(void)
+{
+ tty_register_ldisc(N_MOUSE, NULL);
+}
+
+module_init(serport_init);
+module_exit(serport_exit);
+
+MODULE_LICENSE("GPL");
dep_mbool ' Creative SBLive! MIDI' CONFIG_MIDI_EMU10K1 $CONFIG_SOUND_EMU10K1 $CONFIG_EXPERIMENTAL
dep_tristate ' Crystal SoundFusion (CS4280/461x)' CONFIG_SOUND_FUSION $CONFIG_SOUND
dep_tristate ' Crystal Sound CS4281' CONFIG_SOUND_CS4281 $CONFIG_SOUND
-dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI
-dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI
-dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND
+dep_tristate ' Ensoniq AudioPCI (ES1370)' CONFIG_SOUND_ES1370 $CONFIG_SOUND $CONFIG_PCI $CONFIG_SOUND_GAMEPORT
+dep_tristate ' Creative Ensoniq AudioPCI 97 (ES1371)' CONFIG_SOUND_ES1371 $CONFIG_SOUND $CONFIG_PCI $CONFIG_SOUND_GAMEPORT
+dep_tristate ' ESS Technology Solo1' CONFIG_SOUND_ESSSOLO1 $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
dep_tristate ' ESS Maestro, Maestro2, Maestro2E driver' CONFIG_SOUND_MAESTRO $CONFIG_SOUND
dep_tristate ' ESS Maestro3/Allegro driver (EXPERIMENTAL)' CONFIG_SOUND_MAESTRO3 $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
dep_tristate ' Intel ICH (i8xx) audio support' CONFIG_SOUND_ICH $CONFIG_PCI
dep_tristate ' RME Hammerfall (RME96XX) support' CONFIG_SOUND_RME96XX $CONFIG_SOUND $CONFIG_PCI $CONFIG_EXPERIMENTAL
-dep_tristate ' S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND
+dep_tristate ' S3 SonicVibes' CONFIG_SOUND_SONICVIBES $CONFIG_SOUND $CONFIG_SOUND_GAMEPORT
if [ "$CONFIG_VISWS" = "y" ]; then
dep_tristate ' SGI Visual Workstation Sound' CONFIG_SOUND_VWSND $CONFIG_SOUND
fi
void gameport_close(struct gameport *gameport);
void gameport_rescan(struct gameport *gameport);
-#if defined(CONFIG_INPUT_GAMEPORT) || defined(CONFIG_INPUT_GAMEPORT_MODULE)
+#if defined(CONFIG_GAMEPORT) || defined(CONFIG_GAMEPORT_MODULE)
void gameport_register_port(struct gameport *gameport);
void gameport_unregister_port(struct gameport *gameport);
#else