]> git.hungrycats.org Git - linux/commitdiff
The patch moves:
authorVojtech Pavlik <vojtech@suse.cz>
Tue, 5 Feb 2002 10:03:32 +0000 (02:03 -0800)
committerVojtech Pavlik <vojtech@suse.cz>
Tue, 5 Feb 2002 10:03:32 +0000 (02:03 -0800)
* joystick drivers from drivers/char/joystick to drivers/input/joystick
* gameport drivers from drivers/char/joystick to drivers/input/gameport
* serio drivers from drivers/char/joystick to drivers/input/serio

I don't think the joystick drivers should stay in char, because they're
NOT character device drivers (check for register_chrdev, none to be found).

It also fixes build problems with sound driver gameport support.

75 files changed:
Makefile
drivers/Makefile
drivers/char/Config.in
drivers/char/Makefile
drivers/char/joystick/Config.help [deleted file]
drivers/char/joystick/Config.in [deleted file]
drivers/char/joystick/Makefile [deleted file]
drivers/char/joystick/a3d.c [deleted file]
drivers/char/joystick/adi.c [deleted file]
drivers/char/joystick/amijoy.c [deleted file]
drivers/char/joystick/analog.c [deleted file]
drivers/char/joystick/cobra.c [deleted file]
drivers/char/joystick/cs461x.c [deleted file]
drivers/char/joystick/db9.c [deleted file]
drivers/char/joystick/emu10k1-gp.c [deleted file]
drivers/char/joystick/gamecon.c [deleted file]
drivers/char/joystick/gameport.c [deleted file]
drivers/char/joystick/gf2k.c [deleted file]
drivers/char/joystick/grip.c [deleted file]
drivers/char/joystick/iforce.c [deleted file]
drivers/char/joystick/interact.c [deleted file]
drivers/char/joystick/lightning.c [deleted file]
drivers/char/joystick/magellan.c [deleted file]
drivers/char/joystick/ns558.c [deleted file]
drivers/char/joystick/pcigame.c [deleted file]
drivers/char/joystick/serio.c [deleted file]
drivers/char/joystick/serport.c [deleted file]
drivers/char/joystick/sidewinder.c [deleted file]
drivers/char/joystick/spaceball.c [deleted file]
drivers/char/joystick/spaceorb.c [deleted file]
drivers/char/joystick/stinger.c [deleted file]
drivers/char/joystick/tmdc.c [deleted file]
drivers/char/joystick/turbografx.c [deleted file]
drivers/char/joystick/warrior.c [deleted file]
drivers/input/Config.help
drivers/input/Config.in
drivers/input/Makefile
drivers/input/gameport/Config.help [new file with mode: 0644]
drivers/input/gameport/Config.in [new file with mode: 0644]
drivers/input/gameport/Makefile [new file with mode: 0644]
drivers/input/gameport/cs461x.c [new file with mode: 0644]
drivers/input/gameport/emu10k1-gp.c [new file with mode: 0644]
drivers/input/gameport/gameport.c [new file with mode: 0644]
drivers/input/gameport/lightning.c [new file with mode: 0644]
drivers/input/gameport/ns558.c [new file with mode: 0644]
drivers/input/gameport/pcigame.c [new file with mode: 0644]
drivers/input/joystick/Config.help [new file with mode: 0644]
drivers/input/joystick/Config.in [new file with mode: 0644]
drivers/input/joystick/Makefile [new file with mode: 0644]
drivers/input/joystick/a3d.c [new file with mode: 0644]
drivers/input/joystick/adi.c [new file with mode: 0644]
drivers/input/joystick/amijoy.c [new file with mode: 0644]
drivers/input/joystick/analog.c [new file with mode: 0644]
drivers/input/joystick/cobra.c [new file with mode: 0644]
drivers/input/joystick/db9.c [new file with mode: 0644]
drivers/input/joystick/gamecon.c [new file with mode: 0644]
drivers/input/joystick/gf2k.c [new file with mode: 0644]
drivers/input/joystick/grip.c [new file with mode: 0644]
drivers/input/joystick/iforce.c [new file with mode: 0644]
drivers/input/joystick/interact.c [new file with mode: 0644]
drivers/input/joystick/magellan.c [new file with mode: 0644]
drivers/input/joystick/sidewinder.c [new file with mode: 0644]
drivers/input/joystick/spaceball.c [new file with mode: 0644]
drivers/input/joystick/spaceorb.c [new file with mode: 0644]
drivers/input/joystick/stinger.c [new file with mode: 0644]
drivers/input/joystick/tmdc.c [new file with mode: 0644]
drivers/input/joystick/turbografx.c [new file with mode: 0644]
drivers/input/joystick/warrior.c [new file with mode: 0644]
drivers/input/serio/Config.help [new file with mode: 0644]
drivers/input/serio/Config.in [new file with mode: 0644]
drivers/input/serio/Makefile [new file with mode: 0644]
drivers/input/serio/serio.c [new file with mode: 0644]
drivers/input/serio/serport.c [new file with mode: 0644]
drivers/sound/Config.in
include/linux/gameport.h

index 7c729498936fbd183b88b4eb272c5d9bfc0f0c84..7f6f23048b900fb0c5b82301b9e4db5b3bfd80eb 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -178,6 +178,8 @@ DRIVERS-$(CONFIG_HAMRADIO) += drivers/net/hamradio/hamradio.o
 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
index 4d2f078d6475e43fd5570734df155ee6e4492a46..aa1e43f643bf8dfe907659a23c3478b2579ac4d9 100644 (file)
@@ -8,7 +8,7 @@
 
 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)
@@ -27,6 +27,8 @@ subdir-$(CONFIG_MAC)          += macintosh
 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
index eed80ec1ad8c02031c22d9f9f985d79a55795174..6358b6aa81995ff23009dae407d041c969512c8b 100644 (file)
@@ -127,8 +127,6 @@ if [ "$CONFIG_MOUSE" != "n" ]; then
 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
index ddffec9a0282fae5134a4317b71e38b9c3a0d6a4..cae9ed93433ca190de506015d3ae5a33c2eed972 100644 (file)
@@ -25,7 +25,7 @@ export-objs     :=    busmouse.o console.o keyboard.o sysrq.o \
                        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     :=      
 
@@ -166,16 +166,11 @@ obj-$(CONFIG_BVME6000_SCC) += generic_serial.o vme_scc.o
 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
diff --git a/drivers/char/joystick/Config.help b/drivers/char/joystick/Config.help
deleted file mode 100644 (file)
index 58d7110..0000000
+++ /dev/null
@@ -1,300 +0,0 @@
-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>.
-
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
deleted file mode 100644 (file)
index 7e4185b..0000000
+++ /dev/null
@@ -1,53 +0,0 @@
-#
-# 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
diff --git a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile
deleted file mode 100644 (file)
index 4d018b1..0000000
+++ /dev/null
@@ -1,70 +0,0 @@
-#
-# 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
diff --git a/drivers/char/joystick/a3d.c b/drivers/char/joystick/a3d.c
deleted file mode 100644 (file)
index a560ccf..0000000
+++ /dev/null
@@ -1,388 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/adi.c b/drivers/char/joystick/adi.c
deleted file mode 100644 (file)
index 777d4b9..0000000
+++ /dev/null
@@ -1,557 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/amijoy.c b/drivers/char/joystick/amijoy.c
deleted file mode 100644 (file)
index 6134e1f..0000000
+++ /dev/null
@@ -1,161 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/analog.c b/drivers/char/joystick/analog.c
deleted file mode 100644 (file)
index b45127e..0000000
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/cobra.c b/drivers/char/joystick/cobra.c
deleted file mode 100644 (file)
index 5356160..0000000
+++ /dev/null
@@ -1,252 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/cs461x.c b/drivers/char/joystick/cs461x.c
deleted file mode 100644 (file)
index 7116b34..0000000
+++ /dev/null
@@ -1,331 +0,0 @@
-/*
-       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);
-
diff --git a/drivers/char/joystick/db9.c b/drivers/char/joystick/db9.c
deleted file mode 100644 (file)
index 2244a9a..0000000
+++ /dev/null
@@ -1,424 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/emu10k1-gp.c b/drivers/char/joystick/emu10k1-gp.c
deleted file mode 100644 (file)
index 2489b11..0000000
+++ /dev/null
@@ -1,125 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/gamecon.c b/drivers/char/joystick/gamecon.c
deleted file mode 100644 (file)
index e7b4a79..0000000
+++ /dev/null
@@ -1,670 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/gameport.c b/drivers/char/joystick/gameport.c
deleted file mode 100644 (file)
index 5eacff4..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * $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);
-}
diff --git a/drivers/char/joystick/gf2k.c b/drivers/char/joystick/gf2k.c
deleted file mode 100644 (file)
index dbb364f..0000000
+++ /dev/null
@@ -1,361 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/grip.c b/drivers/char/joystick/grip.c
deleted file mode 100644 (file)
index bcd73ac..0000000
+++ /dev/null
@@ -1,425 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/iforce.c b/drivers/char/joystick/iforce.c
deleted file mode 100644 (file)
index d967c37..0000000
+++ /dev/null
@@ -1,1224 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/interact.c b/drivers/char/joystick/interact.c
deleted file mode 100644 (file)
index 9dec620..0000000
+++ /dev/null
@@ -1,308 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/lightning.c b/drivers/char/joystick/lightning.c
deleted file mode 100644 (file)
index 68b79ff..0000000
+++ /dev/null
@@ -1,298 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/magellan.c b/drivers/char/joystick/magellan.c
deleted file mode 100644 (file)
index e22c831..0000000
+++ /dev/null
@@ -1,212 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c
deleted file mode 100644 (file)
index 4cefeab..0000000
+++ /dev/null
@@ -1,285 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c
deleted file mode 100644 (file)
index 04e1bee..0000000
+++ /dev/null
@@ -1,199 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/serio.c b/drivers/char/joystick/serio.c
deleted file mode 100644 (file)
index 98111da..0000000
+++ /dev/null
@@ -1,133 +0,0 @@
-/*
- * $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;
-}
diff --git a/drivers/char/joystick/serport.c b/drivers/char/joystick/serport.c
deleted file mode 100644 (file)
index efe94e6..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c
deleted file mode 100644 (file)
index 29fa6f7..0000000
+++ /dev/null
@@ -1,761 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/spaceball.c b/drivers/char/joystick/spaceball.c
deleted file mode 100644 (file)
index d7614d5..0000000
+++ /dev/null
@@ -1,238 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/spaceorb.c b/drivers/char/joystick/spaceorb.c
deleted file mode 100644 (file)
index 0ec9c72..0000000
+++ /dev/null
@@ -1,227 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/stinger.c b/drivers/char/joystick/stinger.c
deleted file mode 100644 (file)
index f520fc3..0000000
+++ /dev/null
@@ -1,202 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/tmdc.c b/drivers/char/joystick/tmdc.c
deleted file mode 100644 (file)
index 85d2e69..0000000
+++ /dev/null
@@ -1,378 +0,0 @@
-/*
- * $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");
diff --git a/drivers/char/joystick/turbografx.c b/drivers/char/joystick/turbografx.c
deleted file mode 100644 (file)
index 3e8431c..0000000
+++ /dev/null
@@ -1,259 +0,0 @@
-/*
- * $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);
diff --git a/drivers/char/joystick/warrior.c b/drivers/char/joystick/warrior.c
deleted file mode 100644 (file)
index 2acfed2..0000000
+++ /dev/null
@@ -1,214 +0,0 @@
-/*
- * $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");
index 981eb6f0ffce09a49332d5a52a6a16716dc3543c..15bc1aab59bdea0298327c97d263a93888d735cb 100644 (file)
@@ -1,27 +1,35 @@
 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.
@@ -44,16 +52,23 @@ CONFIG_INPUT_MOUSEDEV_SCREEN_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>.
index fb9eceff2c474f451d6bc5b5daeeadb6b28448d9..66b2aa72897eb8490a976776596fa7f81a3a0573 100644 (file)
@@ -1,18 +1,25 @@
 #
-# 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
index 4e60129dca0bdfc75cb8272ebe7fe405558d37f2..69d9bc3794ea8e6bbb66ad06f6d143d128b643d2 100644 (file)
@@ -8,15 +8,9 @@ O_TARGET       := inputdrv.o
 
 # 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
@@ -25,6 +19,12 @@ obj-$(CONFIG_INPUT_MOUSEDEV) += mousedev.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
diff --git a/drivers/input/gameport/Config.help b/drivers/input/gameport/Config.help
new file mode 100644 (file)
index 0000000..54cac24
--- /dev/null
@@ -0,0 +1,62 @@
+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>.
diff --git a/drivers/input/gameport/Config.in b/drivers/input/gameport/Config.in
new file mode 100644 (file)
index 0000000..df89f6a
--- /dev/null
@@ -0,0 +1,19 @@
+#
+# 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
diff --git a/drivers/input/gameport/Makefile b/drivers/input/gameport/Makefile
new file mode 100644 (file)
index 0000000..a15bcbb
--- /dev/null
@@ -0,0 +1,24 @@
+#
+# 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
diff --git a/drivers/input/gameport/cs461x.c b/drivers/input/gameport/cs461x.c
new file mode 100644 (file)
index 0000000..7116b34
--- /dev/null
@@ -0,0 +1,331 @@
+/*
+       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);
+
diff --git a/drivers/input/gameport/emu10k1-gp.c b/drivers/input/gameport/emu10k1-gp.c
new file mode 100644 (file)
index 0000000..2489b11
--- /dev/null
@@ -0,0 +1,125 @@
+/*
+ * $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);
diff --git a/drivers/input/gameport/gameport.c b/drivers/input/gameport/gameport.c
new file mode 100644 (file)
index 0000000..5eacff4
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * $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);
+}
diff --git a/drivers/input/gameport/lightning.c b/drivers/input/gameport/lightning.c
new file mode 100644 (file)
index 0000000..68b79ff
--- /dev/null
@@ -0,0 +1,298 @@
+/*
+ * $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);
diff --git a/drivers/input/gameport/ns558.c b/drivers/input/gameport/ns558.c
new file mode 100644 (file)
index 0000000..4cefeab
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * $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);
diff --git a/drivers/input/gameport/pcigame.c b/drivers/input/gameport/pcigame.c
new file mode 100644 (file)
index 0000000..04e1bee
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/Config.help b/drivers/input/joystick/Config.help
new file mode 100644 (file)
index 0000000..1b4187b
--- /dev/null
@@ -0,0 +1,205 @@
+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>.
+
diff --git a/drivers/input/joystick/Config.in b/drivers/input/joystick/Config.in
new file mode 100644 (file)
index 0000000..afd07b8
--- /dev/null
@@ -0,0 +1,31 @@
+#
+# 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
diff --git a/drivers/input/joystick/Makefile b/drivers/input/joystick/Makefile
new file mode 100644 (file)
index 0000000..8b2cdd2
--- /dev/null
@@ -0,0 +1,51 @@
+#
+# 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
diff --git a/drivers/input/joystick/a3d.c b/drivers/input/joystick/a3d.c
new file mode 100644 (file)
index 0000000..a560ccf
--- /dev/null
@@ -0,0 +1,388 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/adi.c b/drivers/input/joystick/adi.c
new file mode 100644 (file)
index 0000000..777d4b9
--- /dev/null
@@ -0,0 +1,557 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/amijoy.c b/drivers/input/joystick/amijoy.c
new file mode 100644 (file)
index 0000000..6134e1f
--- /dev/null
@@ -0,0 +1,161 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/analog.c b/drivers/input/joystick/analog.c
new file mode 100644 (file)
index 0000000..b45127e
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/cobra.c b/drivers/input/joystick/cobra.c
new file mode 100644 (file)
index 0000000..5356160
--- /dev/null
@@ -0,0 +1,252 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/db9.c b/drivers/input/joystick/db9.c
new file mode 100644 (file)
index 0000000..2244a9a
--- /dev/null
@@ -0,0 +1,424 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/gamecon.c b/drivers/input/joystick/gamecon.c
new file mode 100644 (file)
index 0000000..e7b4a79
--- /dev/null
@@ -0,0 +1,670 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/gf2k.c b/drivers/input/joystick/gf2k.c
new file mode 100644 (file)
index 0000000..dbb364f
--- /dev/null
@@ -0,0 +1,361 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/grip.c b/drivers/input/joystick/grip.c
new file mode 100644 (file)
index 0000000..bcd73ac
--- /dev/null
@@ -0,0 +1,425 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/iforce.c b/drivers/input/joystick/iforce.c
new file mode 100644 (file)
index 0000000..bc9569f
--- /dev/null
@@ -0,0 +1,1224 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/interact.c b/drivers/input/joystick/interact.c
new file mode 100644 (file)
index 0000000..9dec620
--- /dev/null
@@ -0,0 +1,308 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/magellan.c b/drivers/input/joystick/magellan.c
new file mode 100644 (file)
index 0000000..e22c831
--- /dev/null
@@ -0,0 +1,212 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/sidewinder.c b/drivers/input/joystick/sidewinder.c
new file mode 100644 (file)
index 0000000..29fa6f7
--- /dev/null
@@ -0,0 +1,761 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/spaceball.c b/drivers/input/joystick/spaceball.c
new file mode 100644 (file)
index 0000000..d7614d5
--- /dev/null
@@ -0,0 +1,238 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/spaceorb.c b/drivers/input/joystick/spaceorb.c
new file mode 100644 (file)
index 0000000..0ec9c72
--- /dev/null
@@ -0,0 +1,227 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/stinger.c b/drivers/input/joystick/stinger.c
new file mode 100644 (file)
index 0000000..f520fc3
--- /dev/null
@@ -0,0 +1,202 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/tmdc.c b/drivers/input/joystick/tmdc.c
new file mode 100644 (file)
index 0000000..85d2e69
--- /dev/null
@@ -0,0 +1,378 @@
+/*
+ * $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");
diff --git a/drivers/input/joystick/turbografx.c b/drivers/input/joystick/turbografx.c
new file mode 100644 (file)
index 0000000..3e8431c
--- /dev/null
@@ -0,0 +1,259 @@
+/*
+ * $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);
diff --git a/drivers/input/joystick/warrior.c b/drivers/input/joystick/warrior.c
new file mode 100644 (file)
index 0000000..2acfed2
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * $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");
diff --git a/drivers/input/serio/Config.help b/drivers/input/serio/Config.help
new file mode 100644 (file)
index 0000000..a827854
--- /dev/null
@@ -0,0 +1,26 @@
+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>.
diff --git a/drivers/input/serio/Config.in b/drivers/input/serio/Config.in
new file mode 100644 (file)
index 0000000..cc566ad
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Input core configuration
+#
+
+tristate 'Serial i/o support' CONFIG_SERIO
+
+dep_tristate '  Serial port line discipline' CONFIG_SERIO_SERPORT $CONFIG_SERIO 
diff --git a/drivers/input/serio/Makefile b/drivers/input/serio/Makefile
new file mode 100644 (file)
index 0000000..9287af0
--- /dev/null
@@ -0,0 +1,20 @@
+#
+# 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
diff --git a/drivers/input/serio/serio.c b/drivers/input/serio/serio.c
new file mode 100644 (file)
index 0000000..98111da
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * $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;
+}
diff --git a/drivers/input/serio/serport.c b/drivers/input/serio/serport.c
new file mode 100644 (file)
index 0000000..efe94e6
--- /dev/null
@@ -0,0 +1,226 @@
+/*
+ * $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");
index f521741825b80523ad42da83e6344d0baf1e8367..aa65d567ebdcf6d102f22a7194064042a492f658 100644 (file)
@@ -34,14 +34,14 @@ dep_tristate '  Creative SBLive! (EMU10K1)' CONFIG_SOUND_EMU10K1 $CONFIG_SOUND $
 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
index 37b72807182b2baab3cf65f1686b3aaed8ab18b7..5e741a18c004aecf326f6a1e24889453501cd17d 100644 (file)
@@ -70,7 +70,7 @@ int gameport_open(struct gameport *gameport, struct gameport_dev *dev, int mode)
 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