summaryrefslogtreecommitdiffstats
path: root/drivers/char
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/char')
-rw-r--r--drivers/char/applicom.c1
-rw-r--r--drivers/char/dsp56k.c4
-rw-r--r--drivers/char/dtlk.c4
-rw-r--r--drivers/char/ftape/zftape/zftape-init.c24
-rw-r--r--drivers/char/i2c-old.c8
-rw-r--r--drivers/char/ip2main.c12
-rw-r--r--drivers/char/istallion.c2
-rw-r--r--drivers/char/joystick/Config.in64
-rw-r--r--drivers/char/joystick/Makefile217
-rw-r--r--drivers/char/joystick/a3d.c387
-rw-r--r--drivers/char/joystick/adi.c554
-rw-r--r--drivers/char/joystick/amijoy.c149
-rw-r--r--drivers/char/joystick/analog.c758
-rw-r--r--drivers/char/joystick/cobra.c250
-rw-r--r--drivers/char/joystick/db9.c423
-rw-r--r--drivers/char/joystick/gamecon.c668
-rw-r--r--drivers/char/joystick/gameport.c198
-rw-r--r--drivers/char/joystick/gf2k.c359
-rw-r--r--drivers/char/joystick/grip.c423
-rw-r--r--drivers/char/joystick/interact.c306
-rw-r--r--drivers/char/joystick/joy-amiga.c143
-rw-r--r--drivers/char/joystick/joy-analog.c295
-rw-r--r--drivers/char/joystick/joy-analog.h287
-rw-r--r--drivers/char/joystick/joy-assassin.c396
-rw-r--r--drivers/char/joystick/joy-console.c811
-rw-r--r--drivers/char/joystick/joy-creative.c267
-rw-r--r--drivers/char/joystick/joy-db9.c421
-rw-r--r--drivers/char/joystick/joy-gravis.c383
-rw-r--r--drivers/char/joystick/joy-lightning.c351
-rw-r--r--drivers/char/joystick/joy-logitech.c534
-rw-r--r--drivers/char/joystick/joy-magellan.c395
-rw-r--r--drivers/char/joystick/joy-pci.c254
-rw-r--r--drivers/char/joystick/joy-sidewinder.c835
-rw-r--r--drivers/char/joystick/joy-spaceball.c343
-rw-r--r--drivers/char/joystick/joy-spaceorb.c301
-rw-r--r--drivers/char/joystick/joy-thrustmaster.c280
-rw-r--r--drivers/char/joystick/joy-turbografx.c267
-rw-r--r--drivers/char/joystick/joy-warrior.c301
-rw-r--r--drivers/char/joystick/joystick.c864
-rw-r--r--drivers/char/joystick/lightning.c300
-rw-r--r--drivers/char/joystick/magellan.c210
-rw-r--r--drivers/char/joystick/ns558.c366
-rw-r--r--drivers/char/joystick/pcigame.c198
-rw-r--r--drivers/char/joystick/serio.c132
-rw-r--r--drivers/char/joystick/serport.c220
-rw-r--r--drivers/char/joystick/sidewinder.c756
-rw-r--r--drivers/char/joystick/spaceball.c231
-rw-r--r--drivers/char/joystick/spaceorb.c225
-rw-r--r--drivers/char/joystick/tmdc.c348
-rw-r--r--drivers/char/joystick/turbografx.c258
-rw-r--r--drivers/char/joystick/warrior.c212
-rw-r--r--drivers/char/lp.c4
-rw-r--r--drivers/char/mem.c12
-rw-r--r--drivers/char/misc.c4
-rw-r--r--drivers/char/ppdev.c2
-rw-r--r--drivers/char/stallion.c2
-rw-r--r--drivers/char/tpqic02.c32
-rw-r--r--drivers/char/tty_io.c13
-rw-r--r--drivers/char/vc_screen.c16
-rw-r--r--drivers/char/videodev.c19
60 files changed, 8119 insertions, 7980 deletions
diff --git a/drivers/char/applicom.c b/drivers/char/applicom.c
index 3fc7005ed..d5091ff4d 100644
--- a/drivers/char/applicom.c
+++ b/drivers/char/applicom.c
@@ -226,7 +226,6 @@ int __init applicom_init(void)
continue;
}
- /* &ac_open as dev_id? David, could you pass me this joint? */
if (request_irq(dev->irq, &ac_interrupt, SA_SHIRQ, "Applicom PCI", &ac_open)) {
printk(KERN_INFO "Could not allocate IRQ %d for PCI Applicom device.\n", dev->irq);
iounmap(RamIO);
diff --git a/drivers/char/dsp56k.c b/drivers/char/dsp56k.c
index dc076dd5a..6fe41e118 100644
--- a/drivers/char/dsp56k.c
+++ b/drivers/char/dsp56k.c
@@ -519,9 +519,9 @@ int __init dsp56k_init(void)
printk("DSP56k driver: Unable to register driver\n");
return -ENODEV;
}
- devfs_handle = devfs_register (NULL, "dsp56k", 0, DEVFS_FL_NONE,
+ devfs_handle = devfs_register (NULL, "dsp56k", DEVFS_FL_DEFAULT,
DSP56K_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&dsp56k_fops, NULL);
dsp56k.in_use = 0;
diff --git a/drivers/char/dtlk.c b/drivers/char/dtlk.c
index 730b69b17..475e1d052 100644
--- a/drivers/char/dtlk.c
+++ b/drivers/char/dtlk.c
@@ -352,9 +352,9 @@ static int __init dtlk_init(void)
}
if (dtlk_dev_probe() == 0)
printk(", MAJOR %d\n", dtlk_major);
- devfs_handle = devfs_register (NULL, "dtlk", 0, DEVFS_FL_NONE,
+ devfs_handle = devfs_register (NULL, "dtlk", DEVFS_FL_DEFAULT,
dtlk_major, DTLK_MINOR,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&dtlk_fops, NULL);
init_timer(&dtlk_timer);
diff --git a/drivers/char/ftape/zftape/zftape-init.c b/drivers/char/ftape/zftape/zftape-init.c
index 883f4a106..e6cb87d1e 100644
--- a/drivers/char/ftape/zftape/zftape-init.c
+++ b/drivers/char/ftape/zftape/zftape-init.c
@@ -439,34 +439,34 @@ KERN_INFO
char devname[9];
sprintf (devname, "qft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 4,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "zqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 16,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nzqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 20,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "rawqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 32,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
sprintf (devname, "nrawqft%i", i);
- devfs_register (NULL, devname, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, devname, DEVFS_FL_DEFAULT,
QIC117_TAPE_MAJOR, i + 36,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&zft_cdev, NULL);
}
diff --git a/drivers/char/i2c-old.c b/drivers/char/i2c-old.c
index b509c9a18..bd9750fc3 100644
--- a/drivers/char/i2c-old.c
+++ b/drivers/char/i2c-old.c
@@ -37,8 +37,8 @@ static struct i2c_driver *drivers[I2C_DRIVER_MAX];
static int bus_count = 0, driver_count = 0;
#ifdef CONFIG_VIDEO_BT848
-extern int tuner_init_module(void);
-extern int msp3400_init_module(void);
+extern int i2c_tuner_init(void);
+extern int msp3400c_init(void);
#endif
#ifdef CONFIG_VIDEO_BUZ
extern int saa7111_init(void);
@@ -55,8 +55,8 @@ int i2c_init(void)
scan ? " (i2c bus scan enabled)" : "");
/* anything to do here ? */
#ifdef CONFIG_VIDEO_BT848
- tuner_init_module();
- msp3400_init_module();
+ i2c_tuner_init();
+ msp3400c_init();
#endif
#ifdef CONFIG_VIDEO_BUZ
saa7111_init();
diff --git a/drivers/char/ip2main.c b/drivers/char/ip2main.c
index 033eb9aaf..a645832c4 100644
--- a/drivers/char/ip2main.c
+++ b/drivers/char/ip2main.c
@@ -877,19 +877,19 @@ old_ip2_init(void)
#ifdef CONFIG_DEVFS_FS
sprintf( name, "ipl%d", i );
i2BoardPtrTable[i]->devfs_ipl_handle =
- devfs_register (devfs_handle, name, 0,
- DEVFS_FL_NONE,
+ devfs_register (devfs_handle, name,
+ DEVFS_FL_DEFAULT,
IP2_IPL_MAJOR, 4 * i,
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- 0, 0, &ip2_ipl, NULL);
+ &ip2_ipl, NULL);
sprintf( name, "stat%d", i );
i2BoardPtrTable[i]->devfs_stat_handle =
- devfs_register (devfs_handle, name, 0,
- DEVFS_FL_NONE,
+ devfs_register (devfs_handle, name,
+ DEVFS_FL_DEFAULT,
IP2_IPL_MAJOR, 4 * i + 1,
S_IRUSR | S_IWUSR | S_IRGRP | S_IFCHR,
- 0, 0, &ip2_ipl, NULL);
+ &ip2_ipl, NULL);
for ( box = 0; box < ABS_MAX_BOXES; ++box )
{
diff --git a/drivers/char/istallion.c b/drivers/char/istallion.c
index 8d16c9daf..81421c032 100644
--- a/drivers/char/istallion.c
+++ b/drivers/char/istallion.c
@@ -5310,7 +5310,7 @@ int __init stli_init(void)
devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&stli_fsiomem, NULL);
/*
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
index 3e371744e..1547e5f38 100644
--- a/drivers/char/joystick/Config.in
+++ b/drivers/char/joystick/Config.in
@@ -1,34 +1,56 @@
#
-# Joystick driver
+# Joystick driver configuration
#
mainmenu_option next_comment
comment 'Joysticks'
tristate 'Joystick support' CONFIG_JOYSTICK
-
if [ "$CONFIG_JOYSTICK" != "n" ]; then
- dep_tristate ' Classic PC analog' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
- dep_tristate ' FPGaming and MadCatz A3D' CONFIG_JOY_ASSASSIN $CONFIG_JOYSTICK
- dep_tristate ' Gravis GrIP' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
- dep_tristate ' Logitech ADI' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
- dep_tristate ' Microsoft SideWinder' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
- dep_tristate ' ThrustMaster DirectConnect' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
- dep_tristate ' Creative Labs Blaster' CONFIG_JOY_CREATIVE $CONFIG_JOYSTICK
- dep_tristate ' PDPI Lightning 4 card' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
- dep_tristate ' Trident 4DWave and Aureal Vortex gameport' CONFIG_JOY_PCI $CONFIG_JOYSTICK
- dep_tristate ' Magellan and Space Mouse' CONFIG_JOY_MAGELLAN $CONFIG_JOYSTICK
- dep_tristate ' SpaceTec SpaceOrb 360 and SpaceBall Avenger' CONFIG_JOY_SPACEORB $CONFIG_JOYSTICK
- dep_tristate ' SpaceTec SpaceBall 4000 FLX' CONFIG_JOY_SPACEBALL $CONFIG_JOYSTICK
- dep_tristate ' Logitech WingMan Warrior' CONFIG_JOY_WARRIOR $CONFIG_JOYSTICK
+
+ define_tristate CONFIG_USB $CONFIG_JOYSTICK
+ define_tristate CONFIG_INPUT_JOYDEV $CONFIG_JOYSTICK
+
+ comment 'Game port support'
+ dep_tristate ' ns558 gameports' CONFIG_INPUT_NS558 $CONFIG_JOYSTICK
+ dep_tristate ' PDPI Lightning 4 gamecard' CONFIG_INPUT_LIGHTNING $CONFIG_JOYSTICK
+ dep_tristate ' Aureal Vortex and Trident 4DWave gameports' CONFIG_INPUT_PCIGAME $CONFIG_JOYSTICK
+
+ comment 'Gameport joysticks'
+ dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_INPUT_ANALOG $CONFIG_JOYSTICK
+ dep_tristate ' Assasin 3D and MadCatz Panther devices' CONFIG_INPUT_A3D $CONFIG_JOYSTICK
+ dep_tristate ' Logitech ADI digital joysticks and gamepads' CONFIG_INPUT_ADI $CONFIG_JOYSTICK
+ dep_tristate ' Creative Labs Blaster Cobra gamepad' CONFIG_INPUT_COBRA $CONFIG_JOYSTICK
+ dep_tristate ' Genius Flight2000 Digital joysticks and gamepads' CONFIG_INPUT_GF2K $CONFIG_JOYSTICK
+ dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_INPUT_GRIP $CONFIG_JOYSTICK
+ dep_tristate ' InterAct digital joysticks and gamepads' CONFIG_INPUT_INTERACT $CONFIG_JOYSTICK
+ dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_INPUT_TMDC $CONFIG_JOYSTICK
+ dep_tristate ' Microsoft SideWinder digital joysticks and gamepads' CONFIG_INPUT_SIDEWINDER $CONFIG_JOYSTICK
+
+ comment 'Serial port support'
+ dep_tristate ' Serial port input line discipline' CONFIG_INPUT_SERPORT $CONFIG_JOYSTICK
+
+ comment 'Serial port joysticks'
+ dep_tristate ' Logitech WingMan Warrior joystick' CONFIG_INPUT_WARRIOR $CONFIG_JOYSTICK
+ dep_tristate ' LogiCad3d Magellan/SpaceMouse 6dof controller' CONFIG_INPUT_MAGELLAN $CONFIG_JOYSTICK
+ dep_tristate ' SpaceTec SpaceOrb/Avenger 6dof controller' CONFIG_INPUT_SPACEORB $CONFIG_JOYSTICK
+ dep_tristate ' SpaceTec SpaceBall 4000 FLX 6dof controller' CONFIG_INPUT_SPACEBALL $CONFIG_JOYSTICK
+ dep_tristate ' I-Force joysticks/wheels' CONFIG_INPUT_IFORCE_232 $CONFIG_JOYSTICK
+ if [ "$CONFIG_INPUT_IFORCE_232" != "n" ]; then
+ define_tristate CONFIG_INPUT_IFORCE $CONFIG_INPUT_IFORCE_232
+ fi
+
if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' NES, SNES, PSX, N64, Multi' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' Sega, Multi' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' TurboGraFX interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
- fi
+ comment 'Parallel port joysticks'
+ dep_tristate ' Multisystem, Sega Genesis, Saturn joysticks and gamepads' CONFIG_INPUT_DB9 $CONFIG_JOYSTICK
+ dep_tristate ' Multisystem, NES, SNES, N64, PSX joysticks and gamepads' CONFIG_INPUT_GAMECON $CONFIG_JOYSTICK
+ dep_tristate ' Multisystem joysticks via TurboGraFX device' CONFIG_INPUT_TURBOGRAFX $CONFIG_JOYSTICK
+ fi
+
if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+ comment 'System joysticks'
+ dep_tristate ' Amiga joysticks' CONFIG_INPUT_AMIJOY $CONFIG_JOYSTICK
fi
fi
-
+
endmenu
diff --git a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile
index 2bb5870b0..2ad452618 100644
--- a/drivers/char/joystick/Makefile
+++ b/drivers/char/joystick/Makefile
@@ -2,154 +2,73 @@
# Makefile for the joystick drivers.
#
-O_TARGET := js.o
-OX_OBJS :=
-O_OBJS :=
-MX_OBJS :=
-M_OBJS :=
-
-ifeq ($(CONFIG_JOYSTICK),y)
-OX_OBJS += joystick.o
-else
- ifeq ($(CONFIG_JOYSTICK),m)
- MX_OBJS += joystick.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_AMIGA),y)
-O_OBJS += joy-amiga.o
-else
- ifeq ($(CONFIG_JOY_AMIGA),m)
- M_OBJS += joy-amiga.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_ANALOG),y)
-O_OBJS += joy-analog.o
-else
- ifeq ($(CONFIG_JOY_ANALOG),m)
- M_OBJS += joy-analog.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_ASSASSIN),y)
-O_OBJS += joy-assassin.o
-else
- ifeq ($(CONFIG_JOY_ASSASSIN),m)
- M_OBJS += joy-assassin.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_CONSOLE),y)
-O_OBJS += joy-console.o
-else
- ifeq ($(CONFIG_JOY_CONSOLE),m)
- M_OBJS += joy-console.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_CREATIVE),y)
-O_OBJS += joy-creative.o
-else
- ifeq ($(CONFIG_JOY_CREATIVE),m)
- M_OBJS += joy-creative.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_DB9),y)
-O_OBJS += joy-db9.o
-else
- ifeq ($(CONFIG_JOY_DB9),m)
- M_OBJS += joy-db9.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_GRAVIS),y)
-O_OBJS += joy-gravis.o
-else
- ifeq ($(CONFIG_JOY_GRAVIS),m)
- M_OBJS += joy-gravis.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_LIGHTNING),y)
-O_OBJS += joy-lightning.o
-else
- ifeq ($(CONFIG_JOY_LIGHTNING),m)
- M_OBJS += joy-lightning.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_LOGITECH),y)
-O_OBJS += joy-logitech.o
-else
- ifeq ($(CONFIG_JOY_LOGITECH),m)
- M_OBJS += joy-logitech.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_MAGELLAN),y)
-O_OBJS += joy-magellan.o
-else
- ifeq ($(CONFIG_JOY_MAGELLAN),m)
- M_OBJS += joy-magellan.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_PCI),y)
-O_OBJS += joy-pci.o
-else
- ifeq ($(CONFIG_JOY_PCI),m)
- M_OBJS += joy-pci.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SIDEWINDER),y)
-O_OBJS += joy-sidewinder.o
-else
- ifeq ($(CONFIG_JOY_SIDEWINDER),m)
- M_OBJS += joy-sidewinder.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SPACEORB),y)
-O_OBJS += joy-spaceorb.o
-else
- ifeq ($(CONFIG_JOY_SPACEORB),m)
- M_OBJS += joy-spaceorb.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_SPACEBALL),y)
-O_OBJS += joy-spaceball.o
-else
- ifeq ($(CONFIG_JOY_SPACEBALL),m)
- M_OBJS += joy-spaceball.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_THRUSTMASTER),y)
-O_OBJS += joy-thrustmaster.o
-else
- ifeq ($(CONFIG_JOY_THRUSTMASTER),m)
- M_OBJS += joy-thrustmaster.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_TURBOGRAFX),y)
-O_OBJS += joy-turbografx.o
-else
- ifeq ($(CONFIG_JOY_TURBOGRAFX),m)
- M_OBJS += joy-turbografx.o
- endif
-endif
-
-ifeq ($(CONFIG_JOY_WARRIOR),y)
-O_OBJS += joy-warrior.o
-else
- ifeq ($(CONFIG_JOY_WARRIOR),m)
- M_OBJS += joy-warrior.o
- endif
-endif
+# Subdirs.
+
+SUB_DIRS :=
+MOD_SUB_DIRS := $(SUB_DIRS)
+MOD_IN_SUB_DIRS := $(SUB_DIRS)
+ALL_SUB_DIRS := $(SUB_DIRS)
+
+# The target object and module list name.
+
+O_TARGET := js.o
+M_OBJS :=
+O_OBJS :=
+#MOD_LIST_NAME := INPUT_MODULES
+
+# Objects that export symbols.
+
+export-objs := serio.o gameport.o
+
+# Object file lists.
+
+obj-y :=
+obj-m :=
+obj-n :=
+obj- :=
+
+# Each configuration option enables a list of files.
+
+obj-$(CONFIG_INPUT_SERPORT) += serport.o serio.o
+
+obj-$(CONFIG_INPUT_NS558) += ns558.o gameport.o
+obj-$(CONFIG_INPUT_LIGHTNING) += lightning.o gameport.o
+obj-$(CONFIG_INPUT_PCIGAME) += pcigame.o gameport.o
+
+obj-$(CONFIG_INPUT_WARRIOR) += warrior.o serio.o
+obj-$(CONFIG_INPUT_MAGELLAN) += magellan.o serio.o
+obj-$(CONFIG_INPUT_SPACEORB) += spaceorb.o serio.o
+obj-$(CONFIG_INPUT_SPACEBALL) += spaceball.o serio.o
+obj-$(CONFIG_INPUT_IFORCE_232) += serio.o
+
+obj-$(CONFIG_INPUT_ANALOG) += analog.o gameport.o
+obj-$(CONFIG_INPUT_A3D) += a3d.o gameport.o
+obj-$(CONFIG_INPUT_ADI) += adi.o gameport.o
+obj-$(CONFIG_INPUT_COBRA) += cobra.o gameport.o
+obj-$(CONFIG_INPUT_GF2K) += gf2k.o gameport.o
+obj-$(CONFIG_INPUT_GRIP) += grip.o gameport.o
+obj-$(CONFIG_INPUT_INTERACT) += interact.o gameport.o
+obj-$(CONFIG_INPUT_TMDC) += tmdc.o gameport.o
+obj-$(CONFIG_INPUT_SIDEWINDER) += sidewinder.o gameport.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
+
+# Files that are both resident and modular: remove from modular.
+
+obj-m := $(filter-out $(obj-y), $(obj-m))
+int-m := $(filter-out $(int-y), $(int-m))
+
+# Translate to Rules.make lists.
+
+O_OBJS := $(sort $(filter-out $(export-objs), $(obj-y)))
+OX_OBJS := $(sort $(filter $(export-objs), $(obj-y)))
+M_OBJS := $(sort $(filter-out $(export-objs), $(obj-m)))
+MX_OBJS := $(sort $(filter $(export-objs), $(obj-m)))
+
+# The global Rules.make.
include $(TOPDIR)/Rules.make
diff --git a/drivers/char/joystick/a3d.c b/drivers/char/joystick/a3d.c
new file mode 100644
index 000000000..bd17f8de2
--- /dev/null
+++ b/drivers/char/joystick/a3d.c
@@ -0,0 +1,387 @@
+/*
+ * $Id: a3d.c,v 1.10 2000/05/29 11:19:50 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 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/malloc.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->driver;
+ 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->driver;
+ 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->driver;
+ 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.driver = 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->adc.type = GAMEPORT_EXT;
+
+ 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);
diff --git a/drivers/char/joystick/adi.c b/drivers/char/joystick/adi.c
new file mode 100644
index 000000000..3195fce03
--- /dev/null
+++ b/drivers/char/joystick/adi.c
@@ -0,0 +1,554 @@
+/*
+ * $Id: adi.c,v 1.12 2000/06/03 20:18:52 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/malloc.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;
+
+ if (adi->length != (t = 8 + adi->buttons + adi->axes10 * 10 + adi->axes8 * 8 + adi->hats * 4)) {
+ 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 * 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 * 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);
diff --git a/drivers/char/joystick/amijoy.c b/drivers/char/joystick/amijoy.c
new file mode 100644
index 000000000..f17aeda24
--- /dev/null
+++ b/drivers/char/joystick/amijoy.c
@@ -0,0 +1,149 @@
+/*
+ * $Id: amijoy.c,v 1.4 2000/05/29 10:39:54 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");
+
+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)) {
+ amijoy_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 (!--(*port->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]) {
+
+ 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);
+ }
+}
+
+static void _exit amijoy_exit(void)
+{
+ int i;
+
+ for (i = 0; i < 2; i++)
+ if (amijoy[i])
+ input_unregister_device(amijoy_dev + i);
+}
+
+module_init(amijoy_init);
+module_exit(amijoy_exit);
diff --git a/drivers/char/joystick/analog.c b/drivers/char/joystick/analog.c
new file mode 100644
index 000000000..6514bef9b
--- /dev/null
+++ b/drivers/char/joystick/analog.c
@@ -0,0 +1,758 @@
+/*
+ * $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/malloc.h>
+#include <linux/bitops.h>
+#include <linux/init.h>
+#include <linux/input.h>
+#include <linux/gameport.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+/*
+ * Option parsing.
+ */
+
+MODULE_PARM(js,"1-16s");
+
+#define ANALOG_PORTS 16
+
+static char *js[ANALOG_PORTS];
+static int analog_options[ANALOG_PORTS];
+
+/*
+ * 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__
+#ifdef CONFIG_X86_TSC
+#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "TSC"
+#else
+#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y) ((x)-(y)+((x)<(y)?1193180L/HZ:0))
+#define TIME_NAME "PIT"
+#endif
+#elif __alpha__
+#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
+#define DELTA(x,y) ((y)-(x))
+#define TIME_NAME "PCC"
+#endif
+
+#ifndef GET_TIME
+#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"
+#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(" ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
+ port->speed > 10000 ? (port->speed + 800) / 1000 : port->speed,
+ port->speed > 10000 ? "M" : "k", (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
new file mode 100644
index 000000000..f059a2ff6
--- /dev/null
+++ b/drivers/char/joystick/cobra.c
@@ -0,0 +1,250 @@
+/*
+ * $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/malloc.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 << i));
+
+ }
+
+ 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);
diff --git a/drivers/char/joystick/db9.c b/drivers/char/joystick/db9.c
new file mode 100644
index 000000000..f9edd0755
--- /dev/null
+++ b/drivers/char/joystick/db9.c
@@ -0,0 +1,423 @@
+/*
+ * $Id: db9.c,v 1.5 2000/05/29 20:39:38 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_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] = { 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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev + 1, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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_DOWN ?0:1) - (data&DB9_UP ?0:1));
+ input_report_abs(dev, ABS_Y, (data&DB9_RIGHT?0:1) - (data&DB9_LEFT?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/gamecon.c b/drivers/char/joystick/gamecon.c
new file mode 100644
index 000000000..a92ef58a9
--- /dev/null
+++ b/drivers/char/joystick/gamecon.c
@@ -0,0 +1,668 @@
+/*
+ * $Id: gamecon.c,v 1.4 2000/05/29 21:08:45 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 Vojtech Pavlik
+ *
+ * Based on the work of:
+ * Andree Borrmann John Dahlstrom
+ * David Kuder
+ *
+ * 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_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_PSX + 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 pad",
+ "PSX NegCon", "PSX Analog contoller" };
+/*
+ * 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_START, BTN_SELECT, 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
+ */
+
+#define GC_PSX_DELAY 10
+#define GC_PSX_LENGTH 8 /* talk to the controller in bytes */
+
+#define GC_PSX_MOUSE 0x12 /* PSX Mouse */
+#define GC_PSX_NEGCON 0x23 /* NegCon pad */
+#define GC_PSX_NORMAL 0x41 /* Standard Digital controller */
+#define GC_PSX_ANALOGR 0x73 /* Analog controller in Red mode */
+#define GC_PSX_ANALOGG 0x53 /* Analog controller in Green mode */
+
+#define GC_PSX_CLOCK 0x04 /* Pin 3 */
+#define GC_PSX_COMMAND 0x01 /* Pin 1 */
+#define GC_PSX_POWER 0xf8 /* Pins 5-9 */
+#define GC_PSX_SELECT 0x02 /* Pin 2 */
+#define GC_PSX_NOPOWER 0x04
+
+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_THUMB, BTN_THUMB2 };
+
+/*
+ * 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, ret = 0;
+
+ cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+ for (i = 0; i < 8; i++) {
+ parport_write_data(gc->pd->port, cmd | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ ret |= ((parport_read_status(gc->pd->port) ^ 0x80) & gc->pads[GC_PSX]) ? (1 << i) : 0;
+ cmd = (b & 1) ? GC_PSX_COMMAND : 0;
+ parport_write_data(gc->pd->port, cmd | GC_PSX_CLOCK | GC_PSX_POWER);
+ udelay(GC_PSX_DELAY);
+ b >>= 1;
+ }
+ return ret;
+}
+
+/*
+ * gc_psx_read_packet() reads a whole psx packet and returns
+ * device identifier code.
+ */
+
+static int gc_psx_read_packet(struct gc *gc, int length, unsigned char *data)
+{
+ int i, ret;
+ unsigned long flags;
+
+ __save_flags(flags);
+ __cli();
+
+ parport_write_data(gc->pd->port, GC_PSX_POWER);
+
+ parport_write_data(gc->pd->port, GC_PSX_CLOCK | GC_PSX_SELECT | GC_PSX_POWER); /* Select pad */
+ udelay(GC_PSX_DELAY * 2);
+ gc_psx_command(gc, 0x01); /* Access pad */
+ ret = gc_psx_command(gc, 0x42); /* Get device id */
+ if (gc_psx_command(gc, 0) == 'Z') /* okay? */
+ for (i = 0; i < length; i++)
+ data[i] = gc_psx_command(gc, 0);
+ else ret = -1;
+
+ parport_write_data(gc->pd->port, GC_PSX_SELECT | GC_PSX_CLOCK | GC_PSX_POWER);
+ __restore_flags(flags);
+
+ return ret;
+}
+
+/*
+ * 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[7]) - !!(s & data[6]));
+ input_report_abs(dev + i, ABS_HAT0Y, !!(s & data[5]) - !!(s & data[4]));
+
+ 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[7]) - !!(s & data[6]));
+ input_report_abs(dev + i, ABS_Y, !!(s & data[5]) - !!(s & data[4]));
+ }
+
+ 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[3]) - !!(s & data[2]));
+ input_report_abs(dev + i, ABS_Y, !!(s & data[1]) - !!(s & data[0]));
+ 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, 6, data)) {
+
+ case GC_PSX_ANALOGG:
+
+ 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 << i));
+
+ input_report_key(dev + i, BTN_START, ~data[0] & 0x08);
+ input_report_key(dev + i, BTN_SELECT, ~data[0] & 0x01);
+
+ break;
+
+ case GC_PSX_ANALOGR:
+
+ input_report_key(dev + i, BTN_THUMB, ~data[0] & 0x04);
+ input_report_key(dev + i, BTN_THUMB2, ~data[0] & 0x02);
+
+ case GC_PSX_NORMAL:
+ case GC_PSX_NEGCON:
+
+ 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 << i));
+
+ 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, pbtn;
+ unsigned char data[2];
+
+ 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[j].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 = 0; j < 8; j++)
+ set_bit(gc_snes_btn[j], gc->dev[j].keybit);
+ break;
+
+ case GC_NES:
+ for (j = 0; j < 4; j++)
+ set_bit(gc_snes_btn[j], gc->dev[j].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, 2, data);
+
+ switch(psx) {
+ case GC_PSX_NEGCON:
+ config[i + 1] += 1;
+ case GC_PSX_NORMAL:
+ pbtn = 10;
+ break;
+
+ case GC_PSX_ANALOGG:
+ case GC_PSX_ANALOGR:
+ config[i + 1] += 2;
+ pbtn = 12;
+ for (j = 0; j < 6; j++) {
+ psx = gc_psx_abs[j];
+ set_bit(psx, gc->dev[i].absbit);
+ gc->dev[i].absmin[psx] = 4;
+ gc->dev[i].absmax[psx] = 252;
+ gc->dev[i].absflat[psx] = 2;
+ }
+ break;
+
+ case -1:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ pbtn = 0;
+ printk(KERN_ERR "gamecon.c: No PSX controller found.\n");
+ break;
+
+ default:
+ gc->pads[GC_PSX] &= ~gc_status_bit[i];
+ pbtn = 0;
+ printk(KERN_WARNING "gamecon.c: Unsupported PSX controller %#x,"
+ " please report to <vojtech@suse.cz>.\n", psx);
+ }
+
+ for (j = 0; j < pbtn; j++)
+ set_bit(gc_psx_btn[j], gc->dev[i].keybit);
+
+ 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++) {
+ 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
new file mode 100644
index 000000000..5a5e1219b
--- /dev/null
+++ b/drivers/char/joystick/gameport.c
@@ -0,0 +1,198 @@
+/*
+ * $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/malloc.h>
+#include <linux/isapnp.h>
+#include <linux/stddef.h>
+#include <linux/delay.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
+
+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 = NULL;
+static struct gameport_dev *gameport_dev = NULL;
+static int gameport_number = 0;
+
+/*
+ * gameport_measure_speed() measures the gameport i/o speed.
+ */
+
+static int gameport_measure_speed(struct gameport *gameport)
+{
+#ifdef __i386__
+
+#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
+#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
+
+ unsigned int i, t, t1, t2, t3, tx;
+ unsigned long flags;
+
+ 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
new file mode 100644
index 000000000..cad8be16b
--- /dev/null
+++ b/drivers/char/joystick/gf2k.c
@@ -0,0 +1,359 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/joystick/grip.c b/drivers/char/joystick/grip.c
new file mode 100644
index 000000000..4cedd7892
--- /dev/null
+++ b/drivers/char/joystick/grip.c
@@ -0,0 +1,423 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/joystick/interact.c b/drivers/char/joystick/interact.c
new file mode 100644
index 000000000..7104e5d49
--- /dev/null
+++ b/drivers/char/joystick/interact.c
@@ -0,0 +1,306 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c
deleted file mode 100644
index 8c0ba6923..000000000
--- a/drivers/char/joystick/joy-amiga.c
+++ /dev/null
@@ -1,143 +0,0 @@
-/*
- * joy-amiga.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * microswitch based joystick connected to Amiga joystick port.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/system.h>
-#include <linux/types.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <asm/amigahw.h>
-#include <linux/init.h>
-
-static struct js_port* js_am_port __initdata = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_am, "1-2i");
-
-static int __initdata js_am[] = { 0, 0 };
-
-/*
- * js_am_read() reads and Amiga joystick data.
- */
-
-static int js_am_read(void *info, int **axes, int **buttons)
-{
- int data = 0;
-
- switch (*(int*)info) {
- case 0:
- data = ~custom.joy0dat;
- buttons[0][0] = (~ciaa.pra >> 6) & 1;
- break;
-
- case 1:
- data = ~custom.joy1dat;
- buttons[0][0] = (~ciaa.pra >> 7) & 1;
- break;
-
- default:
- return -1;
- }
-
- axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
- data = ~(data ^ (data << 1));
- axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1);
-
- return 0;
-}
-
-/*
- * js_am_init_corr() initializes correction values of
- * Amiga joysticks.
- */
-
-static void __init js_am_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-}
-
-#ifndef MODULE
-int __init js_am_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_am[i] = ints[i+1];
- return 1;
-}
-__setup("js_am=", js_am_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_am_init(void)
-#endif
-{
- int i;
-
- for (i = 0; i < 2; i++)
- if (js_am[i]) {
- js_am_port = js_register_port(js_am_port, &i, 1, sizeof(int), js_am_read);
- printk(KERN_INFO "js%d: Amiga joystick at joy%ddat\n",
- js_register_device(js_am_port, 0, 2, 1, "Amiga joystick", THIS_MODULE, NULL, NULL), i);
- js_am_init_corr(js_am_port->corr);
- }
- if (js_am_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-amiga: no joysticks specified\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- while (js_am_port) {
- if (js_am_port->devs[0])
- js_unregister_device(js_am_port->devs[0]);
- js_am_port = js_unregister_port(js_am_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c
deleted file mode 100644
index f73ee8ded..000000000
--- a/drivers/char/joystick/joy-analog.c
+++ /dev/null
@@ -1,295 +0,0 @@
-/*
- * joy-analog.c Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * up to two analog (or CHF/FCS) joysticks on a single joystick port.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/param.h>
-#include <asm/system.h>
-#include <linux/config.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/sched.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_AN_MAX_TIME 3000 /* 3 ms */
-#define JS_AN_LOOP_TIME 2000 /* 2 t */
-
-static int js_an_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_an_port __initdata = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_an, "2-24i");
-
-static int __initdata js_an[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-#include "joy-analog.h"
-
-struct js_ax_info {
- int io;
- int speed;
- int loop;
- int timeout;
- struct js_an_info an;
-};
-
-/*
- * Time macros.
- */
-
-#ifdef __i386__
-#ifdef CONFIG_X86_TSC
-#define GET_TIME(x) __asm__ __volatile__ ( "rdtsc" : "=a" (x) : : "dx" )
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "TSC"
-#else
-#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
-#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
-#define TIME_NAME "PIT"
-#endif
-#elif __alpha__
-#define GET_TIME(x) __asm__ __volatile__ ( "rpcc %0" : "=r" (x) )
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "PCC"
-#endif
-
-#ifndef GET_TIME
-#define FAKE_TIME
-static unsigned long js_an_faketime = 0;
-#define GET_TIME(x) do { x = js_an_faketime++; } while(0)
-#define DELTA(x,y) ((x)-(y))
-#define TIME_NAME "Unreliable"
-#endif
-
-/*
- * js_an_read() reads analog joystick data.
- */
-
-static int js_an_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_ax_info *info = xinfo;
- struct js_an_info *an = &info->an;
- int io = info->io;
- unsigned long flags;
- unsigned char buf[4];
- unsigned int time[4];
- unsigned char u, v, w;
- unsigned int p, q, r, s, t;
- int i, j;
-
- an->buttons = ~inb(io) >> 4;
-
- i = 0;
- w = ((an->mask[0] | an->mask[1]) & JS_AN_AXES_STD) | (an->extensions & JS_AN_HAT_FCS)
- | ((an->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((an->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
- p = info->loop;
- q = info->timeout;
-
- __save_flags(flags);
- __cli();
- outb(0xff,io);
- GET_TIME(r);
- __restore_flags(flags);
- t = r;
- v = w;
- do {
- s = t;
- u = v;
- __cli();
- v = inb(io) & w;
- GET_TIME(t);
- __restore_flags(flags);
- if ((u ^ v) && (DELTA(t,s) < p)) {
- time[i] = t;
- buf[i] = u ^ v;
- i++;
- }
- } while (v && (i < 4) && (DELTA(t,r) < q));
-
- v <<= 4;
-
- for (--i; i >= 0; i--) {
- v |= buf[i];
- for (j = 0; j < 4; j++)
- if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
- }
-
- js_an_decode(an, axes, buttons);
-
- return -(v != w);
-}
-
-/*
- * js_an_calibrate_timer() calibrates the timer and computes loop
- * and timeout values for a joystick port.
- */
-
-static void __init js_an_calibrate_timer(struct js_ax_info *info)
-{
- unsigned int i, t, tx, t1, t2, t3;
- unsigned long flags;
- int io = info->io;
-
- save_flags(flags);
- cli();
- GET_TIME(t1);
-#ifdef FAKE_TIME
- js_an_faketime += 830;
-#endif
- udelay(1000);
- GET_TIME(t2);
- GET_TIME(t3);
- restore_flags(flags);
-
- info->speed = DELTA(t2, t1) - DELTA(t3, t2);
-
- tx = 1 << 30;
-
- for(i = 0; i < 50; i++) {
- save_flags(flags);
- cli();
- GET_TIME(t1);
- for(t = 0; t < 50; t++) { inb(io); GET_TIME(t2); }
- GET_TIME(t3);
- restore_flags(flags);
- udelay(i);
- if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
- }
-
- info->loop = (JS_AN_LOOP_TIME * t) / 50000;
- info->timeout = (JS_AN_MAX_TIME * info->speed) / 1000;
-}
-
-/*
- * js_an_probe() probes for analog joysticks.
- */
-
-static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct js_port *port)
-{
- struct js_ax_info info, *ax;
- int i, numdev;
- unsigned char u;
-
- if (io < 0) return port;
-
- if (check_region(io, 1)) return port;
-
- outb(0xff,io);
- u = inb(io);
- udelay(JS_AN_MAX_TIME);
- u = (inb(io) ^ u) & u;
-
- if (!u) return port;
- if (u & 0xf0) return port;
-
- if ((numdev = js_an_probe_devs(&info.an, u, mask0, mask1, port)) <= 0)
- return port;
-
- info.io = io;
- js_an_calibrate_timer(&info);
-
- request_region(info.io, 1, "joystick (analog)");
- port = js_register_port(port, &info, numdev, sizeof(struct js_ax_info), js_an_read);
- ax = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
- js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
- js_an_name(i, &ax->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &ax->an),
- ax->io,
- ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
- ax->speed > 10000 ? "M" : "k",
- ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);
-
- js_an_read(ax, port->axes, port->buttons);
- js_an_init_corr(&ax->an, port->axes, port->corr, 8);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_an_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_an[i] = ints[i+1];
- return 1;
-}
-__setup("js_an=", js_an_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_an_init(void)
-#endif
-{
- int i;
-
- if (js_an[0] >= 0) {
- for (i = 0; (js_an[i*3] >= 0) && i < 8; i++)
- js_an_port = js_an_probe(js_an[i*3], js_an[i*3+1], js_an[i*3+2], js_an_port);
- } else {
- for (i = 0; js_an_port_list[i]; i++)
- js_an_port = js_an_probe(js_an_port_list[i], 0, 0, js_an_port);
- }
- if (js_an_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-analog: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_ax_info *info;
-
- while (js_an_port) {
- for (i = 0; i < js_an_port->ndevs; i++)
- if (js_an_port->devs[i])
- js_unregister_device(js_an_port->devs[i]);
- info = js_an_port->info;
- release_region(info->io, 1);
- js_an_port = js_unregister_port(js_an_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-analog.h b/drivers/char/joystick/joy-analog.h
deleted file mode 100644
index a1644350c..000000000
--- a/drivers/char/joystick/joy-analog.h
+++ /dev/null
@@ -1,287 +0,0 @@
-/*
- * joy-analog.h Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This file is designed to be included in any joystick driver
- * that communicates with standard analog joysticks. This currently
- * is: joy-analog.c, joy-assassin.c, and joy-lightning.c
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <linux/bitops.h>
-
-#define JS_AN_AXES_STD 0x0f
-#define JS_AN_BUTTONS_STD 0xf0
-
-#define JS_AN_BUTTONS_CHF 0x01
-#define JS_AN_HAT1_CHF 0x02
-#define JS_AN_HAT2_CHF 0x04
-#define JS_AN_ANY_CHF 0x07
-#define JS_AN_HAT_FCS 0x08
-#define JS_AN_HATS_ALL 0x0e
-#define JS_AN_BUTTON_PXY_X 0x10
-#define JS_AN_BUTTON_PXY_Y 0x20
-#define JS_AN_BUTTON_PXY_U 0x40
-#define JS_AN_BUTTON_PXY_V 0x80
-#define JS_AN_BUTTONS_PXY_XY 0x30
-#define JS_AN_BUTTONS_PXY_UV 0xc0
-#define JS_AN_BUTTONS_PXY 0xf0
-
-static struct {
- int x;
- int y;
-} js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}};
-
-struct js_an_info {
- unsigned char mask[2];
- unsigned int extensions;
- int axes[4];
- int initial[4];
- unsigned char buttons;
-};
-
-/*
- * js_an_decode() decodes analog joystick data.
- */
-
-static void js_an_decode(struct js_an_info *info, int **axes, int **buttons)
-{
- int i, j, k;
- int hat1, hat2, hat3;
-
- hat1 = hat2 = hat3 = 0;
- if (info->mask[0] & JS_AN_BUTTONS_STD) buttons[0][0] = 0;
- if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0;
-
- if (info->extensions & JS_AN_ANY_CHF) {
- switch (info->buttons & 0xf) {
- case 0x1: buttons[0][0] = 0x01; break;
- case 0x2: buttons[0][0] = 0x02; break;
- case 0x4: buttons[0][0] = 0x04; break;
- case 0x8: buttons[0][0] = 0x08; break;
- case 0x5: buttons[0][0] = 0x10; break;
- case 0x9: buttons[0][0] = 0x20; break;
- case 0xf: hat1 = 1; break;
- case 0xb: hat1 = 2; break;
- case 0x7: hat1 = 3; break;
- case 0x3: hat1 = 4; break;
- case 0xe: hat2 = 1; break;
- case 0xa: hat2 = 2; break;
- case 0x6: hat2 = 3; break;
- case 0xc: hat2 = 4; break;
- }
- k = info->extensions & JS_AN_BUTTONS_CHF ? 6 : 4;
- } else {
- for (i = 1; i >= 0; i--)
- for (j = k = 0; j < 4; j++)
- if (info->mask[i] & (0x10 << j))
- buttons[i][0] |= ((info->buttons >> j) & 1) << k++;
- }
-
- if (info->extensions & JS_AN_BUTTON_PXY_X)
- buttons[0][0] |= (info->axes[2] < (info->initial[2] >> 1)) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_Y)
- buttons[0][0] |= (info->axes[3] < (info->initial[3] >> 1)) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_U)
- buttons[0][0] |= (info->axes[2] > (info->initial[2] + (info->initial[2] >> 1))) << k++;
- if (info->extensions & JS_AN_BUTTON_PXY_V)
- buttons[0][0] |= (info->axes[3] > (info->initial[3] + (info->initial[3] >> 1))) << k++;
-
- if (info->extensions & JS_AN_HAT_FCS)
- for (j = 0; j < 4; j++)
- if (info->axes[3] < ((info->initial[3] * ((j << 1) + 1)) >> 3)) {
- hat3 = j + 1;
- break;
- }
-
- for (i = 1; i >= 0; i--)
- for (j = k = 0; j < 4; j++)
- if (info->mask[i] & (1 << j))
- axes[i][k++] = info->axes[j];
-
- if (info->extensions & JS_AN_HAT1_CHF) {
- axes[0][k++] = js_an_hat_to_axis[hat1].x;
- axes[0][k++] = js_an_hat_to_axis[hat1].y;
- }
- if (info->extensions & JS_AN_HAT2_CHF) {
- axes[0][k++] = js_an_hat_to_axis[hat2].x;
- axes[0][k++] = js_an_hat_to_axis[hat2].y;
- }
- if (info->extensions & JS_AN_HAT_FCS) {
- axes[0][k++] = js_an_hat_to_axis[hat3].x;
- axes[0][k++] = js_an_hat_to_axis[hat3].y;
- }
-}
-
-
-/*
- * js_an_init_corr() initializes the correction values for
- * analog joysticks.
- */
-
-static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct js_corr **corr, int prec)
-{
- int i, j, t;
-
- for (i = 0; i < 2; i++)
- for (j = 0; j < hweight8(info->mask[i] & 0xf); j++) {
-
- if ((j == 2 && (info->mask[i] & 0xb) == 0xb) ||
- (j == 3 && (info->mask[i] & 0xf) == 0xf)) {
- t = (axes[i][0] + axes[i][1]) >> 1;
- } else {
- t = axes[i][j];
- }
-
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = prec;
- corr[i][j].coef[0] = t - (t >> 3);
- corr[i][j].coef[1] = t + (t >> 3);
- corr[i][j].coef[2] = (1 << 29) / (t - (t >> 2) + 1);
- corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1);
- }
-
- i = hweight8(info->mask[0] & 0xf);
-
- for (j = i; j < i + (hweight8(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = (1 << 29);
- corr[0][j].coef[3] = (1 << 29);
- }
-
- for (i = 0; i < 4; i++)
- info->initial[i] = info->axes[i];
-}
-
-
-/*
- * js_an_probe_devs() probes for analog joysticks.
- */
-
-static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0, int mask1, struct js_port *port)
-{
- info->mask[0] = info->mask[1] = info->extensions = 0;
-
- if (mask0 || mask1) {
- info->mask[0] = mask0 & (exist | 0xf0);
- info->mask[1] = mask1 & (exist | 0xf0) & ~info->mask[0];
- info->extensions = (mask0 >> 8) & ((exist & JS_AN_HAT_FCS) | ((exist << 2) & JS_AN_BUTTONS_PXY_XY) |
- ((exist << 4) & JS_AN_BUTTONS_PXY_UV) | JS_AN_ANY_CHF);
-
- if (info->extensions & JS_AN_BUTTONS_PXY) {
- info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2);
- info->mask[0] &= ~((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
- info->mask[1] = 0;
- }
- if (info->extensions & JS_AN_HAT_FCS) {
- info->mask[0] &= ~JS_AN_HAT_FCS;
- info->mask[1] = 0;
- info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V);
- }
- if (info->extensions & JS_AN_ANY_CHF) {
- info->mask[0] |= 0xf0;
- info->mask[1] = 0;
- }
- if (!(info->mask[0] | info->mask[1])) return -1;
- } else {
- switch (exist) {
- case 0x0:
- return -1;
- case 0x3:
- info->mask[0] = 0xf3; /* joystick 0, assuming 4-button */
- break;
- case 0xb:
- info->mask[0] = 0xfb; /* 3-axis, 4-button joystick */
- break;
- case 0xc:
- info->mask[0] = 0xcc; /* joystick 1 */
- break;
- case 0xf:
- info->mask[0] = 0xff; /* 4-axis 4-button joystick */
- break;
- default:
- printk(KERN_WARNING "joy-analog: Unknown joystick device detected "
- "(data=%#x), contact <vojtech@suse.cz>\n", exist);
- return -1;
- }
- }
-
- return !!info->mask[0] + !!info->mask[1];
-}
-
-/*
- * js_an_axes() returns the number of axes for an analog joystick.
- */
-
-static inline int js_an_axes(int i, struct js_an_info *info)
-{
- return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2;
-}
-
-/*
- * js_an_buttons() returns the number of buttons for an analog joystick.
- */
-
-static inline int js_an_buttons(int i, struct js_an_info *info)
-{
- return hweight8(info->mask[i] & 0xf0) +
- (info->extensions & JS_AN_BUTTONS_CHF) * 2 +
- hweight8(info->extensions & JS_AN_BUTTONS_PXY);
-}
-
-/*
- * js_an_name() constructs a name for an analog joystick.
- */
-
-static char js_an_name_buf[128] __initdata = "";
-
-static char __init *js_an_name(int i, struct js_an_info *info)
-{
-
- sprintf(js_an_name_buf, "Analog %d-axis %d-button",
- hweight8(info->mask[i] & 0x0f),
- js_an_buttons(i, info));
-
- if (info->extensions & JS_AN_HATS_ALL)
- sprintf(js_an_name_buf, "%s %d-hat",
- js_an_name_buf,
- hweight8(info->extensions & JS_AN_HATS_ALL));
-
- strcat(js_an_name_buf, " joystick");
-
- if (info->extensions)
- sprintf(js_an_name_buf, "%s with%s%s%s extensions",
- js_an_name_buf,
- info->extensions & JS_AN_ANY_CHF ? " CHF" : "",
- info->extensions & JS_AN_HAT_FCS ? " FCS" : "",
- info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : "");
-
- return js_an_name_buf;
-}
diff --git a/drivers/char/joystick/joy-assassin.c b/drivers/char/joystick/joy-assassin.c
deleted file mode 100644
index 469c6c8ce..000000000
--- a/drivers/char/joystick/joy-assassin.c
+++ /dev/null
@@ -1,396 +0,0 @@
-/*
- * joy-assassin.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * joysticks using FP-Gaming's Assassin 3D protocol.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_AS_MAX_START 1000
-#define JS_AS_DELAY_READ 3000
-#define JS_AS_MAX_LENGTH 40
-
-#define JS_AS_MODE_A3D 1 /* Assassin 3D */
-#define JS_AS_MODE_PAN 2 /* Panther */
-#define JS_AS_MODE_OEM 3 /* Panther OEM version */
-#define JS_AS_MODE_PXL 4 /* Panther XL */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_as, "2-24i");
-
-static int __initdata js_as[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-static int js_as_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_as_port __initdata = NULL;
-
-#include "joy-analog.h"
-
-struct js_as_info {
- int io;
- char mode;
- char rudder;
- struct js_an_info an;
-};
-
-/*
- * js_as_read_packet() reads an Assassin 3D packet.
- */
-
-static int js_as_read_packet(int io, int length, char *data)
-{
- unsigned char u, v;
- int i;
- unsigned int t, p;
- unsigned long flags;
-
- i = 0;
-
- __save_flags(flags);
- __cli();
-
- outb(0xff,io);
- v = inb(io);
- t = p = JS_AS_MAX_START;
-
- while (t > 0 && i < length) {
- t--;
- u = v; v = inb(io);
- if (~v & u & 0x10) {
- data[i++] = v >> 5;
- p = t = (p - t) << 3;
- }
- }
-
- __restore_flags(flags);
-
- return i;
-}
-
-/*
- * js_as_csum() computes checksum of triplet packet
- */
-
-static int js_as_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]);
-}
-
-/*
- * js_as_read() reads and analyzes A3D joystick data.
- */
-
-static int js_as_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_as_info *info = xinfo;
- char data[JS_AS_MAX_LENGTH];
-
- switch (info->mode) {
-
- case JS_AS_MODE_A3D:
- case JS_AS_MODE_OEM:
- case JS_AS_MODE_PAN:
-
- if (js_as_read_packet(info->io, 29, data) != 29) return -1;
- if (data[0] != info->mode) return -1;
- if (js_as_csum(data, 29)) return -1;
-
- axes[0][0] = ((data[5] << 6) | (data[6] << 3) | data[ 7]) - ((data[5] & 4) << 7);
- axes[0][1] = ((data[8] << 6) | (data[9] << 3) | data[10]) - ((data[8] & 4) << 7);
-
- buttons[0][0] = (data[2] << 2) | (data[3] >> 1);
-
- info->an.axes[0] = ((char)((data[11] << 6) | (data[12] << 3) | (data[13]))) + 128;
- info->an.axes[1] = ((char)((data[14] << 6) | (data[15] << 3) | (data[16]))) + 128;
- info->an.axes[2] = ((char)((data[17] << 6) | (data[18] << 3) | (data[19]))) + 128;
- info->an.axes[3] = ((char)((data[20] << 6) | (data[21] << 3) | (data[22]))) + 128;
-
- info->an.buttons = ((data[3] << 3) | data[4]) & 0xf;
-
- js_an_decode(&info->an, axes + 1, buttons + 1);
-
- return 0;
-
- case JS_AS_MODE_PXL:
-
- if (js_as_read_packet(info->io, 33, data) != 33) return -1;
- if (data[0] != info->mode) return -1;
- if (js_as_csum(data, 33)) return -1;
-
- axes[0][0] = ((char)((data[15] << 6) | (data[16] << 3) | (data[17]))) + 128;
- axes[0][1] = ((char)((data[18] << 6) | (data[19] << 3) | (data[20]))) + 128;
- info->an.axes[0] = ((char)((data[21] << 6) | (data[22] << 3) | (data[23]))) + 128;
- axes[0][2] = ((char)((data[24] << 6) | (data[25] << 3) | (data[26]))) + 128;
-
- axes[0][3] = ( data[5] & 1) - ((data[5] >> 2) & 1);
- axes[0][4] = ((data[5] >> 1) & 1) - ((data[6] >> 2) & 1);
- axes[0][5] = ((data[4] >> 1) & 1) - ( data[3] & 1);
- axes[0][6] = ((data[4] >> 2) & 1) - ( data[4] & 1);
-
- axes[0][7] = ((data[ 9] << 6) | (data[10] << 3) | data[11]) - ((data[ 9] & 4) << 7);
- axes[0][8] = ((data[12] << 6) | (data[13] << 3) | data[14]) - ((data[12] & 4) << 7);
-
- buttons[0][0] = (data[2] << 8) | ((data[3] & 6) << 5) | (data[7] << 3) | data[8];
-
- if (info->rudder) axes[1][0] = info->an.axes[0];
-
- return 0;
- }
- return -1;
-}
-
-/*
- * js_as_pxl_init_corr() initializes the correction values for
- * the Panther XL.
- */
-
-static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = axes[0][i] - 4;
- corr[0][i].coef[1] = axes[0][i] + 4;
- corr[0][i].coef[2] = (1 << 29) / (127 - 32);
- corr[0][i].coef[3] = (1 << 29) / (127 - 32);
- }
-
- corr[0][2].type = JS_CORR_BROKEN;
- corr[0][2].prec = 0;
- corr[0][2].coef[0] = 127 - 4;
- corr[0][2].coef[1] = 128 + 4;
- corr[0][2].coef[2] = (1 << 29) / (127 - 6);
- corr[0][2].coef[3] = (1 << 29) / (127 - 6);
-
- for (i = 3; i < 7; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-
- for (i = 7; i < 9; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = -1;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (104 << 14);
- corr[0][i].coef[3] = (104 << 14);
- }
-}
-
-/*
- * js_as_as_init_corr() initializes the correction values for
- * the Panther and Assassin.
- */
-
-static void __init js_as_as_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = -1;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (104 << 14);
- corr[0][i].coef[3] = (104 << 14);
- }
-}
-
-/*
- * js_as_rudder_init_corr() initializes the correction values for
- * the Panther XL connected rudder.
- */
-
-static void __init js_as_rudder_init_corr(struct js_corr **corr, int **axes)
-{
- corr[1][0].type = JS_CORR_BROKEN;
- corr[1][0].prec = 0;
- corr[1][0].coef[0] = axes[1][0] - (axes[1][0] >> 3);
- corr[1][0].coef[1] = axes[1][0] + (axes[1][0] >> 3);
- corr[1][0].coef[2] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
- corr[1][0].coef[3] = (1 << 29) / (axes[1][0] - (axes[1][0] >> 2) + 1);
-}
-
-/*
- * js_as_probe() probes for A3D joysticks.
- */
-
-static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct js_port *port)
-{
- struct js_as_info iniinfo;
- struct js_as_info *info = &iniinfo;
- char *name;
- char data[JS_AS_MAX_LENGTH];
- unsigned char u;
- int i;
- int numdev;
-
- memset(info, 0, sizeof(struct js_as_info));
-
- if (io < 0) return port;
-
- if (check_region(io, 1)) return port;
-
- i = js_as_read_packet(io, JS_AS_MAX_LENGTH, data);
-
- printk("%d\n", i);
-
- if (!i) return port;
- if (js_as_csum(data, i)) return port;
-
- if (data[0] && data[0] <= 4) {
- info->mode = data[0];
- info->io = io;
- request_region(io, 1, "joystick (assassin)");
- port = js_register_port(port, info, 3, sizeof(struct js_as_info), js_as_read);
- info = port->info;
- } else {
- printk(KERN_WARNING "joy-assassin: unknown joystick device detected "
- "(io=%#x, id=%d), contact <vojtech@suse.cz>\n", io, data[0]);
- return port;
- }
-
- udelay(JS_AS_DELAY_READ);
-
- if (info->mode == JS_AS_MODE_PXL) {
- printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
- js_register_device(port, 0, 9, 9, "MadCatz Panther XL", THIS_MODULE, NULL, NULL),
- info->io);
- js_as_read(port->info, port->axes, port->buttons);
- js_as_pxl_init_corr(port->corr, port->axes);
- if (info->an.axes[0] < 254) {
- printk(KERN_INFO "js%d: Analog rudder on MadCatz Panther XL\n",
- js_register_device(port, 1, 1, 0, "Analog rudder", THIS_MODULE, NULL, NULL));
- info->rudder = 1;
- port->axes[1][0] = info->an.axes[0];
- js_as_rudder_init_corr(port->corr, port->axes);
- }
- return port;
- }
-
- switch (info->mode) {
- case JS_AS_MODE_A3D: name = "FP-Gaming Assassin 3D"; break;
- case JS_AS_MODE_PAN: name = "MadCatz Panther"; break;
- case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break;
- default: name = "This cannot happen"; break;
- }
-
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, 0, 2, 3, name, THIS_MODULE, NULL, NULL),
- name, info->io);
-
- js_as_as_init_corr(port->corr);
-
- js_as_read(port->info, port->axes, port->buttons);
-
- for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 254) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i + 1, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &info->an), name);
-
- js_an_decode(&info->an, port->axes + 1, port->buttons + 1);
- js_an_init_corr(&info->an, port->axes + 1, port->corr + 1, 0);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_as_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_as[i] = ints[i+1];
- return 1;
-}
-__setup("js_as=", js_as_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_as_init(void)
-#endif
-{
- int i;
-
- if (js_as[0] >= 0) {
- for (i = 0; (js_as[i*3] >= 0) && i < 8; i++)
- js_as_port = js_as_probe(js_as[i*3], js_as[i*3+1], js_as[i*3+2], js_as_port);
- } else {
- for (i = 0; js_as_port_list[i]; i++) js_as_port = js_as_probe(js_as_port_list[i], 0, 0, js_as_port);
- }
- if (js_as_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-assassin: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_as_info *info;
-
- while (js_as_port) {
- for (i = 0; i < js_as_port->ndevs; i++)
- if (js_as_port->devs[i])
- js_unregister_device(js_as_port->devs[i]);
- info = js_as_port->info;
- release_region(info->io, 1);
- js_as_port = js_unregister_port(js_as_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-console.c b/drivers/char/joystick/joy-console.c
deleted file mode 100644
index e56da540a..000000000
--- a/drivers/char/joystick/joy-console.c
+++ /dev/null
@@ -1,811 +0,0 @@
-/*
- * joy-console.c Version 0.14V
- *
- * Copyright (c) 1998 Andree Borrmann
- * Copyright (c) 1999 John Dahlstrom
- * Copyright (c) 1999 David Kuder
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads
- * connected via parallel port. Up to five such controllers
- * can be connected to one parallel port.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_console, "2-6i");
-MODULE_PARM(js_console_2,"2-6i");
-MODULE_PARM(js_console_3,"2-6i");
-
-
-#define JS_NO_PAD 0
-#define JS_SNES_PAD 1
-#define JS_NES_PAD 2
-#define JS_NES4_PAD 3
-#define JS_MULTI_STICK 4
-#define JS_MULTI2_STICK 5
-#define JS_PSX_PAD 6
-#define JS_N64_PAD 7
-#define JS_N64_PAD_DPP 8 /* DirectPad Pro compatible layout */
-
-#define JS_MAX_PAD JS_N64_PAD_DPP
-
-struct js_console_info {
- struct pardevice *port; /* parport device */
- int pads; /* total number of pads */
- int pad_to_device[5]; /* pad to js device mapping (js0, js1, etc.) */
- int snes; /* SNES pads */
- int nes; /* NES pads */
- int n64; /* N64 pads */
- int n64_dpp; /* bits indicate N64 pads treated 14 button, 2 axis */
- int multi; /* Multi joysticks */
- int multi2; /* Multi joysticks with 2 buttons */
- int psx; /* PSX controllers */
-};
-
-static struct js_port* js_console_port = NULL;
-
-static int js_console[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console_2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console_3[] __initdata = { -1, 0, 0, 0, 0, 0 };
-
-static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
-
-/*
- * NES/SNES support.
- */
-
-#define JS_NES_DELAY 6 /* Delay between bits - 6us */
-
-#define JS_NES_LENGTH 8 /* The NES pads use 8 bits of data */
-
-#define JS_NES_A 0
-#define JS_NES_B 1
-#define JS_NES_START 2
-#define JS_NES_SELECT 3
-#define JS_NES_UP 4
-#define JS_NES_DOWN 5
-#define JS_NES_LEFT 6
-#define JS_NES_RIGHT 7
-
-#define JS_SNES_LENGTH 12 /* The SNES true length is 16, but the last 4 bits are unused */
-
-#define JS_SNES_B 0
-#define JS_SNES_Y 1
-#define JS_SNES_START 2
-#define JS_SNES_SELECT 3
-#define JS_SNES_UP 4
-#define JS_SNES_DOWN 5
-#define JS_SNES_LEFT 6
-#define JS_SNES_RIGHT 7
-#define JS_SNES_A 8
-#define JS_SNES_X 9
-#define JS_SNES_L 10
-#define JS_SNES_R 11
-
-#define JS_NES_POWER 0xfc
-#define JS_NES_CLOCK 0x01
-#define JS_NES_LATCH 0x02
-
-/*
- * js_nes_read_packet() reads a NES/SNES packet.
- * Each pad uses one bit per byte. So all pads connected to
- * this port are read in parallel.
- */
-
-static void js_nes_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i;
-
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK | JS_NES_LATCH, info->port);
- udelay(JS_NES_DELAY * 2);
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
-
- for (i = 0; i < length; i++) {
- udelay(JS_NES_DELAY);
- JS_PAR_DATA_OUT(JS_NES_POWER, info->port);
- data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- udelay(JS_NES_DELAY);
- JS_PAR_DATA_OUT(JS_NES_POWER | JS_NES_CLOCK, info->port);
- }
-}
-
-/*
- * N64 support.
- */
-
-#define JS_N64_A 0
-#define JS_N64_B 1
-#define JS_N64_Z 2
-#define JS_N64_START 3
-#define JS_N64_UP 4
-#define JS_N64_DOWN 5
-#define JS_N64_LEFT 6
-#define JS_N64_RIGHT 7
-#define JS_N64_UNUSED1 8
-#define JS_N64_UNUSED2 9
-#define JS_N64_L 10
-#define JS_N64_R 11
-#define JS_N64_CU 12
-#define JS_N64_CD 13
-#define JS_N64_CL 14
-#define JS_N64_CR 15
-#define JS_N64_X 23 /* 16 - 23, signed 8-bit int */
-#define JS_N64_Y 31 /* 24 - 31, signed 8-bit int */
-
-#define JS_N64_LENGTH 32 /* N64 bit length, not including stop bit */
-#define JS_N64_REQUEST_LENGTH 37 /* transmit request sequence is 9 bits long */
-#define JS_N64_DELAY 133 /* delay between transmit request, and response ready (us) */
-#define JS_N64_REQUEST 0x1dd1111111ULL /* the request data command (encoded for 000000011) */
-#define JS_N64_DWS 3 /* delay between write segments (required for sound playback because of ISA DMA) */
- /* JS_N64_DWS > 24 is known to fail */
-#define JS_N64_POWER_W 0xe2 /* power during write (transmit request) */
-#define JS_N64_POWER_R 0xfd /* power during read */
-#define JS_N64_OUT 0x1d /* output bits to the 4 pads */
- /* Reading the main axes of any N64 pad is known to fail if the corresponding bit */
- /* in JS_N64_OUT is pulled low on the output port (by any routine) for more */
- /* than 0.123 consecutive ms */
-#define JS_N64_CLOCK 0x02 /* clock bits for read */
-
-/*
- * js_n64_read_packet() reads an N64 packet.
- * Each pad uses one bit per byte. So all pads connected to this port are read in parallel.
- */
-
-static void js_n64_read_packet(struct js_console_info *info, unsigned char *data)
-{
- int i;
- unsigned long flags;
-
-/*
- * Request the pad to transmit data
- */
-
- save_flags(flags);
- cli();
- for (i = 0; i < JS_N64_REQUEST_LENGTH; i++) {
- JS_PAR_DATA_OUT(JS_N64_POWER_W | ((JS_N64_REQUEST >> i) & 1 ? JS_N64_OUT : 0), info->port);
- udelay(JS_N64_DWS);
- }
- restore_flags(flags);
-
-/*
- * Wait for the pad response to be loaded into the 33-bit register of the adapter
- */
-
- udelay(JS_N64_DELAY);
-
-/*
- * Grab data (ignoring the last bit, which is a stop bit)
- */
-
- for (i = 0; i < JS_N64_LENGTH; i++) {
- JS_PAR_DATA_OUT(JS_N64_POWER_R, info->port);
- data[i] = JS_PAR_STATUS(info->port);
- JS_PAR_DATA_OUT(JS_N64_POWER_R | JS_N64_CLOCK, info->port);
- }
-
-/*
- * We must wait ~0.2 ms here for the controller to reinitialize before the next read request.
- * No worries as long as js_console_read is polled less frequently than this.
- */
-
-}
-
-/*
- * Multisystem joystick support
- */
-
-#define JS_MULTI_LENGTH 5 /* Multi system joystick packet lenght is 5 */
-#define JS_MULTI2_LENGTH 6 /* One more bit for one more button */
-
-#define JS_MULTI_UP 0
-#define JS_MULTI_DOWN 1
-#define JS_MULTI_LEFT 2
-#define JS_MULTI_RIGHT 3
-#define JS_MULTI_BUTTON 4
-#define JS_MULTI_BUTTON2 5
-
-/*
- * js_multi_read_packet() reads a Multisystem joystick packet.
- */
-
-static void js_multi_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i;
-
- for (i = 0; i < length; i++) {
- JS_PAR_DATA_OUT(~(1 << i), info->port);
- data[i] = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- printk(" %d", data[i]);
- }
- printk("\n");
-}
-
-/*
- * PSX support
- */
-
-#define JS_PSX_DELAY 10
-#define JS_PSX_LENGTH 8 /* talk to the controller in bytes */
-
-#define JS_PSX_NORMAL 0x41 /* Standard Digital controller */
-#define JS_PSX_NEGCON 0x23 /* NegCon pad */
-#define JS_PSX_MOUSE 0x12 /* PSX Mouse */
-#define JS_PSX_ANALOGR 0x73 /* Analog controller in Red mode */
-#define JS_PSX_ANALOGG 0x53 /* Analog controller in Green mode */
-
-#define JS_PSX_JOYR 0x02 /* These are for the Analog/Dual Shock controller in RED mode */
-#define JS_PSX_JOYL 0x04 /* I'm not sure the exact purpose of these but its in the docs */
-#define JS_PSX_SELBUT 0x01 /* Standard buttons on almost all PSX controllers. */
-#define JS_PSX_START 0x08
-#define JS_PSX_UP 0x10 /* Digital direction pad */
-#define JS_PSX_RIGHT 0x20
-#define JS_PSX_DOWN 0x40
-#define JS_PSX_LEFT 0x80
-
-#define JS_PSX_CLOCK 0x04 /* Pin 3 */
-#define JS_PSX_COMMAND 0x01 /* Pin 1 */
-#define JS_PSX_POWER 0xf8 /* Pins 5-9 */
-#define JS_PSX_SELECT 0x02 /* Pin 2 */
-#define JS_PSX_NOPOWER 0x04
-
-/*
- * js_psx_command() writes 8bit command and reads 8bit data from
- * the psx pad.
- */
-
-static int js_psx_command(struct js_console_info *info, int b)
-{
- int i, cmd, ret=0;
-
- cmd = (b&1)?JS_PSX_COMMAND:0;
- for (i=0; i<8; i++) {
- JS_PAR_DATA_OUT(cmd | JS_PSX_POWER, info->port);
- udelay(JS_PSX_DELAY);
- ret |= ((JS_PAR_STATUS(info->port) ^ JS_PAR_STATUS_INVERT ) & info->psx) ? (1<<i) : 0;
- cmd = (b&1)?JS_PSX_COMMAND:0;
- JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
- udelay(JS_PSX_DELAY);
- b >>= 1;
- }
- return ret;
-}
-
-/*
- * js_psx_read_packet() reads a whole psx packet and returns
- * device identifier code.
- */
-
-static int js_psx_read_packet(struct js_console_info *info, int length, unsigned char *data)
-{
- int i, ret;
- unsigned long flags;
-
- __save_flags(flags);
- __cli();
-
- JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);
-
- JS_PAR_DATA_OUT(JS_PSX_CLOCK | JS_PSX_SELECT | JS_PSX_POWER, info->port); /* Select pad */
- udelay(JS_PSX_DELAY*2);
- js_psx_command(info, 0x01); /* Access pad */
- ret = js_psx_command(info, 0x42); /* Get device id */
- if (js_psx_command(info, 0)=='Z') /* okay? */
- for (i=0; i<length; i++)
- data[i]=js_psx_command(info, 0);
- else ret = -1;
-
- JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
- __restore_flags(flags);
-
- return ret;
-}
-
-
-/*
- * js_console_read() reads and analyzes console pads data.
- */
-
-#define JS_MAX_LENGTH JS_N64_LENGTH
-
-static int js_console_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_console_info *info = xinfo;
- unsigned char data[JS_MAX_LENGTH];
-
- int i, j, s;
- int n = 0;
-
-/*
- * NES and SNES pads
- */
-
- if (info->nes || info->snes) {
-
- js_nes_read_packet(info, info->snes ? JS_SNES_LENGTH : JS_NES_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->nes & s) {
- axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
- axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_NES_A] &s?1:0) | (data[JS_NES_B] &s?2:0)
- | (data[JS_NES_START]&s?4:0) | (data[JS_NES_SELECT]&s?8:0);
- } else
- if (info->snes & s) {
- axes[n][0] = (data[JS_SNES_RIGHT]&s?1:0) - (data[JS_SNES_LEFT]&s?1:0);
- axes[n][1] = (data[JS_SNES_DOWN] &s?1:0) - (data[JS_SNES_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_SNES_A] &s?0x01:0) | (data[JS_SNES_B] &s?0x02:0)
- | (data[JS_SNES_X] &s?0x04:0) | (data[JS_SNES_Y] &s?0x08:0)
- | (data[JS_SNES_L] &s?0x10:0) | (data[JS_SNES_R] &s?0x20:0)
- | (data[JS_SNES_START]&s?0x40:0) | (data[JS_SNES_SELECT]&s?0x80:0);
- }
- }
- }
-
-/*
- * N64 pads
- */
-
- if (info->n64) {
- if ( (info->nes || info->snes) && (info->n64 & status_bit[0]) ) {
- /* SNES/NES compatibility */
- udelay(240); /* 200 us delay + 20% tolerance */
- }
-
- js_n64_read_packet(info, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->n64 & s & ~(data[JS_N64_UNUSED1] | data[JS_N64_UNUSED2])) {
-
- buttons[n][0] = ( ((data[JS_N64_A]&s) ? 0x01:0) | ((data[JS_N64_B] & s ) ? 0x02:0)
- | ((data[JS_N64_Z]&s) ? 0x04:0) | ((data[JS_N64_L] & s ) ? 0x08:0)
- | ((data[JS_N64_R]&s) ? 0x10:0) | ((data[JS_N64_START]&s)? 0x20:0)
- | ((data[JS_N64_CU]&s)? 0x40:0) | ((data[JS_N64_CR]&s) ? 0x80:0)
- | ((data[JS_N64_CD]&s)?0x100:0) | ((data[JS_N64_CL]&s) ?0x200:0) );
-
- if (info->n64_dpp & s) {
- buttons[n][0] |= ((data[JS_N64_LEFT]&s) ? 0x400:0) | ((data[JS_N64_UP] & s)? 0x800:0)
- |((data[JS_N64_RIGHT]&s)?0x1000:0) | ((data[JS_N64_DOWN]&s)?0x2000:0);
- } else {
- axes[n][2] = (data[JS_N64_RIGHT]&s?1:0) - (data[JS_N64_LEFT]&s?1:0);
- axes[n][3] = (data[JS_N64_DOWN] &s?1:0) - (data[JS_N64_UP] &s?1:0);
- }
-
- /* build int from bits of signed 8-bit int's */
- j = 7;
- axes[n][0] = (data[JS_N64_X - j] & s) ? ~0x7f : 0;
- axes[n][1] = (data[JS_N64_Y - j] & s) ? ~0x7f : 0;
- while ( j-- > 0 ) {
- axes[n][0] |= (data[JS_N64_X - j] & s) ? (1 << j) : 0;
- axes[n][1] |= (data[JS_N64_Y - j] & s) ? (1 << j) : 0;
- }
- /* flip Y-axis for conformity */
- axes[n][1] = -axes[n][1];
-
- }
- }
- }
-
-/*
- * Multi and Multi2 joysticks
- */
-
- if (info->multi || info->multi2) {
-
- js_multi_read_packet(info, info->multi2 ? JS_MULTI2_LENGTH : JS_MULTI_LENGTH, data);
-
- for (i = 0; i < 5; i++) {
- s = status_bit[i];
- n = info->pad_to_device[i];
- if (info->multi & s) {
- axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
- axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0;
- } else
- if (info->multi2 & s) {
- axes[n][0] = (data[JS_MULTI_RIGHT]&s?1:0) - (data[JS_MULTI_LEFT]&s?1:0);
- axes[n][1] = (data[JS_MULTI_DOWN] &s?1:0) - (data[JS_MULTI_UP] &s?1:0);
-
- buttons[n][0] = (data[JS_MULTI_BUTTON]&s)?1:0 | (data[JS_MULTI_BUTTON2]&s)?2:0;
- }
- }
- }
-
-/*
- * PSX controllers
- */
-
- if (info->psx) {
-
- for ( i = 0; i < 5; i++ )
- if ( info->psx & status_bit[i] ) {
- n = info->pad_to_device[i];
- break;
- }
-
- buttons[n][0] = 0;
-
- switch (js_psx_read_packet(info, 6, data)) {
-
- case JS_PSX_ANALOGR:
-
- buttons[n][0] |= (data[0]&JS_PSX_JOYL?0:0x800) | (data[0]&JS_PSX_JOYR?0:0x400);
-
- case JS_PSX_ANALOGG:
-
- axes[n][2] = data[2];
- axes[n][3] = data[3];
- axes[n][4] = data[4];
- axes[n][5] = data[5];
-
- case JS_PSX_NORMAL:
- case JS_PSX_NEGCON:
-
- axes[n][0] = (data[0]&JS_PSX_RIGHT?0:1) - (data[0]&JS_PSX_LEFT?0:1);
- axes[n][1] = (data[0]&JS_PSX_DOWN ?0:1) - (data[0]&JS_PSX_UP ?0:1);
-
- buttons[n][0] |= ((~data[1]&0xf)<<4) | ((~data[1]&0xf0)>>4) |
- (data[0]&JS_PSX_START?0:0x200) | (data[0]&JS_PSX_SELBUT?0:0x100);
-
- break;
-
- }
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: if parport_claim() will sleep we can get into mess.
- */
-
-int js_console_open(struct js_dev *dev)
-{
- struct js_console_info *info = dev->port->info;
- if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_console_close(struct js_dev *dev)
-{
- struct js_console_info *info = dev->port->info;
- MOD_DEC_USE_COUNT;
- if (!MOD_IN_USE) parport_release(info->port);
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_console_info *info;
- int i;
-
- while (js_console_port) {
- for (i = 0; i < js_console_port->ndevs; i++)
- if (js_console_port->devs[i])
- js_unregister_device(js_console_port->devs[i]);
- info = js_console_port->info;
- parport_unregister_device(info->port);
- js_console_port = js_unregister_port(js_console_port);
- }
-}
-#endif
-
-/*
- * js_console_init_corr() initializes correction values of
- * console gamepads.
- */
-
-static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr)
-{
- int i;
-
- for (i = 0; i < num_axes; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- if (type == JS_N64_PAD || type == JS_N64_PAD_DPP) {
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 22);
- corr[i].coef[3] = (1 << 22);
- }
- }
-
- if (type == JS_PSX_ANALOGG || type == JS_PSX_ANALOGR) {
- for (i = 2; i < 6; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 127 - 2;
- corr[i].coef[1] = 128 + 2;
- corr[i].coef[2] = (1 << 29) / (127 - 4);
- corr[i].coef[3] = (1 << 29) / (127 - 4);
- }
- }
-}
-
-/*
- * js_console_probe() probes for console gamepads.
- * Only PSX pads can really be probed for.
- */
-
-static struct js_port __init *js_console_probe(int *config, struct js_port *port)
-{
- char *name[5];
- int i, psx, axes[5], buttons[5], type[5];
- unsigned char data[2]; /* used for PSX probe */
- struct js_console_info info;
- struct parport *pp;
-
- memset(&info, 0, sizeof(struct js_console_info));
-
- if (config[0] < 0) return port;
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-console: no such parport\n");
- return port;
- }
-
- info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info.port)
- return port;
-
- if (parport_claim(info.port))
- {
- parport_unregister_device(info.port); /* port currently not available ... */
- return port;
- }
-
- for (i = 0; i < 5; i++) {
-
- type[info.pads] = config[i+1];
- info.pad_to_device[i] = info.pads;
-
- switch(config[i+1]) {
-
- case JS_NO_PAD:
-
- break;
-
- case JS_SNES_PAD:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 8;
- name[info.pads] = "SNES pad";
- info.snes |= status_bit[i];
- info.pads++;
- break;
-
- case JS_NES_PAD:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 4;
- name[info.pads] = "NES pad";
- info.nes |= status_bit[i];
- info.pads++;
- break;
-
- case JS_N64_PAD:
- axes[info.pads] = 4;
- buttons[info.pads] = 10;
- name[info.pads] = "N64 pad";
- info.n64 |= status_bit[i];
- info.pads++;
- break;
-
- case JS_N64_PAD_DPP:
- axes[info.pads] = 2;
- buttons[info.pads] = 14;
- name[info.pads] = "N64 pad (DPP mode)";
- info.n64 |= status_bit[i];
- info.n64_dpp |= status_bit[i];
- info.pads++;
- break;
-
- case JS_MULTI_STICK:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 1;
- name[info.pads] = "Multisystem joystick";
- info.multi |= status_bit[i];
- info.pads++;
- break;
-
- case JS_MULTI2_STICK:
-
- axes[info.pads] = 2;
- buttons[info.pads] = 2;
- name[info.pads] = "Multisystem joystick (2 fire)";
- info.multi |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_PAD:
-
- info.psx |= status_bit[i];
- psx = js_psx_read_packet(&info, 2, data);
- psx = js_psx_read_packet(&info, 2, data);
- info.psx &= ~status_bit[i];
-
- type[i] = psx;
-
- switch(psx) {
- case JS_PSX_NORMAL:
- axes[info.pads] = 2;
- buttons[info.pads] = 10;
- name[info.pads] = "PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_ANALOGR:
- axes[info.pads] = 6;
- buttons[info.pads] = 12;
- name[info.pads] = "Analog Red PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_ANALOGG:
- axes[info.pads] = 6;
- buttons[info.pads] = 10;
- name[info.pads] = "Analog Green PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_NEGCON:
- axes[info.pads] = 2;
- buttons[info.pads] = 10;
- name[info.pads] = "NegCon PSX pad";
- info.psx |= status_bit[i];
- info.pads++;
- break;
-
- case JS_PSX_MOUSE:
- printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n");
- break;
-
- case -1:
- printk(KERN_ERR "joy-psx: no PSX controller found...\n");
- break;
-
- default:
- printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x,"
- " please report to <vojtech@suse.cz>.\n", psx);
- }
- break;
-
- default:
-
- printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
- }
- }
-
- if (!info.pads) {
- parport_release(info.port);
- parport_unregister_device(info.port);
- return port;
- }
-
- port = js_register_port(port, &info, info.pads, sizeof(struct js_console_info), js_console_read);
-
- for (i = 0; i < info.pads; i++) {
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, axes[i], buttons[i], name[i], NULL, js_console_open, js_console_close),
- name[i], info.port->port->name);
-
- js_console_init_corr(axes[i], type[i], port->corr[i]);
- }
-
- parport_release(info.port);
- return port;
-}
-
-#ifndef MODULE
-int __init js_console_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
- return 1;
-}
-int __init js_console_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console_2[i] = ints[i+1];
- return 1;
-}
-int __init js_console_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(6);
- for (i = 0; i <= ints[0] && i < 6; i++) js_console_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_console=", js_console_setup);
-__setup("js_console_2=", js_console_setup_2);
-__setup("js_console_3=", js_console_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_console_init(void)
-#endif
-{
- js_console_port = js_console_probe(js_console, js_console_port);
- js_console_port = js_console_probe(js_console_2, js_console_port);
- js_console_port = js_console_probe(js_console_3, js_console_port);
-
- if (js_console_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-console: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c
deleted file mode 100644
index b5ae4c019..000000000
--- a/drivers/char/joystick/joy-creative.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * joy-creative.c Version 1.2
- *
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Creative Labs Blaster gamepad family.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_CR_MAX_STROBE 100 /* 100 us max wait for first strobe */
-#define JS_CR_LENGTH 36
-
-#define JS_CR_MODE_BGPC 8
-
-static int js_cr_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_cr_port __initdata = NULL;
-
-struct js_cr_info {
- int io;
- unsigned char mode[2];
-};
-
-/*
- * js_cr_read_packet() reads a Blaster gamepad packet.
- */
-
-static int js_cr_read_packet(int io, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v, w;
- __u64 buf[2];
- int r[2], t[2], p[2];
- int i, j, ret;
-
- for (i = 0; i < 2; i++) {
- r[i] = buf[i] = 0;
- p[i] = t[i] = JS_CR_MAX_STROBE;
- p[i] += JS_CR_MAX_STROBE;
- }
-
- __save_flags(flags);
- __cli();
-
- u = inb(io);
-
- do {
- t[0]--; t[1]--;
- v = inb(io);
- for (i = 0, w = u ^ v; i < 2 && w; i++, w >>= 2)
- if (w & 0x30) {
- if ((w & 0x30) < 0x30 && r[i] < JS_CR_LENGTH && t[i] > 0) {
- buf[i] |= (__u64)((w >> 5) & 1) << r[i]++;
- p[i] = t[i] = (p[i] - t[i]) << 1;
- 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] != JS_CR_LENGTH) continue;
-
- for (j = 0; j < JS_CR_LENGTH && (buf[i] & 0x04104107f) ^ 0x041041040; j++)
- buf[i] = (buf[i] >> 1) | ((__u64)(buf[i] & 1) << (JS_CR_LENGTH - 1));
-
- if (j < JS_CR_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;
-}
-
-/*
- * js_cr_read() reads and analyzes Blaster gamepad data.
- */
-
-static int js_cr_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_cr_info *info = xinfo;
- unsigned int data[2];
- int i, r;
-
- if (!(r = js_cr_read_packet(info->io, data)))
- return -1;
-
- for (i = 0; i < 2; i++)
- if (r & (1 << i)) {
- switch (info->mode[i]) {
-
- case JS_CR_MODE_BGPC:
-
- axes[i][0] = ((data[i] >> 4) & 1) - ((data[i] >> 3) & 1);
- axes[i][1] = ((data[i] >> 2) & 1) - ((data[i] >> 1) & 1);
-
- buttons[i][0] = ((data[i] >> 12) & 0x007) | ((data[i] >> 6) & 0x038)
- | ((data[i] >> 1) & 0x0c0) | ((data[i] >> 7) & 0x300)
- | ((data[i] << 5) & 0xc00);
-
- break;
-
- default:
- break;
-
- }
- }
-
- return 0;
-}
-
-/*
- * js_cr_init_corr() initializes correction values of
- * Blaster gamepads.
- */
-
-static void __init js_cr_init_corr(int mode, struct js_corr *corr)
-{
- int i;
-
- switch (mode) {
-
- case JS_CR_MODE_BGPC:
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- }
-}
-
-/*
- * js_cr_probe() probes for Blaster gamepads.
- */
-
-static struct js_port __init *js_cr_probe(int io, struct js_port *port)
-{
- struct js_cr_info info;
- char *names[] = { NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, "Blaster GamePad Cobra" };
- char axes[] = { 0, 0, 0, 0, 0, 0, 0, 0, 2 };
- char buttons[] = { 0, 0, 0, 0, 0, 0, 0, 0, 12 };
- unsigned int data[2];
- int i, r;
-
- if (check_region(io, 1)) return port;
-
- info.mode[0] = info.mode[1] = 0;
-
- if (!(r = js_cr_read_packet(io, data)))
- return port;
-
- for (i = 0; i < 2; i++) {
- if (r & (1 << i)) {
- if (~data[i] & 1) {
- info.mode[i] = JS_CR_MODE_BGPC;
- } else {
- info.mode[i] = (data[i] >> 2) & 7;
- }
- if (!names[info.mode[i]]) {
- printk(KERN_WARNING "joy-creative: Unknown Creative device %d at %#x\n",
- info.mode[i], io);
- info.mode[i] = 0;
- }
- }
- }
-
- if (!info.mode[0] && !info.mode[1]) return port;
-
- info.io = io;
-
- request_region(io, 1, "joystick (creative)");
- port = js_register_port(port, &info, 2, sizeof(struct js_cr_info), js_cr_read);
-
- for (i = 0; i < 2; i++)
- if (info.mode[i]) {
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], THIS_MODULE, NULL, NULL),
- names[info.mode[i]], io);
- js_cr_init_corr(info.mode[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_cr_init(void)
-#endif
-{
- int *p;
-
- for (p = js_cr_port_list; *p; p++) js_cr_port = js_cr_probe(*p, js_cr_port);
- if (js_cr_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-creative: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_cr_info *info;
-
- while (js_cr_port) {
- for (i = 0; i < js_cr_port->ndevs; i++)
- if (js_cr_port->devs[i])
- js_unregister_device(js_cr_port->devs[i]);
- info = js_cr_port->info;
- release_region(info->io, 1);
- js_cr_port = js_unregister_port(js_cr_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-db9.c b/drivers/char/joystick/joy-db9.c
deleted file mode 100644
index 41169b12c..000000000
--- a/drivers/char/joystick/joy-db9.c
+++ /dev/null
@@ -1,421 +0,0 @@
-/*
- * joy-db9.c Version 0.6V
- *
- * Copyright (c) 1998 Andree Borrmann
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * console (Atari, Amstrad, Commodore, Amiga, Sega) joysticks
- * and gamepads connected to the parallel port.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_db9, "2i");
-MODULE_PARM(js_db9_2, "2i");
-MODULE_PARM(js_db9_3, "2i");
-
-#define JS_MULTI_STICK 0x01
-#define JS_MULTI2_STICK 0x02
-#define JS_GENESIS_PAD 0x03
-#define JS_GENESIS5_PAD 0x05
-#define JS_GENESIS6_PAD 0x06
-#define JS_SATURN_PAD 0x07
-#define JS_MULTI_0802 0x08
-#define JS_MULTI_0802_2 0x09
-#define JS_MAX_PAD 0x0A
-
-#define JS_DB9_UP 0x01
-#define JS_DB9_DOWN 0x02
-#define JS_DB9_LEFT 0x04
-#define JS_DB9_RIGHT 0x08
-#define JS_DB9_FIRE1 0x10
-#define JS_DB9_FIRE2 0x20
-#define JS_DB9_FIRE3 0x40
-#define JS_DB9_FIRE4 0x80
-
-#define JS_DB9_NORMAL 0x2a
-#define JS_DB9_NOSELECT 0x28
-
-#define JS_DB9_SATURN0 0x20
-#define JS_DB9_SATURN1 0x22
-#define JS_DB9_SATURN2 0x24
-#define JS_DB9_SATURN3 0x26
-
-#define JS_GENESIS6_DELAY 14
-
-static struct js_port* js_db9_port = NULL;
-
-static int js_db9[] __initdata = { -1, 0 };
-static int js_db9_2[] __initdata = { -1, 0 };
-static int js_db9_3[] __initdata = { -1, 0 };
-
-struct js_db9_info {
- struct pardevice *port; /* parport device */
- int mode; /* pad mode */
-};
-
-/*
- * js_db9_read() reads and analyzes db9 joystick data.
- */
-
-static int js_db9_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_db9_info *info = xinfo;
- int data;
-
- switch(info->mode)
- {
- case JS_MULTI_0802_2:
-
- data = JS_PAR_DATA_IN(info->port) >> 3;
-
- axes[1][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[1][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[1][0] = (data&JS_DB9_FIRE1?0:1);
-
- case JS_MULTI_0802:
-
- data = JS_PAR_STATUS(info->port) >> 3;
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?1:0);
-
- break;
-
- case JS_MULTI_STICK:
-
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:1);
-
- break;
-
- case JS_MULTI2_STICK:
-
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:2);
-
- break;
-
- case JS_GENESIS_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:2) | (data&JS_DB9_FIRE2?0:4);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:1) | (data&JS_DB9_FIRE2?0:8);
-
- break;
-
- case JS_GENESIS5_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08) |
- (data&JS_DB9_LEFT ?0:0x10) | (data&JS_DB9_RIGHT?0:0x20);
- break;
-
- case JS_GENESIS6_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT,info->port); /* 1 */
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- buttons[0][0] = (data&JS_DB9_FIRE1?0:0x02) | (data&JS_DB9_FIRE2?0:0x04);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_FIRE1?0:0x01) | (data&JS_DB9_FIRE2?0:0x08);
-
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 2 */
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */
- udelay(JS_GENESIS6_DELAY);
- data=JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_LEFT?0:0x10) | (data&JS_DB9_DOWN ?0:0x20) |
- (data&JS_DB9_UP ?0:0x40) | (data&JS_DB9_RIGHT?0:0x80);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 4 */
- udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
-
- break;
-
- case JS_SATURN_PAD:
-
- JS_PAR_CTRL_OUT(JS_DB9_SATURN0, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] = (data&JS_DB9_UP ?0:0x20) | (data&JS_DB9_DOWN ?0:0x10) |
- (data&JS_DB9_LEFT?0:0x08) | (data&JS_DB9_RIGHT?0:0x40);
-
- JS_PAR_CTRL_OUT(JS_DB9_SATURN2, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- axes[0][1] = (data&JS_DB9_DOWN ?0:1) - (data&JS_DB9_UP ?0:1);
- axes[0][0] = (data&JS_DB9_RIGHT?0:1) - (data&JS_DB9_LEFT?0:1);
-
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
- data = JS_PAR_DATA_IN(info->port);
-
- buttons[0][0] |= (data&JS_DB9_UP ?0:0x02) | (data&JS_DB9_DOWN ?0:0x04) |
- (data&JS_DB9_LEFT?0:0x01) | (data&JS_DB9_RIGHT?0:0x80);
-
-
- break;
-
- default:
- return -1;
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: race possible.
- */
-
-int js_db9_open(struct js_dev *dev)
-{
- struct js_db9_info *info = dev->port->info;
-
- if (!MOD_IN_USE) {
- if (parport_claim(info->port)) return -EBUSY;
-
- JS_PAR_DATA_OUT(0xff, info->port);
- if (info->mode != JS_MULTI_0802)
- JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL,info->port); /* reverse direction, enable Select signal */
- }
-
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_db9_close(struct js_dev *dev)
-{
- struct js_db9_info *info = dev->port->info;
-
- MOD_DEC_USE_COUNT;
-
- if (!MOD_IN_USE) {
-
- JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */
- if (info->mode != JS_MULTI_0802)
- JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */
-
- parport_release(info->port);
- }
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_db9_info *info;
- int i;
-
- while (js_db9_port) {
- info = js_db9_port->info;
-
- for (i = 0; i < js_db9_port->ndevs; i++)
- if (js_db9_port->devs[i])
- js_unregister_device(js_db9_port->devs[i]);
- parport_unregister_device(info->port);
- js_db9_port = js_unregister_port(js_db9_port);
- }
-
-}
-#endif
-
-/*
- * js_db9_init_corr() initializes correction values of
- * db9 gamepads.
- */
-
-static void __init js_db9_init_corr(struct js_corr *corr)
-{
- int i;
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_db9_probe() probes for db9 gamepads.
- */
-
-static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
-{
- struct js_db9_info info;
- struct parport *pp;
- int i;
- char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,8,8,1,1};
- char *name[JS_MAX_PAD] = {NULL, "Multisystem joystick", "Multisystem joystick (2 fire)", "Genesis pad",
- NULL, "Genesis 5 pad", "Genesis 6 pad", "Saturn pad", "Multisystem (0.8.0.2) joystick",
- "Multisystem (0.8.0.2-dual) joystick"};
-
- if (config[0] < 0) return port;
- if (config[1] < 0 || config[1] >= JS_MAX_PAD || !name[config[1]]) return port;
-
- info.mode = config[1];
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-db9: no such parport\n");
- return port;
- }
-
- if (!(pp->modes & (PARPORT_MODE_PCPS2 | PARPORT_MODE_PCECPPS2)) && info.mode != JS_MULTI_0802) {
- printk(KERN_ERR "js-db9: specified parport is not bidirectional\n");
- return port;
- }
-
- info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info.port)
- return port;
-
- port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read);
-
- for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, i, 2, buttons[info.mode], name[info.mode], NULL, js_db9_open, js_db9_close),
- name[info.mode], info.port->port->name);
-
- js_db9_init_corr(port->corr[i]);
- }
-
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_db9_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
- return 1;
-}
-int __init js_db9_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
- return 1;
-}
-int __init js_db9_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_db9=", js_db9_setup);
-__setup("js_db9_2=", js_db9_setup_2);
-__setup("js_db9_3=", js_db9_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_db9_init(void)
-#endif
-{
- js_db9_port = js_db9_probe(js_db9, js_db9_port);
- js_db9_port = js_db9_probe(js_db9_2, js_db9_port);
- js_db9_port = js_db9_probe(js_db9_3, js_db9_port);
-
- if (js_db9_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-db9: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c
deleted file mode 100644
index 84a6def16..000000000
--- a/drivers/char/joystick/joy-gravis.c
+++ /dev/null
@@ -1,383 +0,0 @@
-/*
- * joy-gravis.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Gravis GrIP digital joystick family.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_GR_MODE_GPP 1
-#define JS_GR_LENGTH_GPP 24
-#define JS_GR_STROBE_GPP 400
-
-#define JS_GR_MODE_XT 2
-#define JS_GR_MODE_BD 3
-#define JS_GR_LENGTH_XT 4
-#define JS_GR_STROBE_XT 200
-#define JS_GR_MAX_CHUNKS_XT 10
-#define JS_GR_MAX_BITS_XT 30
-
-static int js_gr_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_gr_port __initdata = NULL;
-
-struct js_gr_info {
- int io;
- unsigned char mode[2];
-};
-
-/*
- * js_gr_gpp_read_packet() reads a Gravis GamePad Pro packet.
- */
-
-static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
-{
- unsigned long flags;
- unsigned char u, v;
- unsigned int t, p;
- int i;
-
- i = 0;
- data[0] = 0;
- p = t = JS_GR_STROBE_GPP;
- p += JS_GR_STROBE_GPP;
-
- __save_flags(flags);
- __cli();
-
- v = inb(io) >> shift;
-
- do {
- t--;
- u = v; v = (inb(io) >> shift) & 3;
- if (~v & u & 1) {
- data[0] |= (v >> 1) << i++;
- p = t = (p - t) << 1;
- }
- } while (i < JS_GR_LENGTH_GPP && t > 0);
-
- __restore_flags(flags);
-
- if (i < JS_GR_LENGTH_GPP) return -1;
-
- for (i = 0; i < JS_GR_LENGTH_GPP && (data[0] & 0xfe4210) ^ 0x7c0000; i++)
- data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1);
-
- return -(i == JS_GR_LENGTH_GPP);
-}
-
-/*
- * js_gr_xt_read_packet() reads a Gravis Xterminator packet.
- */
-
-static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
-{
- unsigned int i, j, buf, crc;
- unsigned char u, v, w;
- unsigned long flags;
- unsigned int t, p;
- char status;
-
- data[0] = data[1] = data[2] = data[3] = 0;
- status = buf = i = j = 0;
- p = t = JS_GR_STROBE_XT;
- p += JS_GR_STROBE_XT;
-
- __save_flags(flags);
- __cli();
-
- v = w = (inb(io) >> shift) & 3;
-
- do {
- t--;
- u = (inb(io) >> shift) & 3;
-
- if (u ^ v) {
-
- if ((u ^ v) & 1) {
- p = t = (p - t) << 2;
- buf = (buf << 1) | (u >> 1);
- i++;
- } else
-
- if ((((u ^ v) & (v ^ w)) >> 1) & ~(u | v | w) & 1) {
- p = t = (p - t) << 2;
- if (i == 20) {
- crc = buf ^ (buf >> 7) ^ (buf >> 14);
- if (!((crc ^ (0x25cb9e70 >> ((crc >> 2) & 0x1c))) & 0xf)) {
- data[buf >> 18] = buf >> 4;
- status |= 1 << (buf >> 18);
- }
- j++;
- }
- buf = 0;
- i = 0;
- }
-
- w = v;
- v = u;
- }
-
- } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0);
-
- __restore_flags(flags);
-
- return -(status != 0xf);
-}
-
-/*
- * js_gr_read() reads and analyzes GrIP joystick data.
- */
-
-static int js_gr_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_gr_info *info = xinfo;
- unsigned int data[JS_GR_LENGTH_XT];
- int i;
-
- for (i = 0; i < 2; i++)
- switch (info->mode[i]) {
-
- case JS_GR_MODE_GPP:
-
- if (js_gr_gpp_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = ((data[0] >> 15) & 1) - ((data[0] >> 16) & 1);
- axes[i][1] = ((data[0] >> 13) & 1) - ((data[0] >> 12) & 1);
-
- data[0] = ((data[0] >> 6) & 0x37) | (data[0] & 0x08) | ((data[0] << 1) & 0x40) |
- ((data[0] << 5) & 0x80) | ((data[0] << 8) & 0x300);
-
- buttons[i][0] = (data[0] & 0xfc) | ((data[0] >> 1) & 0x101) | ((data[0] << 1) & 0x202);
-
- break;
-
- case JS_GR_MODE_XT:
-
- if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = (data[0] >> 2) & 0x3f;
- axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
- axes[i][2] = (data[1] >> 2) & 0x3f;
- axes[i][3] = (data[1] >> 8) & 0x3f;
- axes[i][4] = (data[2] >> 8) & 0x3f;
-
- axes[i][5] = ((data[2] >> 1) & 1) - ( data[2] & 1);
- axes[i][6] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
- axes[i][7] = ((data[2] >> 5) & 1) - ((data[2] >> 4) & 1);
- axes[i][8] = ((data[2] >> 6) & 1) - ((data[2] >> 7) & 1);
-
- buttons[i][0] = (data[3] >> 3) & 0x7ff;
-
- break;
-
- case JS_GR_MODE_BD:
-
- if (js_gr_xt_read_packet(info->io, (i << 1) + 4, data)) return -1;
-
- axes[i][0] = (data[0] >> 2) & 0x3f;
- axes[i][1] = 63 - ((data[0] >> 8) & 0x3f);
- axes[i][2] = (data[2] >> 8) & 0x3f;
-
- axes[i][3] = ((data[2] >> 1) & 1) - ( data[2] & 1);
- axes[i][4] = ((data[2] >> 2) & 1) - ((data[2] >> 3) & 1);
-
- buttons[i][0] = ((data[3] >> 6) & 0x01) | ((data[3] >> 3) & 0x06)
- | ((data[3] >> 4) & 0x18);
-
- break;
-
- default:
- break;
-
- }
-
-
- return 0;
-}
-
-/*
- * js_gr_init_corr() initializes correction values of
- * GrIP joysticks.
- */
-
-static void __init js_gr_init_corr(int mode, struct js_corr *corr)
-{
- int i;
-
- switch (mode) {
-
- case JS_GR_MODE_GPP:
-
- for (i = 0; i < 2; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- case JS_GR_MODE_XT:
-
- for (i = 0; i < 5; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 31 - 4;
- corr[i].coef[1] = 32 + 4;
- corr[i].coef[2] = (1 << 29) / (32 - 14);
- corr[i].coef[3] = (1 << 29) / (32 - 14);
- }
-
- for (i = 5; i < 9; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- case JS_GR_MODE_BD:
-
- for (i = 0; i < 3; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 31 - 4;
- corr[i].coef[1] = 32 + 4;
- corr[i].coef[2] = (1 << 29) / (32 - 14);
- corr[i].coef[3] = (1 << 29) / (32 - 14);
- }
-
- for (i = 3; i < 5; i++) {
- corr[i].type = JS_CORR_BROKEN;
- corr[i].prec = 0;
- corr[i].coef[0] = 0;
- corr[i].coef[1] = 0;
- corr[i].coef[2] = (1 << 29);
- corr[i].coef[3] = (1 << 29);
- }
-
- break;
-
- }
-}
-
-/*
- * js_gr_probe() probes for GrIP joysticks.
- */
-
-static struct js_port __init *js_gr_probe(int io, struct js_port *port)
-{
- struct js_gr_info info;
- char *names[] = { NULL, "Gravis GamePad Pro", "Gravis Xterminator", "Gravis Blackhawk Digital"};
- char axes[] = { 0, 2, 9, 5};
- char buttons[] = { 0, 10, 11, 5};
- unsigned int data[JS_GR_LENGTH_XT];
- int i;
-
- if (check_region(io, 1)) return port;
-
- info.mode[0] = info.mode[1] = 0;
-
- for (i = 0; i < 2; i++) {
- if (!js_gr_gpp_read_packet(io, (i << 1) + 4, data)) info.mode[i] = JS_GR_MODE_GPP;
- if (!js_gr_xt_read_packet(io, (i << 1) + 4, data)) {
- if ((data[3] & 7) == 7)
- info.mode[i] = JS_GR_MODE_XT;
- if ((data[3] & 7) == 0)
- info.mode[i] = JS_GR_MODE_BD;
- }
- }
-
- if (!info.mode[0] && !info.mode[1]) return port;
-
- info.io = io;
-
- request_region(io, 1, "joystick (gravis)");
- port = js_register_port(port, &info, 2, sizeof(struct js_gr_info), js_gr_read);
-
- for (i = 0; i < 2; i++)
- if (info.mode[i]) {
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, i, axes[info.mode[i]], buttons[info.mode[i]],
- names[info.mode[i]], THIS_MODULE, NULL, NULL),
- names[info.mode[i]], io);
- js_gr_init_corr(info.mode[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_gr_init(void)
-#endif
-{
- int *p;
-
- for (p = js_gr_port_list; *p; p++) js_gr_port = js_gr_probe(*p, js_gr_port);
- if (js_gr_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-gravis: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_gr_info *info;
-
- while (js_gr_port) {
- for (i = 0; i < js_gr_port->ndevs; i++)
- if (js_gr_port->devs[i])
- js_unregister_device(js_gr_port->devs[i]);
- info = js_gr_port->info;
- release_region(info->io, 1);
- js_gr_port = js_unregister_port(js_gr_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c
deleted file mode 100644
index 26c18856a..000000000
--- a/drivers/char/joystick/joy-lightning.c
+++ /dev/null
@@ -1,351 +0,0 @@
-/*
- * joy-lightning.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * PDPI Lightning 4 gamecards and analog joysticks connected
- * to them.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_L4_PORT 0x201
-#define JS_L4_SELECT_ANALOG 0xa4
-#define JS_L4_SELECT_DIGITAL 0xa5
-#define JS_L4_SELECT_SECONDARY 0xa6
-#define JS_L4_CMD_ID 0x80
-#define JS_L4_CMD_GETCAL 0x92
-#define JS_L4_CMD_SETCAL 0x93
-#define JS_L4_ID 0x04
-#define JS_L4_BUSY 0x01
-#define JS_L4_TIMEOUT 80 /* 80 us */
-
-static struct js_port* __initdata js_l4_port = NULL;
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_l4, "2-24i");
-
-static int __initdata js_l4[] = { -1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0,-1,0,0 };
-
-#include "joy-analog.h"
-
-struct js_l4_info {
- int port;
- struct js_an_info an;
-};
-
-/*
- * js_l4_wait_ready() waits for the L4 to become ready.
- */
-
-static int js_l4_wait_ready(void)
-{
- unsigned int t;
- t = JS_L4_TIMEOUT;
- while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
- return -(t<=0);
-}
-
-/*
- * js_l4_read() reads data from the Lightning 4.
- */
-
-static int js_l4_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_l4_info *info = xinfo;
- int i;
- unsigned char status;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (info->port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(info->port & 3, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- status = inb(JS_L4_PORT);
-
- for (i = 0; i < 4; i++)
- if (status & (1 << i)) {
- if (js_l4_wait_ready()) return -1;
- info->an.axes[i] = inb(JS_L4_PORT);
- }
-
- if (status & 0x10) {
- if (js_l4_wait_ready()) return -1;
- info->an.buttons = inb(JS_L4_PORT);
- }
-
- js_an_decode(&info->an, axes, buttons);
-
- return 0;
-}
-
-/*
- * js_l4_getcal() reads the L4 with calibration values.
- */
-
-static int js_l4_getcal(int port, int *cal)
-{
- int i;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(JS_L4_CMD_GETCAL, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
-
- if (js_l4_wait_ready()) return -1;
- outb(port & 3, JS_L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (js_l4_wait_ready()) return -1;
- cal[i] = inb(JS_L4_PORT);
- }
-
- return 0;
-}
-
-/*
- * js_l4_setcal() programs the L4 with calibration values.
- */
-
-static int js_l4_setcal(int port, int *cal)
-{
- int i;
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + (port >> 2), JS_L4_PORT);
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) return -1;
- outb(JS_L4_CMD_SETCAL, JS_L4_PORT);
-
- if (js_l4_wait_ready()) return -1;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + (port >> 2)) return -1;
-
- if (js_l4_wait_ready()) return -1;
- outb(port & 3, JS_L4_PORT);
-
- for (i = 0; i < 4; i++) {
- if (js_l4_wait_ready()) return -1;
- outb(cal[i], JS_L4_PORT);
- }
-
- return 0;
-}
-
-/*
- * js_l4_calibrate() calibrates the L4 for the attached device, so
- * that the device's resistance fits into the L4's 8-bit range.
- */
-
-static void js_l4_calibrate(struct js_l4_info *info)
-{
- int i;
- int cal[4];
- int axes[4];
- int t;
-
- js_l4_getcal(info->port, cal);
-
- for (i = 0; i < 4; i++)
- axes[i] = info->an.axes[i];
-
- if ((info->an.extensions & JS_AN_BUTTON_PXY_X) && !(info->an.extensions & JS_AN_BUTTON_PXY_U))
- axes[2] >>= 1; /* Pad button X */
-
- if ((info->an.extensions & JS_AN_BUTTON_PXY_Y) && !(info->an.extensions & JS_AN_BUTTON_PXY_V))
- axes[3] >>= 1; /* Pad button Y */
-
- if (info->an.extensions & JS_AN_HAT_FCS)
- axes[3] >>= 1; /* FCS hat */
-
- if (((info->an.mask[0] & 0xb) == 0xb) || ((info->an.mask[1] & 0xb) == 0xb))
- axes[3] = (axes[0] + axes[1]) >> 1; /* Throttle */
-
- for (i = 0; i < 4; i++) {
- t = (axes[i] * cal[i]) / 100;
- if (t > 255) t = 255;
- info->an.axes[i] = (info->an.axes[i] * cal[i]) / t;
- cal[i] = t;
- }
-
- js_l4_setcal(info->port, cal);
-}
-
-/*
- * js_l4_probe() probes for joysticks on the L4 cards.
- */
-
-static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int mask0, int mask1, struct js_port *port)
-{
- struct js_l4_info iniinfo;
- struct js_l4_info *info = &iniinfo;
- int cal[4] = {255,255,255,255};
- int i, numdev;
- unsigned char u;
-
- if (l4port < 0) return port;
- if (!cards[(l4port >> 2)]) return port;
-
- memset(info, 0, sizeof(struct js_l4_info));
- info->port = l4port;
-
- if (cards[l4port >> 2] > 0x28) js_l4_setcal(info->port, cal);
- if (js_l4_read(info, NULL, NULL)) return port;
-
- for (i = u = 0; i < 4; i++) if (info->an.axes[i] < 253) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);
-
- info = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_INFO "js%d: %s on L4 port %d\n",
- js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL),
- js_an_name(i, &info->an), info->port);
-
- js_l4_calibrate(info);
- js_l4_read(info, port->axes, port->buttons);
- js_an_init_corr(&info->an, port->axes, port->corr, 0);
-
- return port;
-}
-
-/*
- * js_l4_card_probe() probes for presence of the L4 card(s).
- */
-
-static void __init js_l4_card_probe(unsigned char *cards)
-{
- int i;
- unsigned char rev = 0;
-
- if (check_region(JS_L4_PORT, 1)) return;
-
- for (i = 0; i < 2; i++) {
-
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- outb(JS_L4_SELECT_DIGITAL + i, JS_L4_PORT); /* Select card 0-1 */
-
- if (inb(JS_L4_PORT) & JS_L4_BUSY) continue;
- outb(JS_L4_CMD_ID, JS_L4_PORT); /* Get card ID & rev */
-
- if (js_l4_wait_ready()) continue;
- if (inb(JS_L4_PORT) != JS_L4_SELECT_DIGITAL + i) continue;
-
- if (js_l4_wait_ready()) continue;
- if (inb(JS_L4_PORT) != JS_L4_ID) continue;
-
- if (js_l4_wait_ready()) continue;
- rev = inb(JS_L4_PORT);
-
- cards[i] = rev;
-
- printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d at %#x\n",
- i ? "secondary" : "primary", (i << 2), (i << 2) + 3, rev >> 4, rev & 0xf, JS_L4_PORT);
- }
-
-}
-
-#ifndef MODULE
-int __init js_l4_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(24);
- for (i = 0; i <= ints[0] && i < 24; i++) js_l4[i] = ints[i+1];
- return 1;
-}
-__setup("js_l4=", js_l4_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_l4_init(void)
-#endif
-{
- int i;
- unsigned char cards[2] = {0, 0};
-
- js_l4_card_probe(cards);
-
- if (js_l4[0] >= 0) {
- for (i = 0; (js_l4[i*3] >= 0) && i < 8; i++)
- js_l4_port = js_l4_probe(cards, js_l4[i*3], js_l4[i*3+1], js_l4[i*3+2], js_l4_port);
- } else {
- for (i = 0; i < 8; i++)
- js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
- }
-
- if (!js_l4_port) {
-#ifdef MODULE
- printk(KERN_WARNING "joy-lightning: no joysticks found\n");
-#endif
- return -ENODEV;
- }
-
- request_region(JS_L4_PORT, 1, "joystick (lightning)");
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- int cal[4] = {59, 59, 59, 59};
- struct js_l4_info *info;
-
- while (js_l4_port) {
- for (i = 0; i < js_l4_port->ndevs; i++)
- if (js_l4_port->devs[i])
- js_unregister_device(js_l4_port->devs[i]);
- info = js_l4_port->info;
- js_l4_setcal(info->port, cal);
- js_l4_port = js_unregister_port(js_l4_port);
- }
- outb(JS_L4_SELECT_ANALOG, JS_L4_PORT);
- release_region(JS_L4_PORT, 1);
-}
-#endif
diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c
deleted file mode 100644
index 6044cbfb0..000000000
--- a/drivers/char/joystick/joy-logitech.c
+++ /dev/null
@@ -1,534 +0,0 @@
-/*
- * joy-logitech.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Logitech ADI joystick family.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/malloc.h>
-#include <linux/init.h>
-
-/*
- * Times array sizes, flags, ids.
- */
-
-#undef JS_LT_DEBUG
-
-#define JS_LT_MAX_START 400 /* Trigger to packet timeout [400us] */
-
-#define JS_LT_MAX_LENGTH 256
-#define JS_LT_MIN_LENGTH 8
-#define JS_LT_MIN_LEN_LENGTH 10
-#define JS_LT_MIN_ID_LENGTH 66
-#define JS_LT_MAX_NAME_LENGTH 16
-
-#define JS_LT_INIT_DELAY 10 /* Delay after init packet [10ms] */
-#define JS_LT_DATA_DELAY 4 /* Delay after data packet [4ms] */
-
-#define JS_LT_FLAG_HAT 0x04
-#define JS_LT_FLAG_10BIT 0x08
-
-#define JS_LT_ID_WMED 0x00
-#define JS_LT_ID_TPD 0x01
-#define JS_LT_ID_WMI 0x04
-#define JS_LT_ID_WGP 0x06
-#define JS_LT_ID_WM3D 0x07
-#define JS_LT_ID_WGPE 0x08
-
-#define JS_LT_BUG_BUTTONS 0x01
-#define JS_LT_BUG_LONGID 0x02
-#define JS_LT_BUG_LONGDATA 0x04
-#define JS_LT_BUG_IGNTRIG 0x08
-
-/*
- * Port probing variables.
- */
-
-static int js_lt_port_list[] __initdata = { 0x201, 0 };
-static struct js_port* js_lt_port __initdata = NULL;
-
-/*
- * Device names.
- */
-
-#define JS_LT_MAX_ID 10
-
-static char *js_lt_names[] = { "WingMan Extreme Digital", "ThunderPad Digital", "SideCar", "CyberMan 2",
- "WingMan Interceptor", "WingMan Formula", "WingMan GamePad",
- "WingMan Extreme Digital 3D", "WingMan GamePad Extreme",
- "WingMan GamePad USB", "Unknown Device %#x"};
-
-/*
- * Hat to axis conversion arrays.
- */
-
-static struct {
- int x;
- int y;
-} js_lt_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-/*
- * Per-port information.
- */
-
-struct js_lt_info {
- int io;
- int length[2];
- int ret[2];
- int idx[2];
- unsigned char id[2];
- char buttons[2];
- char axes10[2];
- char axes8[2];
- char pad[2];
- char hats[2];
- char name[2][JS_LT_MAX_NAME_LENGTH];
- unsigned char data[2][JS_LT_MAX_LENGTH];
- char bugs[2];
-};
-
-/*
- * js_lt_read_packet() reads a Logitech ADI packet.
- */
-
-static void js_lt_read_packet(struct js_lt_info *info)
-{
- unsigned char u, v, w, x, z;
- int t[2], s[2], p[2], i;
- unsigned long flags;
-
- for (i = 0; i < 2; i++) {
- info->ret[i] = -1;
- p[i] = t[i] = JS_LT_MAX_START;
- s[i] = 0;
- }
-
- __save_flags(flags);
- __cli();
-
- outb(0xff, info->io);
- v = z = inb(info->io);
-
- do {
- u = v;
- w = u ^ (v = x = inb(info->io));
- for (i = 0; i < 2; i++, w >>= 2, x >>= 2) {
- t[i]--;
- if ((w & 0x30) && s[i]) {
- if ((w & 0x30) < 0x30 && info->ret[i] < JS_LT_MAX_LENGTH && t[i] > 0) {
- info->data[i][++info->ret[i]] = w;
- p[i] = t[i] = (p[i] - t[i]) << 1;
- } else t[i] = 0;
- } else if (!(x & 0x30)) s[i] = 1;
- }
- } while (t[0] > 0 || t[1] > 0);
-
- __restore_flags(flags);
-
- for (i = 0; i < 2; i++, z >>= 2)
- if ((z & 0x30) && info->ret[i] > 0)
- info->bugs[i] |= JS_LT_BUG_BUTTONS;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: read %d %d bits\n", info->ret[0], info->ret[1]);
- printk(KERN_DEBUG "joy-logitech: stream0:");
- for (i = 0; i <= info->ret[0]; i++) printk("%d", (info->data[0][i] >> 5) & 1);
- printk("\n");
- printk(KERN_DEBUG "joy-logitech: stream1:");
- for (i = 0; i <= info->ret[1]; i++) printk("%d", (info->data[1][i] >> 5) & 1);
- printk("\n");
-#endif
-
- return;
-}
-
-/*
- * js_lt_move_bits() detects a possible 2-stream mode, and moves
- * the bits accordingly.
- */
-
-static void js_lt_move_bits(struct js_lt_info *info, int length)
-{
- int i;
-
- info->idx[0] = info->idx[1] = 0;
-
- if (info->ret[0] <= 0 || info->ret[1] <= 0) return;
- if (info->data[0][0] & 0x20 || ~info->data[1][0] & 0x20) return;
-
- for (i = 1; i <= info->ret[1]; i++)
- info->data[0][((length - 1) >> 1) + i + 1] = info->data[1][i];
-
- info->ret[0] += info->ret[1];
- info->ret[1] = -1;
-}
-
-/*
- * js_lt_get_bits() gathers bits from the data packet.
- */
-
-static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count)
-{
- int bits = 0;
- int i;
- if ((info->idx[device] += count) > info->ret[device]) return 0;
- for (i = 0; i < count; i++) bits |= ((info->data[device][info->idx[device] - i] >> 5) & 1) << i;
- return bits;
-}
-
-/*
- * js_lt_read() reads and analyzes Logitech joystick data.
- */
-
-static int js_lt_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_lt_info *info = xinfo;
- int i, j, k, l, t;
- int ret = 0;
-
- js_lt_read_packet(info);
- js_lt_move_bits(info, info->length[0]);
-
- for (i = 0; i < 2; i++) {
-
- if (!info->length[i]) continue;
-
- if (info->length[i] > info->ret[i] ||
- info->id[i] != (js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4))) {
- ret = -1;
- continue;
- }
-
- if (info->length[i] < info->ret[i])
- info->bugs[i] |= JS_LT_BUG_LONGDATA;
-
- k = l = 0;
-
- for (j = 0; j < info->axes10[i]; j++)
- axes[i][k++] = js_lt_get_bits(info, i, 10);
-
- for (j = 0; j < info->axes8[i]; j++)
- axes[i][k++] = js_lt_get_bits(info, i, 8);
-
- for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0;
-
- for (j = 0; j < info->buttons[i] && j < 63; j++) {
- if (j == info->pad[i]) {
- t = js_lt_get_bits(info, i, 4);
- axes[i][k++] = ((t >> 2) & 1) - ( t & 1);
- axes[i][k++] = ((t >> 1) & 1) - ((t >> 3) & 1);
- }
- buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
- l++;
- }
-
- for (j = 0; j < info->hats[i]; j++) {
- if((t = js_lt_get_bits(info, i, 4)) > 8) {
- if (t != 15) ret = -1; /* Hat press */
- t = 0;
- }
- axes[i][k++] = js_lt_hat_to_axis[t].x;
- axes[i][k++] = js_lt_hat_to_axis[t].y;
- }
-
- for (j = 63; j < info->buttons[i]; j++) {
- buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
- l++;
- }
- }
-
- return ret;
-}
-
-/*
- * js_lt_init_digital() sends a trigger & delay sequence
- * to reset and initialize a Logitech joystick into digital mode.
- */
-
-static void __init js_lt_init_digital(int io)
-{
- int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 };
- int i;
-
- for (i = 0; seq[i]; i++) {
- outb(0xff,io);
- mdelay(seq[i]);
- }
-}
-
-/*
- * js_lt_init_corr() initializes the correction values for
- * Logitech joysticks.
- */
-
-static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr)
-{
- int j;
-
- if (id == JS_LT_ID_WMED) axes[2] = 128; /* Throttle fixup */
- if (id == JS_LT_ID_WMI) axes[2] = 512;
- if (id == JS_LT_ID_WM3D) axes[3] = 128;
-
- if (id == JS_LT_ID_WGPE) { /* Tilt fixup */
- axes[0] = 512;
- axes[1] = 512;
- }
-
- for (j = 0; j < naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 2;
- corr[j].coef[0] = axes[j] - 16;
- corr[j].coef[1] = axes[j] + 16;
- corr[j].coef[2] = (1 << 29) / (256 - 32);
- corr[j].coef[3] = (1 << 29) / (256 - 32);
- }
-
- for (; j < naxes8 + naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 1;
- corr[j].coef[0] = axes[j] - 2;
- corr[j].coef[1] = axes[j] + 2;
- corr[j].coef[2] = (1 << 29) / (64 - 16);
- corr[j].coef[3] = (1 << 29) / (64 - 16);
- }
-
- for (; j < naxes1 + naxes8 + naxes10; j++) {
- corr[j].type = JS_CORR_BROKEN;
- corr[j].prec = 0;
- corr[j].coef[0] = 0;
- corr[j].coef[1] = 0;
- corr[j].coef[2] = (1 << 29);
- corr[j].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_lt_probe() probes for Logitech type joysticks.
- */
-
-static struct js_port __init *js_lt_probe(int io, struct js_port *port)
-{
- struct js_lt_info iniinfo;
- struct js_lt_info *info = &iniinfo;
- char name[32];
- int i, j, t;
-
- if (check_region(io, 1)) return port;
-
- js_lt_init_digital(io);
-
- memset(info, 0, sizeof(struct js_lt_info));
-
- info->length[0] = info->length[1] = JS_LT_MAX_LENGTH;
-
- info->io = io;
- js_lt_read_packet(info);
-
- if (info->ret[0] >= JS_LT_MIN_LEN_LENGTH)
- js_lt_move_bits(info, js_lt_get_bits(info, 0, 10));
-
- info->length[0] = info->length[1] = 0;
-
- for (i = 0; i < 2; i++) {
-
- if (info->ret[i] < JS_LT_MIN_ID_LENGTH) continue; /* Minimum ID packet length */
-
- if (info->ret[i] < (t = js_lt_get_bits(info, i, 10))) {
- printk(KERN_WARNING "joy-logitech: Short ID packet: reported: %d != read: %d\n",
- t, info->ret[i]);
- continue;
- }
-
- if (info->ret[i] > t)
- info->bugs[i] |= JS_LT_BUG_LONGID;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: id %d length %d", i, t);
-#endif
-
- info->id[i] = js_lt_get_bits(info, i, 4) | (js_lt_get_bits(info, i, 4) << 4);
-
- if ((t = js_lt_get_bits(info, i, 4)) & JS_LT_FLAG_HAT) info->hats[i]++;
-
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "joy-logitech: id %d flags %d", i, t);
-#endif
-
- if ((info->length[i] = js_lt_get_bits(info, i, 10)) >= JS_LT_MAX_LENGTH) {
- printk(KERN_WARNING "joy-logitech: Expected packet length too long (%d).\n",
- info->length[i]);
- continue;
- }
-
- if (info->length[i] < JS_LT_MIN_LENGTH) {
- printk(KERN_WARNING "joy-logitech: Expected packet length too short (%d).\n",
- info->length[i]);
- continue;
- }
-
- info->axes8[i] = js_lt_get_bits(info, i, 4);
- info->buttons[i] = js_lt_get_bits(info, i, 6);
-
- if (js_lt_get_bits(info, i, 6) != 8 && info->hats[i]) {
- printk(KERN_WARNING "joy-logitech: Other than 8-dir POVs not supported yet.\n");
- continue;
- }
-
- info->buttons[i] += js_lt_get_bits(info, i, 6);
- info->hats[i] += js_lt_get_bits(info, i, 4);
-
- j = js_lt_get_bits(info, i, 4);
-
- if (t & JS_LT_FLAG_10BIT) {
- info->axes10[i] = info->axes8[i] - j;
- info->axes8[i] = j;
- }
-
- t = js_lt_get_bits(info, i, 4);
-
- for (j = 0; j < t; j++)
- info->name[i][j] = js_lt_get_bits(info, i, 8);
- info->name[i][j] = 0;
-
- switch (info->id[i]) {
- case JS_LT_ID_TPD:
- info->pad[i] = 4;
- info->buttons[i] -= 4;
- break;
- case JS_LT_ID_WGP:
- info->pad[i] = 0;
- info->buttons[i] -= 4;
- break;
- default:
- info->pad[i] = -1;
- break;
- }
-
- if (info->length[i] !=
- (t = 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
- info->hats[i] * 4 + (info->pad[i] != -1) * 4)) {
- printk(KERN_WARNING "js%d: Expected lenght %d != data length %d\n", i, t, info->length[i]);
- }
-
- }
-
- if (!info->length[0] && !info->length[1])
- return port;
-
- request_region(io, 1, "joystick (logitech)");
-
- port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read);
- info = port->info;
-
- for (i = 0; i < 2; i++)
- if (info->length[i] > 0) {
- sprintf(name, info->id[i] < JS_LT_MAX_ID ?
- js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]);
- printk(KERN_INFO "js%d: %s [%s] at %#x\n",
- js_register_device(port, i,
- info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
- info->buttons[i], name, THIS_MODULE, NULL, NULL), name, info->name[i], io);
- }
-
- mdelay(JS_LT_INIT_DELAY);
- if (js_lt_read(info, port->axes, port->buttons)) {
- if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG;
- if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG;
- mdelay(JS_LT_DATA_DELAY);
- js_lt_read(info, port->axes, port->buttons);
- }
-
- for (i = 0; i < 2; i++)
- if (info->length[i] > 0) {
-#ifdef JS_LT_DEBUG
- printk(KERN_DEBUG "js%d: length %d ret %d id %d buttons %d axes10 %d axes8 %d "
- "pad %d hats %d name %s explen %d\n",
- i, info->length[i], info->ret[i], info->id[i],
- info->buttons[i], info->axes10[i], info->axes8[i],
- info->pad[i], info->hats[i], info->name[i],
- 8 + info->buttons[i] + info->axes10[i] * 10 + info->axes8[i] * 8 +
- info->hats[i] * 4 + (info->pad[i] != -1) * 4);
-#endif
- if (info->bugs[i]) {
- printk(KERN_WARNING "js%d: Firmware bugs detected:%s%s%s%s\n", i,
- info->bugs[i] & JS_LT_BUG_BUTTONS ? " init_buttons" : "",
- info->bugs[i] & JS_LT_BUG_LONGID ? " long_id" : "",
- info->bugs[i] & JS_LT_BUG_LONGDATA ? " long_data" : "",
- info->bugs[i] & JS_LT_BUG_IGNTRIG ? " ignore_trigger" : "");
- }
- js_lt_init_corr(info->id[i], info->axes10[i], info->axes8[i],
- ((info->pad[i] >= 0) + info->hats[i]) << 1, port->axes[i], port->corr[i]);
- }
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_lt_init(void)
-#endif
-{
- int *p;
-
- for (p = js_lt_port_list; *p; p++) js_lt_port = js_lt_probe(*p, js_lt_port);
- if (js_lt_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-logitech: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_lt_info *info;
-
- while (js_lt_port) {
- for (i = 0; i < js_lt_port->ndevs; i++)
- if (js_lt_port->devs[i])
- js_unregister_device(js_lt_port->devs[i]);
- info = js_lt_port->info;
- release_region(info->io, 1);
- js_lt_port = js_unregister_port(js_lt_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-magellan.c b/drivers/char/joystick/joy-magellan.c
deleted file mode 100644
index cb14646e8..000000000
--- a/drivers/char/joystick/joy-magellan.c
+++ /dev/null
@@ -1,395 +0,0 @@
-/*
- * joy-magellan.c Version 0.1
- *
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the Magellan and Space Mouse 6dof controllers.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_MAG 14
-#define JS_MAG_MAX_LENGTH 64
-
-/*
- * List of Magellans.
- */
-
-static struct js_port* js_mag_port = NULL;
-
-/*
- * Per-Magellan data.
- */
-
-struct js_mag_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_MAG_MAX_LENGTH];
- unsigned char name[JS_MAG_MAX_LENGTH];
- char ack;
- char used;
-};
-
-/*
- * js_mag_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 js_mag_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;
-}
-
-/*
- * js_mag_process_packet() decodes packets the driver receives from the
- * Magellan. It updates the data accordingly, and sets an ACK flag
- * to the type of last packet received, if received OK.
- */
-
-static void js_mag_process_packet(struct js_mag_info* info)
-{
- int i;
-
- if (!info->idx) return;
-
- switch (info->data[0]) {
-
- case 'd': /* Axis data */
- if (info->idx != 25) return;
- if (js_mag_crunch_nibbles(info->data, 24)) return;
- if (!info->port->devs[0]) return;
- for (i = 0; i < 6; i++) {
- info->port->axes[0][i] =
- ( info->data[(i << 2) + 1] << 12 | info->data[(i << 2) + 2] << 8 |
- info->data[(i << 2) + 3] << 4 | info->data[(i << 2) + 4] )
- - 32768;
- }
- break;
-
- case 'e': /* Error packet */
- if (info->idx != 4) return;
- if (js_mag_crunch_nibbles(info->data, 3)) return;
- switch (info->data[1]) {
- case 1:
- printk(KERN_ERR "joy-magellan: Received command error packet. Failing command byte: %c\n",
- info->data[2] | (info->data[3] << 4));
- break;
- case 2:
- printk(KERN_ERR "joy-magellan: Received framing error packet.\n");
- break;
- default:
- printk(KERN_ERR "joy-magellan: Received unknown error packet.\n");
- }
- break;
-
- case 'k': /* Button data */
- if (info->idx != 4) return;
- if (js_mag_crunch_nibbles(info->data, 3)) return;
- if (!info->port->devs[0]) return;
- info->port->buttons[0][0] = (info->data[1] << 1) | (info->data[2] << 5) | info->data[3];
- break;
-
- case 'm': /* Mode */
- if (info->idx != 2) return;
- if (js_mag_crunch_nibbles(info->data, 1)) return;
- break;
-
- case 'n': /* Null radius */
- if (info->idx != 2) return;
- if (js_mag_crunch_nibbles(info->data, 1)) return;
- break;
-
- case 'p': /* Data rate */
- if (info->idx != 3) return;
- if (js_mag_crunch_nibbles(info->data, 2)) return;
- break;
-
- case 'q': /* Sensitivity */
- if (info->idx != 3) return;
- if (js_mag_crunch_nibbles(info->data, 2)) return;
- break;
-
- case 'v': /* Version string */
- info->data[info->idx] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
- memcpy(info->name, info->data + i, info->idx - i);
- break;
-
- case 'z': /* Zero position */
- break;
-
- default:
- printk("joy-magellan: Unknown packet %d length %d:", info->data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", info->data[i]);
- printk("\n");
- return;
- }
-
- info->ack = info->data[0];
-}
-
-/*
- * js_mag_command() sends a command to the Magellan, and waits for
- * acknowledge.
- */
-
-static int js_mag_command(struct js_mag_info *info, char *command, int timeout)
-{
- info->ack = 0;
- if (info->tty->driver.write(info->tty, 0, command, strlen(command)) != strlen(command)) return -1;
- while (!info->ack && timeout--) mdelay(1);
- return -(info->ack != command[0]);
-}
-
-/*
- * js_mag_setup() initializes the Magellan to sane state. Also works as
- * a probe for Magellan existence.
- */
-
-static int js_mag_setup(struct js_mag_info *info)
-{
-
- if (js_mag_command(info, "vQ\r", 800)) /* Read version */
- return -1;
- if (js_mag_command(info, "m3\r", 50)) /* Set full 3d mode */
- return -1;
- if (js_mag_command(info, "pBB\r", 50)) /* Set 16 reports/second (max) */
- return -1;
- if (js_mag_command(info, "z\r", 50)) /* Set zero position */
- return -1;
-
- return 0;
-}
-
-/*
- * js_mag_read() updates the axis and button data upon startup.
- */
-
-static int js_mag_read(struct js_mag_info *info)
-{
- memset(info->port->axes[0],0, sizeof(int) * 6); /* Axes are 0 after zero postition cmd */
-
- if (js_mag_command(info, "kQ\r", 50)) /* Read buttons */
- return -1;
-
- return 0;
-}
-
-/*
- * js_mag_open() is a callback from the joystick device open routine.
- */
-
-static int js_mag_open(struct js_dev *jd)
-{
- struct js_mag_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_mag_close() is a callback from the joystick device release routine.
- */
-
-static int js_mag_close(struct js_dev *jd)
-{
- struct js_mag_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_mag_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_mag_init_corr() initializes the correction values for the Magellan.
- * It asumes gain setting of 0, question is, what we should do for higher
- * gain settings ...
- */
-
-static void js_mag_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29) / 256;
- corr[0][i].coef[3] = (1 << 29) / 256;
- }
-}
-
-/*
- * js_mag_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty. It looks for the Magellan, and if found, registers
- * it as a joystick device.
- */
-
-static int js_mag_ldisc_open(struct tty_struct *tty)
-{
- struct js_mag_info iniinfo;
- struct js_mag_info *info = &iniinfo;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_mag_port = js_register_port(js_mag_port, info, 1, sizeof(struct js_mag_info), NULL);
-
- info = js_mag_port->info;
- info->port = js_mag_port;
- tty->disc_data = info;
-
- if (js_mag_setup(info)) {
- js_mag_port = js_unregister_port(info->port);
- return -ENODEV;
- }
-
- printk(KERN_INFO "js%d: Magellan [%s] on %s%d\n",
- js_register_device(js_mag_port, 0, 6, 9, "Magellan", THIS_MODULE, js_mag_open, js_mag_close),
- info->name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
-
-
- js_mag_read(info);
- js_mag_init_corr(js_mag_port->corr);
-
- MOD_INC_USE_COUNT;
-
- return 0;
-}
-
-/*
- * js_mag_ldisc_close() is the opposite of js_mag_ldisc_open()
- */
-
-static void js_mag_ldisc_close(struct tty_struct *tty)
-{
- struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_mag_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_mag_ldisc_receive() 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 js_mag_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_mag_info* info = (struct js_mag_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++)
- if (cp[i] == '\r') {
- js_mag_process_packet(info);
- info->idx = 0;
- } else {
- if (info->idx < JS_MAG_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
- }
-}
-
-/*
- * js_mag_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, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_mag_ldisc_room(struct tty_struct *tty)
-{
- return JS_MAG_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_mag_ldisc = {
- magic: TTY_LDISC_MAGIC,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- name: "magellan",
-#endif
- open: js_mag_ldisc_open,
- close: js_mag_ldisc_close,
- receive_buf: js_mag_ldisc_receive,
- receive_room: js_mag_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_mag_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_MAG, &js_mag_ldisc)) {
- printk(KERN_ERR "joy-magellan: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_MAG, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-pci.c b/drivers/char/joystick/joy-pci.c
deleted file mode 100644
index fbf9125e5..000000000
--- a/drivers/char/joystick/joy-pci.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * joy-pci.c Version 0.4.0
- *
- * Copyright (c) 1999 Raymond Ingles
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting the
- * gameports on Trident 4DWave and Aureal Vortex soundcards, and
- * analog joysticks connected to them.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@ucw.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/pci.h>
-#include <linux/pci_ids.h>
-#include <linux/init.h>
-
-MODULE_AUTHOR("Raymond Ingles <sorceror@tir.com>");
-MODULE_PARM(js_pci, "3-32i");
-
-#define NUM_CARDS 8
-static int js_pci[NUM_CARDS * 4] __initdata = { -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0,
- -1,0,0,0,-1,0,0,0,-1,0,0,0,-1,0,0,0 };
-
-static struct js_port * js_pci_port __initdata = NULL;
-
-#include "joy-analog.h"
-
-struct js_pci_info;
-typedef void (*js_pci_func)(struct js_pci_info *);
-
-struct js_pci_data {
- int vendor; /* PCI Vendor ID */
- int model; /* PCI Model ID */
- int size; /* Memory / IO region size */
- int lcr; /* Aureal Legacy Control Register */
- int gcr; /* Gameport control register */
- int buttons; /* Buttons location */
- int axes; /* Axes start */
- int axsize; /* Axis field size */
- int axmax; /* Axis field max value */
- js_pci_func init;
- js_pci_func cleanup;
- char *name;
-};
-
-struct js_pci_info {
- unsigned char *base;
- struct pci_dev *pci_p;
- __u32 lcr;
- struct js_pci_data *data;
- struct js_an_info an;
-};
-
-/*
- * js_pci_*_init() sets the info->base field, disables legacy gameports,
- * and enables the enhanced ones.
- */
-
-static void js_pci_4dwave_init(struct js_pci_info *info)
-{
- info->base = ioremap(BASE_ADDRESS(info->pci_p, 1), info->data->size);
- pci_read_config_word(info->pci_p, info->data->lcr, (unsigned short *)&info->lcr);
- pci_write_config_word(info->pci_p, info->data->lcr, info->lcr & ~0x20);
- writeb(0x80, info->base + info->data->gcr);
-}
-
-static void js_pci_vortex_init(struct js_pci_info *info)
-{
- info->base = ioremap(BASE_ADDRESS(info->pci_p, 0), info->data->size);
- info->lcr = readl(info->base + info->data->lcr);
- writel(info->lcr & ~0x8, info->base + info->data->lcr);
- writel(0x40, info->base + info->data->gcr);
-}
-
-/*
- * js_pci_*_cleanup does the opposite of the above functions.
- */
-
-static void js_pci_4dwave_cleanup(struct js_pci_info *info)
-{
- pci_write_config_word(info->pci_p, info->data->lcr, info->lcr);
- writeb(0x00, info->base + info->data->gcr);
- iounmap(info->base);
-}
-
-static void js_pci_vortex_cleanup(struct js_pci_info *info)
-{
- writel(info->lcr, info->base + info->data->lcr);
- writel(0x00, info->base + info->data->gcr);
- iounmap(info->base);
-}
-
-static struct js_pci_data js_pci_data[] =
-{{ PCI_VENDOR_ID_TRIDENT, 0x2000, 0x10000, 0x00044 ,0x00030, 0x00031, 0x00034, 2, 0xffff,
- js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave DX" },
- { PCI_VENDOR_ID_TRIDENT, 0x2001, 0x10000, 0x00044, 0x00030, 0x00031, 0x00034, 2, 0xffff,
- js_pci_4dwave_init, js_pci_4dwave_cleanup, "Trident 4DWave NX" },
- { PCI_VENDOR_ID_AUREAL, 0x0001, 0x40000, 0x1280c, 0x1100c, 0x11008, 0x11010, 4, 0x1fff,
- js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex1" },
- { PCI_VENDOR_ID_AUREAL, 0x0002, 0x40000, 0x2a00c, 0x2880c, 0x28808, 0x28810, 4, 0x1fff,
- js_pci_vortex_init, js_pci_vortex_cleanup, "Aureal Vortex2" },
- { 0, 0, 0, 0, 0, 0, 0, 0, 0, NULL, NULL }};
-
-/*
- * js_pci_read() reads data from a PCI gameport.
- */
-
-static int js_pci_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_pci_info *info = xinfo;
- int i;
-
- info->an.buttons = ~readb(info->base + info->data->buttons) >> 4;
-
- for (i = 0; i < 4; i++)
- info->an.axes[i] = readw(info->base + info->data->axes + i * info->data->axsize);
-
- js_an_decode(&info->an, axes, buttons);
-
- return 0;
-}
-
-static struct js_port * __init js_pci_probe(struct js_port *port, int type, int number,
- struct pci_dev *pci_p, struct js_pci_data *data)
-{
- int i;
- unsigned char u;
- int mask0, mask1, numdev;
- struct js_pci_info iniinfo;
- struct js_pci_info *info = &iniinfo;
-
- mask0 = mask1 = 0;
-
- for (i = 0; i < NUM_CARDS; i++)
- if (js_pci[i * 4] == type && js_pci[i * 4 + 1] == number) {
- mask0 = js_pci[i * 4 + 2];
- mask1 = js_pci[i * 4 + 3];
- if (!mask0 && !mask1) return port;
- break;
- }
-
- memset(info, 0, sizeof(struct js_pci_info));
-
- info->data = data;
- info->pci_p = pci_p;
- data->init(info);
-
- mdelay(10);
- js_pci_read(info, NULL, NULL);
-
- for (i = u = 0; i < 4; i++)
- if (info->an.axes[i] < info->data->axmax) u |= 1 << i;
-
- if ((numdev = js_an_probe_devs(&info->an, u, mask0, mask1, port)) <= 0)
- return port;
-
- port = js_register_port(port, info, numdev, sizeof(struct js_pci_info), js_pci_read);
-
- info = port->info;
-
- for (i = 0; i < numdev; i++)
- printk(KERN_WARNING "js%d: %s on %s #%d\n",
- js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
- js_an_name(i, &info->an), THIS_MODULE, NULL, NULL), js_an_name(i, &info->an), data->name, number);
-
- js_pci_read(info, port->axes, port->buttons);
- js_an_init_corr(&info->an, port->axes, port->corr, 32);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_pci_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(NUM_CARDS*4);
- for (i = 0; i <= ints[0] && i < NUM_CARDS*4; i++)
- js_pci[i] = ints[i+1];
- return 1;
-}
-__setup("js_pci=", js_pci_setup);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_pci_init(void)
-#endif
-{
- struct pci_dev *pci_p = NULL;
- int i, j;
-
- for (i = 0; js_pci_data[i].vendor; i++)
- for (j = 0; (pci_p = pci_find_device(js_pci_data[i].vendor, js_pci_data[i].model, pci_p)); j++)
- if (pci_enable_device(pci_p) == 0)
- js_pci_port = js_pci_probe(js_pci_port, i, j, pci_p, js_pci_data + i);
-
- if (!js_pci_port) {
-#ifdef MODULE
- printk(KERN_WARNING "joy-pci: no joysticks found\n");
-#endif
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_pci_info *info;
-
- while (js_pci_port) {
- for (i = 0; i < js_pci_port->ndevs; i++)
- if (js_pci_port->devs[i])
- js_unregister_device(js_pci_port->devs[i]);
- info = js_pci_port->info;
- info->data->cleanup(info);
- js_pci_port = js_unregister_port(js_pci_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-sidewinder.c b/drivers/char/joystick/joy-sidewinder.c
deleted file mode 100644
index da11598f4..000000000
--- a/drivers/char/joystick/joy-sidewinder.c
+++ /dev/null
@@ -1,835 +0,0 @@
-/*
- * joy-sidewinder.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Microsoft SideWinder digital joystick family.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-/*
- * These are really magic values. Changing them can make a problem go away,
- * as well as break everything.
- */
-
-#undef JS_SW_DEBUG
-
-#define JS_SW_START 400 /* The time we wait for the first bit [400 us] */
-#define JS_SW_STROBE 45 /* Max time per bit [45 us] */
-#define JS_SW_TIMEOUT 4000 /* Wait for everything to settle [4 ms] */
-#define JS_SW_KICK 45 /* Wait after A0 fall till kick [45 us] */
-#define JS_SW_END 8 /* Number of bits before end of packet to kick */
-#define JS_SW_FAIL 16 /* Number of packet read errors to fail and reinitialize */
-#define JS_SW_BAD 2 /* Number of packet read errors to switch off 3d Pro optimization */
-#define JS_SW_OK 64 /* Number of packet read successes to switch optimization back on */
-#define JS_SW_LENGTH 512 /* Max number of bits in a packet */
-
-/*
- * SideWinder joystick types ...
- */
-
-#define JS_SW_TYPE_3DP 1
-#define JS_SW_TYPE_F23 2
-#define JS_SW_TYPE_GP 3
-#define JS_SW_TYPE_PP 4
-#define JS_SW_TYPE_FFP 5
-#define JS_SW_TYPE_FSP 6
-#define JS_SW_TYPE_FFW 7
-
-static int js_sw_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_sw_port __initdata = NULL;
-
-static struct {
- int x;
- int y;
-} js_sw_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1,-1}, { 1, 0}, { 1, 1}, { 0, 1}, {-1, 1}, {-1, 0}, {-1,-1}};
-
-struct js_sw_info {
- int io;
- int length;
- int speed;
- unsigned char type;
- unsigned char bits;
- unsigned char number;
- unsigned char fail;
- unsigned char ok;
-};
-
-/*
- * Gameport speed.
- */
-
-unsigned int js_sw_io_speed = 0;
-
-/*
- * js_sw_measure_speed() measures the gameport i/o speed.
- */
-
-static int __init js_sw_measure_speed(int io)
-{
-#ifdef __i386__
-
-#define GET_TIME(x) do { outb(0, 0x43); x = inb(0x40); x |= inb(0x40) << 8; } while (0)
-#define DELTA(x,y) ((y)-(x)+((y)<(x)?1193180L/HZ:0))
-
- unsigned int i, t, t1, t2, t3, tx;
- unsigned long flags;
-
- tx = 1 << 30;
-
- for(i = 0; i < 50; i++) {
- save_flags(flags); /* Yes, all CPUs */
- cli();
- GET_TIME(t1);
- for(t = 0; t < 50; t++) inb(io);
- GET_TIME(t2);
- GET_TIME(t3);
- restore_flags(flags);
- udelay(i * 10);
- if ((t = DELTA(t2,t1) - DELTA(t3,t2)) < tx) tx = t;
- }
-
- return 59659 / t;
-
-#else
-
- unsigned int j, t = 0;
-
- j = jiffies; while (j == jiffies);
- j = jiffies; while (j == jiffies) { t++; inb(0x201); }
-
- return t * HZ / 1000;
-
-#endif
-}
-
-/*
- * js_sw_read_packet() is a function which reads either a data packet, or an
- * identification packet from a SideWinder joystick. Better don't try to
- * understand this, since all the ugliness of the Microsoft Digital
- * Overdrive protocol is concentrated in this function. If you really want
- * to know how this works, first go watch a couple horror movies, so that
- * you are well prepared, read US patent #5628686 and then e-mail me,
- * and I'll send you an explanation.
- * Vojtech <vojtech@suse.cz>
- */
-
-static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id)
-{
- unsigned long flags;
- int timeout, bitout, sched, i, kick, start, strobe;
- unsigned char pending, u, v;
-
- i = -id; /* Don't care about data, only want ID */
- timeout = id ? (JS_SW_TIMEOUT * speed) >> 10 : 0; /* Set up global timeout for ID packet */
- kick = id ? (JS_SW_KICK * speed) >> 10 : 0; /* Set up kick timeout for ID packet */
- start = (JS_SW_START * speed) >> 10;
- strobe = (JS_SW_STROBE * speed) >> 10;
- bitout = start;
- pending = 0;
- sched = 0;
-
- __save_flags(flags); /* Quiet, please */
- __cli();
-
- outb(0xff, io); /* Trigger */
- v = inb(io);
-
- do {
- bitout--;
- u = v;
- v = inb(io);
- } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
-
- if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
-
- while ((timeout > 0 || bitout > 0) && (i < length)) {
-
- timeout--;
- bitout--; /* Decrement timers */
- sched--;
-
- u = v;
- v = inb(io);
-
- if ((~u & v & 0x10) && (bitout > 0)) { /* Rising edge on clock - data bit */
- if (i >= 0) /* Want this data */
- buf[i] = v >> 5; /* Store it */
- i++; /* Advance index */
- bitout = strobe; /* Extend timeout for next bit */
- }
-
- if (kick && (~v & u & 0x01)) { /* Falling edge on axis 0 */
- sched = kick; /* Schedule second trigger */
- kick = 0; /* Don't schedule next time on falling edge */
- pending = 1; /* Mark schedule */
- }
-
- if (pending && sched < 0 && (i > -JS_SW_END)) { /* Second trigger time */
- outb(0xff, io); /* Trigger */
- bitout = start; /* Long bit timeout */
- pending = 0; /* Unmark schedule */
- timeout = 0; /* Switch from global to bit timeouts */
- }
- }
-
- __restore_flags(flags); /* Done - relax */
-
-#ifdef JS_SW_DEBUG
- {
- int j;
- printk(KERN_DEBUG "joy-sidewinder: Read %d triplets. [", i);
- for (j = 0; j < i; j++) printk("%d", buf[j]);
- printk("]\n");
- }
-#endif
-
- return i;
-}
-
-/*
- * js_sw_get_bits() and GB() compose bits from the triplet buffer into a __u64.
- * Parameter 'pos' is bit number inside packet where to start at, 'num' is number
- * of bits to be read, 'shift' is offset in the resulting __u64 to start at, bits
- * is number of bits per triplet.
- */
-
-#define GB(pos,num,shift) js_sw_get_bits(buf, pos, num, shift, info->bits)
-
-static __u64 js_sw_get_bits(unsigned char *buf, int pos, int num, char shift, char bits)
-{
- __u64 data = 0;
- int tri = pos % bits; /* Start position */
- int i = pos / bits;
- int bit = shift;
-
- while (num--) {
- data |= (__u64)((buf[i] >> tri++) & 1) << bit++; /* Transfer bit */
- if (tri == bits) {
- i++; /* Next triplet */
- tri = 0;
- }
- }
-
- return data;
-}
-
-/*
- * js_sw_init_digital() initializes a SideWinder 3D Pro joystick
- * into digital mode.
- */
-
-static void js_sw_init_digital(int io, int speed)
-{
- int seq[] = { 140, 140+725, 140+300, 0 };
- unsigned long flags;
- int i, t;
-
- __save_flags(flags);
- __cli();
-
- i = 0;
- do {
- outb(0xff, io); /* Trigger */
- t = (JS_SW_TIMEOUT * speed) >> 10;
- while ((inb(io) & 1) && t) t--; /* Wait for axis to fall back to 0 */
- udelay(seq[i]); /* Delay magic time */
- } while (seq[++i]);
-
- outb(0xff, io); /* Last trigger */
-
- __restore_flags(flags);
-}
-
-/*
- * js_sw_parity() computes parity of __u64
- */
-
-static int js_sw_parity(__u64 t)
-{
- int x = t ^ (t >> 32);
- x ^= x >> 16;
- x ^= x >> 8;
- x ^= x >> 4;
- x ^= x >> 2;
- x ^= x >> 1;
- return x & 1;
-}
-
-/*
- * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
- */
-
-static int js_sw_check(__u64 t)
-{
- char sum = 0;
-
- if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
- return -1;
-
- while (t) { /* Sum */
- sum += t & 0xf;
- t >>= 4;
- }
-
- return sum & 0xf;
-}
-
-/*
- * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
- * the axes and buttons arrays.
- */
-
-static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons)
-{
- int hat, i;
-
- switch (info->type) {
-
- case JS_SW_TYPE_3DP:
- case JS_SW_TYPE_F23:
-
- if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0)) > 8) return -1;
-
- axes[0][0] = GB( 3,3,7) | GB(16,7,0);
- axes[0][1] = GB( 0,3,7) | GB(24,7,0);
- axes[0][2] = GB(35,2,7) | GB(40,7,0);
- axes[0][3] = GB(32,3,7) | GB(48,7,0);
- axes[0][4] = js_sw_hat_to_axis[hat].x;
- axes[0][5] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));
-
- return 0;
-
- case JS_SW_TYPE_GP:
-
- for (i = 0; i < info->number * 15; i += 15) {
-
- if (js_sw_parity(GB(i,15,0))) return -1;
-
- axes[i][0] = GB(i+3,1,0) - GB(i+2,1,0);
- axes[i][1] = GB(i+0,1,0) - GB(i+1,1,0);
- buttons[i][0] = ~GB(i+4,10,0);
-
- }
-
- return 0;
-
- case JS_SW_TYPE_PP:
- case JS_SW_TYPE_FFP:
-
- if (!js_sw_parity(GB(0,48,0)) || (hat = GB(42,4,0)) > 8) return -1;
-
- axes[0][0] = GB( 9,10,0);
- axes[0][1] = GB(19,10,0);
- axes[0][2] = GB(36, 6,0);
- axes[0][3] = GB(29, 7,0);
- axes[0][4] = js_sw_hat_to_axis[hat].x;
- axes[0][5] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~GB(0,9,0);
-
- return 0;
-
- case JS_SW_TYPE_FSP:
-
- if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1;
-
- axes[0][0] = GB( 0,10,0);
- axes[0][1] = GB(16,10,0);
- axes[0][2] = GB(32, 6,0);
- axes[0][3] = js_sw_hat_to_axis[hat].x;
- axes[0][4] = js_sw_hat_to_axis[hat].y;
- buttons[0][0] = ~(GB(10,6,0) | GB(26,2,6) | GB(38,2,8));
-
- return 0;
-
- case JS_SW_TYPE_FFW:
-
- if (!js_sw_parity(GB(0,33,0))) return -1;
-
- axes[0][0] = GB( 0,10,0);
- axes[0][1] = GB(10, 6,0);
- axes[0][2] = GB(16, 6,0);
- buttons[0][0] = ~GB(22,8,0);
-
- return 0;
- }
-
- return -1;
-}
-
-/*
- * js_sw_read() reads SideWinder joystick data, and reinitializes
- * the joystick in case of persistent problems. This is the function that is
- * called from the generic code to poll the joystick.
- */
-
-static int js_sw_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_sw_info *info = xinfo;
- unsigned char buf[JS_SW_LENGTH];
- int i;
-
- i = js_sw_read_packet(info->io, info->speed, buf, info->length, 0);
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 66 && i != 66) { /* Broken packet, try to fix */
-
- if (i == 64 && !js_sw_check(js_sw_get_bits(buf,0,64,0,1))) { /* Last init failed, 1 bit mode */
- printk(KERN_WARNING "joy-sidewinder: Joystick in wrong mode on %#x"
- " - going to reinitialize.\n", info->io);
- info->fail = JS_SW_FAIL; /* Reinitialize */
- i = 128; /* Bogus value */
- }
-
- if (i < 66 && GB(0,64,0) == GB(i*3-66,64,0)) /* 1 == 3 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(0,64,0) == GB(66,64,0)) /* 1 == 2 */
- i = 66; /* Everything is fine */
-
- if (i < 66 && GB(i*3-132,64,0) == GB(i*3-66,64,0)) { /* 2 == 3 */
- memmove(buf, buf + i - 22, 22); /* Move data */
- i = 66; /* Carry on */
- }
- }
-
- if (i == info->length && !js_sw_parse(buf, info, axes, buttons)) { /* Parse data */
-
- info->fail = 0;
- info->ok++;
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 66 /* Many packets OK */
- && info->ok > JS_SW_OK) {
-
- printk(KERN_INFO "joy-sidewinder: No more trouble on %#x"
- " - enabling optimization again.\n", info->io);
- info->length = 22;
- }
-
- return 0;
- }
-
- info->ok = 0;
- info->fail++;
-
- if (info->type <= JS_SW_TYPE_F23 && info->length == 22 /* Consecutive bad packets */
- && info->fail > JS_SW_BAD) {
-
- printk(KERN_INFO "joy-sidewinder: Many bit errors on %#x"
- " - disabling optimization.\n", info->io);
- info->length = 66;
- }
-
- if (info->fail < JS_SW_FAIL) return -1; /* Not enough, don't reinitialize yet */
-
- printk(KERN_WARNING "joy-sidewinder: Too many bit errors on %#x"
- " - reinitializing joystick.\n", info->io);
-
- if (!i && info->type <= JS_SW_TYPE_F23) { /* 3D Pro can be in analog mode */
- udelay(3 * JS_SW_TIMEOUT);
- js_sw_init_digital(info->io, info->speed);
- }
-
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, 0); /* Read normal data packet */
- udelay(JS_SW_TIMEOUT);
- js_sw_read_packet(info->io, info->speed, buf, JS_SW_LENGTH, i); /* Read ID packet, this initializes the stick */
-
- info->fail = JS_SW_FAIL;
-
- return -1;
-}
-
-/*
- * js_sw_init_corr() initializes the correction values for
- * SideWinders.
- */
-
-static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr)
-{
- int i, j;
-
- for (i = 0; i < number; i++) {
-
- for (j = 0; j < num_axes; j++) {
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 8;
- corr[i][j].coef[0] = 511 - 32;
- corr[i][j].coef[1] = 512 + 32;
- corr[i][j].coef[2] = (1 << 29) / (511 - 32);
- corr[i][j].coef[3] = (1 << 29) / (511 - 32);
- }
-
- switch (type) {
-
- case JS_SW_TYPE_3DP:
- case JS_SW_TYPE_F23:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 4;
- corr[i][2].coef[0] = 255 - 16;
- corr[i][2].coef[1] = 256 + 16;
- corr[i][2].coef[2] = (1 << 29) / (255 - 16);
- corr[i][2].coef[3] = (1 << 29) / (255 - 16);
-
- j = 4;
-
- break;
-
- case JS_SW_TYPE_PP:
- case JS_SW_TYPE_FFP:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 0;
- corr[i][2].coef[0] = 31 - 2;
- corr[i][2].coef[1] = 32 + 2;
- corr[i][2].coef[2] = (1 << 29) / (31 - 2);
- corr[i][2].coef[3] = (1 << 29) / (31 - 2);
-
- corr[i][3].type = JS_CORR_BROKEN;
- corr[i][3].prec = 1;
- corr[i][3].coef[0] = 63 - 4;
- corr[i][3].coef[1] = 64 + 4;
- corr[i][3].coef[2] = (1 << 29) / (63 - 4);
- corr[i][3].coef[3] = (1 << 29) / (63 - 4);
-
- j = 4;
-
- break;
-
- case JS_SW_TYPE_FFW:
-
- corr[i][0].type = JS_CORR_BROKEN;
- corr[i][0].prec = 2;
- corr[i][0].coef[0] = 511 - 8;
- corr[i][0].coef[1] = 512 + 8;
- corr[i][0].coef[2] = (1 << 29) / (511 - 8);
- corr[i][0].coef[3] = (1 << 29) / (511 - 8);
-
- corr[i][1].type = JS_CORR_BROKEN;
- corr[i][1].prec = 1;
- corr[i][1].coef[0] = 63;
- corr[i][1].coef[1] = 63;
- corr[i][1].coef[2] = (1 << 29) / -63;
- corr[i][1].coef[3] = (1 << 29) / -63;
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 1;
- corr[i][2].coef[0] = 63;
- corr[i][2].coef[1] = 63;
- corr[i][2].coef[2] = (1 << 29) / -63;
- corr[i][2].coef[3] = (1 << 29) / -63;
-
- j = 3;
-
- break;
-
- case JS_SW_TYPE_FSP:
-
- corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 0;
- corr[i][2].coef[0] = 31 - 2;
- corr[i][2].coef[1] = 32 + 2;
- corr[i][2].coef[2] = (1 << 29) / (31 - 2);
- corr[i][2].coef[3] = (1 << 29) / (31 - 2);
-
- j = 3;
-
- break;
-
- default:
-
- j = 0;
- }
-
- for (; j < num_axes; j++) { /* Hats & other binary axes */
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 0;
- corr[i][j].coef[0] = 0;
- corr[i][j].coef[1] = 0;
- corr[i][j].coef[2] = (1 << 29);
- corr[i][j].coef[3] = (1 << 29);
- }
- }
-}
-
-/*
- * js_sw_print_packet() prints the contents of a SideWinder packet.
- */
-
-static void js_sw_print_packet(char *name, int length, unsigned char *buf, char bits)
-{
- int i;
-
- printk("joy-sidewinder: %s packet, %d bits. [", name, length);
- for (i = (((length + 3) >> 2) - 1); i >= 0; i--)
- printk("%x", (int)js_sw_get_bits(buf, i << 2, 4, 0, bits));
- printk("]\n");
-}
-
-/*
- * js_sw_3dp_id() translates the 3DP id into a human legible string.
- * Unfortunately I don't know how to do this for the other SW types.
- */
-
-static void js_sw_3dp_id(unsigned char *buf, char *comment)
-{
- int i;
- char pnp[8], rev[9];
-
- for (i = 0; i < 7; i++) /* ASCII PnP ID */
- pnp[i] = js_sw_get_bits(buf, 24+8*i, 8, 0, 1);
-
- for (i = 0; i < 8; i++) /* ASCII firmware revision */
- rev[i] = js_sw_get_bits(buf, 88+8*i, 8, 0, 1);
-
- pnp[7] = rev[8] = 0;
-
- sprintf(comment, " [PnP %d.%02d id %s rev %s]",
- (int) (js_sw_get_bits(buf, 8, 6, 6, 1) | /* Two 6-bit values */
- js_sw_get_bits(buf, 16, 6, 0, 1)) / 100,
- (int) (js_sw_get_bits(buf, 8, 6, 6, 1) |
- js_sw_get_bits(buf, 16, 6, 0, 1)) % 100,
- pnp, rev);
-}
-
-/*
- * js_sw_guess_mode() checks the upper two button bits for toggling -
- * indication of that the joystick is in 3-bit mode. This is documented
- * behavior for 3DP ID packet, and for example the FSP does this in
- * normal packets instead. Fun ...
- */
-
-static int js_sw_guess_mode(unsigned char *buf, int len)
-{
- int i;
- unsigned char xor = 0;
- for (i = 1; i < len; i++) xor |= (buf[i - 1] ^ buf[i]) & 6;
- return !!xor * 2 + 1;
-}
-
-/*
- * js_sw_probe() probes for SideWinder type joysticks.
- */
-
-static struct js_port __init *js_sw_probe(int io, struct js_port *port)
-{
- struct js_sw_info info;
- char *names[] = {NULL, "SideWinder 3D Pro", "Flight2000 F-23", "SideWinder GamePad", "SideWinder Precision Pro",
- "SideWinder Force Feedback Pro", "SideWinder FreeStyle Pro", "SideWinder Force Feedback Wheel" };
- char axes[] = { 0, 6, 6, 2, 6, 6, 5, 3 };
- char buttons[] = { 0, 9, 9, 10, 9, 9, 10, 8 };
- int i, j, k, l, speed;
- unsigned char buf[JS_SW_LENGTH];
- unsigned char idbuf[JS_SW_LENGTH];
- unsigned char m = 1;
- char comment[40];
-
- comment[0] = 0;
-
- if (check_region(io, 1)) return port;
-
- speed = js_sw_measure_speed(io);
-
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read normal packet */
- m |= js_sw_guess_mode(buf, i); /* Data packet (1-bit) can carry mode info [FSP] */
- udelay(JS_SW_TIMEOUT);
-
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 1: Mode %d. Length %d.\n", m , i);
-#endif
-
- if (!i) { /* No data. 3d Pro analog mode? */
- js_sw_init_digital(io, speed); /* Switch to digital */
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */
- udelay(JS_SW_TIMEOUT);
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 1b: Length %d.\n", i);
-#endif
- if (!i) return port; /* No data -> FAIL */
- }
-
- j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i); /* Read ID. This initializes the stick */
- m |= js_sw_guess_mode(idbuf, j); /* ID packet should carry mode info [3DP] */
-
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2: Mode %d. ID Length %d.\n", m , j);
-#endif
-
- if (!j) { /* Read ID failed. Happens in 1-bit mode on PP */
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Retry reading packet */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2b: Mode %d. Length %d.\n", m , i);
-#endif
- if (!i) return port;
- udelay(JS_SW_TIMEOUT);
- j = js_sw_read_packet(io, speed, idbuf, JS_SW_LENGTH, i);/* Retry reading ID */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 2c: ID Length %d.\n", j);
-#endif
-
- }
-
- k = JS_SW_FAIL; /* Try JS_SW_FAIL times */
- l = 0;
-
- do {
- k--;
- udelay(JS_SW_TIMEOUT);
- i = js_sw_read_packet(io, speed, buf, JS_SW_LENGTH, 0); /* Read data packet */
-#ifdef JS_SW_DEBUG
- printk(KERN_DEBUG "joy-sidewinder: Init 3: Length %d.\n", i);
-#endif
-
- if (i > l) { /* Longer? As we can only lose bits, it makes */
- /* no sense to try detection for a packet shorter */
- l = i; /* than the previous one */
-
- info.number = 1;
- info.io = io;
- info.speed = speed;
- info.length = i;
- info.bits = m;
- info.fail = 0;
- info.ok = 0;
- info.type = 0;
-
- switch (i * m) {
- case 60:
- info.number++;
- case 45: /* Ambiguous packet length */
- if (j <= 40) { /* ID length less or eq 40 -> FSP */
- case 43:
- info.type = JS_SW_TYPE_FSP;
- break;
- }
- info.number++;
- case 30:
- info.number++;
- case 15:
- info.type = JS_SW_TYPE_GP;
- break;
- case 33:
- case 31:
- info.type = JS_SW_TYPE_FFW;
- break;
- case 48: /* Ambiguous */
- if (j == 14) { /* ID lenght 14*3 -> FFP */
- info.type = JS_SW_TYPE_FFP;
- sprintf(comment, " [AC %s]", js_sw_get_bits(idbuf,38,1,0,3) ? "off" : "on");
- } else
- info.type = JS_SW_TYPE_PP;
- break;
- case 198:
- info.length = 22;
- case 64:
- info.type = JS_SW_TYPE_3DP;
- if (j == 160) js_sw_3dp_id(idbuf, comment);
- break;
- }
- }
-
- } while (k && !info.type);
-
- if (!info.type) {
- printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
- "(io=%#x), contact <vojtech@suse.cz>\n", io);
- js_sw_print_packet("ID", j * 3, idbuf, 3);
- js_sw_print_packet("Data", i * m, buf, m);
- return port;
- }
-
-#ifdef JS_SW_DEBUG
- js_sw_print_packet("ID", j * 3, idbuf, 3);
- js_sw_print_packet("Data", i * m, buf, m);
-#endif
-
- k = i;
-
- request_region(io, 1, "joystick (sidewinder)");
-
- port = js_register_port(port, &info, info.number, sizeof(struct js_sw_info), js_sw_read);
-
- for (i = 0; i < info.number; i++)
- printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
- js_register_device(port, i, axes[info.type], buttons[info.type],
- names[info.type], THIS_MODULE, NULL, NULL), names[info.type], comment, io,
- 1000000 / speed, m, j, k);
-
- js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_sw_init(void)
-#endif
-{
- int *p;
-
- for (p = js_sw_port_list; *p; p++) js_sw_port = js_sw_probe(*p, js_sw_port);
- if (js_sw_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-sidewinder: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- int i;
- struct js_sw_info *info;
-
- while (js_sw_port) {
- for (i = 0; i < js_sw_port->ndevs; i++)
- if (js_sw_port->devs[i])
- js_unregister_device(js_sw_port->devs[i]);
- info = js_sw_port->info;
- release_region(info->io, 1);
- js_sw_port = js_unregister_port(js_sw_port);
- }
-
-}
-#endif
diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c
deleted file mode 100644
index 3ace13642..000000000
--- a/drivers/char/joystick/joy-spaceball.c
+++ /dev/null
@@ -1,343 +0,0 @@
-/*
- * joy-spaceball.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- * Copyright (c) 1999 Joseph Krahn
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the SpaceTec SpaceBall 4000 FLX.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_SBALL 12
-#define JS_SBALL_MAX_LENGTH 128
-
-/*
- * List of SpaceBalls.
- */
-
-static struct js_port* js_sball_port = NULL;
-
-/*
- * Per-Ball data.
- */
-
-struct js_sball_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_SBALL_MAX_LENGTH];
- int js;
- char used;
-};
-
-/*
- * js_sball_process_packet() decodes packets the driver receives from the
- * SpaceBall.
- */
-
-static void js_sball_process_packet(struct js_sball_info* info)
-{
- int i,b;
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
-
- if (info->idx < 2) return;
-
- switch (info->data[0]) {
-
- case '@': /* Reset packet */
- info->data[info->idx - 1] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
-
- printk(KERN_INFO "js%d: SpaceBall 4000FLX [%s] on %s%d\n",
- info->js, info->data + i, info->tty->driver.name,
- MINOR(info->tty->device) - info->tty->driver.minor_start);
-
- memset(axes[0], 0, sizeof(int) * 6); /* All axes, buttons should be zero */
- buttons[0][0] = 0;
- break;
-
- case 'D': /* Ball data */
- if (info->idx != 16) return;
- if (!info->port->devs[0]) return;
- axes[0][0] = ((data[3] << 8) | data[4] );
- axes[0][1] = ((data[5] << 8) | data[6] );
- axes[0][2] = ((data[7] << 8) | data[8] );
- axes[0][3] = ((data[9] << 8) | data[10]);
- axes[0][4] = ((data[11]<< 8) | data[12]);
- axes[0][5] = ((data[13]<< 8) | data[14]);
- for(i = 0; i < 6; i ++) if (axes[0][i] & 0x8000) axes[0][i] -= 0x10000;
- break;
-
- case 'K': /* Button data, part1 */
- /* We can ignore this packet for the SB 4000FLX. */
- break;
-
- case '.': /* Button data, part2 */
- if (info->idx != 4) return;
- if (!info->port->devs[0]) return;
- b = (data[1] & 0xbf) << 8 | (data[2] & 0xbf);
- buttons[0][0] = ((b & 0x1f80) >> 1 | (b & 0x3f));
- break;
-
- case '?': /* Error packet */
- info->data[info->idx - 1] = 0;
- printk(KERN_ERR "joy-spaceball: Device error. [%s]\n",info->data+1);
- break;
-
- case 'A': /* reply to A command (ID# report) */
- case 'B': /* reply to B command (beep) */
- case 'H': /* reply to H command (firmware report) */
- case 'S': /* reply to S command (single beep) */
- case 'Y': /* reply to Y command (scale flag) */
- case '"': /* reply to "n command (report info, part n) */
- break;
-
- case 'P': /* Pulse (update) speed */
- if (info->idx != 3) return; /* data[2],data[3] = hex digits for speed 00-FF */
- break;
-
- default:
- printk("joy-spaceball: Unknown packet %d length %d:", data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_sball_open() is a callback from the joystick device open routine.
- */
-
-static int js_sball_open(struct js_dev *jd)
-{
- struct js_sball_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_sball_close() is a callback from the joystick device release routine.
- */
-
-static int js_sball_close(struct js_dev *jd)
-{
- struct js_sball_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_sball_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_sball_init_corr() initializes the correction values for the SpaceBall.
- */
-
-static void __init js_sball_init_corr(struct js_corr **corr)
-{
- int j;
-
- for (j = 0; j < 3; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = 50000;
- corr[0][j].coef[3] = 50000;
- }
- for (j = 3; j < 6; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = 300000;
- corr[0][j].coef[3] = 300000;
- }
-}
-
-/*
- * js_sball_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_sball_ldisc_open(struct tty_struct *tty)
-{
- struct js_sball_info iniinfo;
- struct js_sball_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_sball_port = js_register_port(js_sball_port, info, 1, sizeof(struct js_sball_info), NULL);
-
- info = js_sball_port->info;
- info->port = js_sball_port;
- tty->disc_data = info;
-
- info->js = js_register_device(js_sball_port, 0, 6, 12, "SpaceBall 4000 FLX", THIS_MODULE, js_sball_open, js_sball_close);
-
- js_sball_init_corr(js_sball_port->corr);
-
- return 0;
-}
-
-/*
- * js_sball_ldisc_close() is the opposite of js_sball_ldisc_open()
- */
-
-static void js_sball_ldisc_close(struct tty_struct *tty)
-{
- struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_sball_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_sball_ldisc_receive() 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 js_sball_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_sball_info* info = (struct js_sball_info*) tty->disc_data;
- int i;
- int esc_flag = 0;
-
-/*
- * Spaceball 4000 FLX packets all start with a one letter packet-type decriptor,
- * and end in 0x0d. It uses '^' as an escape for 0x0d characters which can
- * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
- * on whether the axis value is increasing, decreasing, or same as before.
- * (I don't see why this is useful).
- *
- * There may be a nicer whay to handle the escapes, but I wanted to be sure to
- * allow for an escape at the end of the buffer.
- */
- for (i = 0; i < count; i++) {
- if (esc_flag) { /* If the last char was an escape, overwrite it with the escaped value */
-
- switch (cp[i]){
- case 'M':
- case 'Q':
- case 'S':
- info->data[info->idx]=0x0d;
- break;
- case '^': /* escaped escape; leave as is */
- break;
- default:
- printk("joy-spaceball: Unknown escape character: %02x\n", cp[i]);
- }
-
- esc_flag = 0;
-
- } else {
-
- if (info->idx < JS_SBALL_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
-
- if (cp[i] == 0x0D) {
- if (info->idx)
- js_sball_process_packet(info);
- info->idx = 0;
- } else
- if (cp[i] == '^') esc_flag = 1;
-
- }
- }
-}
-
-/*
- * js_sball_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, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_sball_ldisc_room(struct tty_struct *tty)
-{
- return JS_SBALL_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_sball_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "spaceball",
- open: js_sball_ldisc_open,
- close: js_sball_ldisc_close,
- receive_buf: js_sball_ldisc_receive,
- receive_room: js_sball_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_sball_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_SBALL, &js_sball_ldisc)) {
- printk(KERN_ERR "joy-spaceball: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_SBALL, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-spaceorb.c b/drivers/char/joystick/joy-spaceorb.c
deleted file mode 100644
index 0fb4f4c71..000000000
--- a/drivers/char/joystick/joy-spaceorb.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * joy-spaceorb.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the SpaceTec SpaceOrb 360 and SpaceBall Avenger 6dof controllers.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_ORB 15
-#define JS_ORB_MAX_LENGTH 64
-
-/*
- * List of SpaceOrbs.
- */
-
-static struct js_port* js_orb_port = NULL;
-
-/*
- * Per-Orb data.
- */
-
-struct js_orb_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- unsigned char data[JS_ORB_MAX_LENGTH];
- int js;
- char used;
-};
-
-static unsigned char js_orb_xor[] = "SpaceWare";
-
-static unsigned char *js_orb_errors[] = { "EEPROM storing 0 failed", "Receive queue overflow", "Transmit queue timeout",
- "Bad packet", "Power brown-out", "EEPROM checksum error", "Hardware fault" };
-
-/*
- * js_orb_process_packet() decodes packets the driver receives from the
- * SpaceOrb.
- */
-
-static void js_orb_process_packet(struct js_orb_info* info)
-{
- int i;
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
- unsigned char c = 0;
-
- if (info->idx < 2) return;
- for (i = 0; i < info->idx; i++) c ^= data[i];
- if (c) return;
-
- switch (info->data[0]) {
-
- case 'R': /* Reset packet */
- info->data[info->idx - 1] = 0;
- for (i = 1; i < info->idx && info->data[i] == ' '; i++);
- printk(KERN_INFO "js%d: SpaceOrb 360 [%s] on %s%d\n",
- info->js, info->data + i, info->tty->driver.name,
- MINOR(info->tty->device) - info->tty->driver.minor_start);
- break;
-
- case 'D': /* Ball + button data */
- if (info->idx != 12) return;
- if (!info->port->devs[0]) return;
- for (i = 0; i < 9; i++) info->data[i+2] ^= js_orb_xor[i];
- axes[0][0] = ( data[2] << 3) | (data[ 3] >> 4);
- axes[0][1] = ((data[3] & 0x0f) << 6) | (data[ 4] >> 1);
- axes[0][2] = ((data[4] & 0x01) << 9) | (data[ 5] << 2) | (data[4] >> 5);
- axes[0][3] = ((data[6] & 0x1f) << 5) | (data[ 7] >> 2);
- axes[0][4] = ((data[7] & 0x03) << 8) | (data[ 8] << 1) | (data[7] >> 6);
- axes[0][5] = ((data[9] & 0x3f) << 4) | (data[10] >> 3);
- for(i = 0; i < 6; i ++) if (axes[0][i] & 0x200) axes[0][i] -= 1024;
- buttons[0][0] = data[1];
- break;
-
- case 'K': /* Button data */
- if (info->idx != 5) return;
- if (!info->port->devs[0]) return;
- buttons[0][0] = data[2];
- break;
-
- case 'E': /* Error packet */
- if (info->idx != 4) return;
- printk(KERN_ERR "joy-spaceorb: Device error. [ ");
- for (i = 0; i < 7; i++)
- if (data[1] & (1 << i))
- printk("%s ", js_orb_errors[i]);
- printk("]\n");
- break;
-
- case 'N': /* Null region */
- if (info->idx != 3) return;
- break;
-
- case 'P': /* Pulse (update) speed */
- if (info->idx != 4) return;
- break;
-
- default:
- printk("joy-spaceorb: Unknown packet %d length %d:", data[0], info->idx);
- for (i = 0; i < info->idx; i++) printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_orb_open() is a callback from the joystick device open routine.
- */
-
-static int js_orb_open(struct js_dev *jd)
-{
- struct js_orb_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_orb_close() is a callback from the joystick device release routine.
- */
-
-static int js_orb_close(struct js_dev *jd)
-{
- struct js_orb_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_orb_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_orb_init_corr() initializes the correction values for the SpaceOrb.
- */
-
-static void __init js_orb_init_corr(struct js_corr **corr)
-{
- int j;
-
- for (j = 0; j < 6; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0 ;
- corr[0][j].coef[1] = 0 ;
- corr[0][j].coef[2] = (1 << 29) / 511;
- corr[0][j].coef[3] = (1 << 29) / 511;
- }
-}
-
-/*
- * js_orb_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_orb_ldisc_open(struct tty_struct *tty)
-{
- struct js_orb_info iniinfo;
- struct js_orb_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->used = 1;
-
- js_orb_port = js_register_port(js_orb_port, info, 1, sizeof(struct js_orb_info), NULL);
-
- info = js_orb_port->info;
- info->port = js_orb_port;
- tty->disc_data = info;
-
- info->js = js_register_device(js_orb_port, 0, 6, 7, "SpaceOrb 360", THIS_MODULE, js_orb_open, js_orb_close);
-
- js_orb_init_corr(js_orb_port->corr);
-
- return 0;
-}
-
-/*
- * js_orb_ldisc_close() is the opposite of js_orb_ldisc_open()
- */
-
-static void js_orb_ldisc_close(struct tty_struct *tty)
-{
- struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_orb_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_orb_ldisc_receive() 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 js_orb_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_orb_info* info = (struct js_orb_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++) {
- if (~cp[i] & 0x80) {
- if (info->idx) js_orb_process_packet(info);
- info->idx = 0;
- }
- if (info->idx < JS_ORB_MAX_LENGTH)
- info->data[info->idx++] = cp[i] & 0x7f;
- }
-}
-
-/*
- * js_orb_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, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_orb_ldisc_room(struct tty_struct *tty)
-{
- return JS_ORB_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_orb_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "spaceorb",
- open: js_orb_ldisc_open,
- close: js_orb_ldisc_close,
- receive_buf: js_orb_ldisc_receive,
- receive_room: js_orb_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_orb_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_ORB, &js_orb_ldisc)) {
- printk(KERN_ERR "joy-spaceorb: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_ORB, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joy-thrustmaster.c b/drivers/char/joystick/joy-thrustmaster.c
deleted file mode 100644
index 56e043a59..000000000
--- a/drivers/char/joystick/joy-thrustmaster.c
+++ /dev/null
@@ -1,280 +0,0 @@
-/*
- * joy-thrustmaster.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * ThrustMaster DirectConnect (BSP) joystick family.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/init.h>
-
-#define JS_TM_MAX_START 400
-#define JS_TM_MAX_STROBE 45
-#define JS_TM_MAX_LENGTH 13
-
-#define JS_TM_MODE_M3DI 1
-#define JS_TM_MODE_3DRP 3
-#define JS_TM_MODE_FGP 163
-
-#define JS_TM_BYTE_ID 10
-#define JS_TM_BYTE_REV 11
-#define JS_TM_BYTE_DEF 12
-
-static int js_tm_port_list[] __initdata = {0x201, 0};
-static struct js_port* js_tm_port __initdata = NULL;
-
-static unsigned char js_tm_byte_a[16] = { 0, 1, 3, 4, 6, 7 };
-static unsigned char js_tm_byte_d[16] = { 2, 5, 8, 9 };
-
-struct js_tm_info {
- int io;
- unsigned char mode;
-};
-
-/*
- * js_tm_read_packet() reads a ThrustMaster packet.
- */
-
-static int js_tm_read_packet(int io, unsigned char *data)
-{
- unsigned int t, p;
- unsigned char u, v, error;
- int i, j;
- unsigned long flags;
-
- error = 0;
- i = j = 0;
- p = t = JS_TM_MAX_START;
-
- __save_flags(flags);
- __cli();
- outb(0xff,io);
-
- v = inb(io) >> 4;
-
- do {
- t--;
- u = v; v = inb(io) >> 4;
- if (~v & u & 2) {
- if (j) {
- if (j < 9) { /* Data bit */
- data[i] |= (~v & 1) << (j - 1);
- j++;
- } else { /* Stop bit */
- error |= v & 1;
- j = 0;
- i++;
- }
- } else { /* Start bit */
- data[i] = 0;
- error |= ~v & 1;
- j++;
- }
- p = t = (p - t) << 1;
- }
- } while (!error && i < JS_TM_MAX_LENGTH && t > 0);
-
- __restore_flags(flags);
-
- return -(i != JS_TM_MAX_LENGTH);
-}
-
-/*
- * js_tm_read() reads and analyzes ThrustMaster joystick data.
- */
-
-static int js_tm_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_tm_info *info = xinfo;
- unsigned char data[JS_TM_MAX_LENGTH];
- int i;
-
- if (js_tm_read_packet(info->io, data)) return -1;
- if (data[JS_TM_BYTE_ID] != info->mode) return -1;
-
- for (i = 0; i < data[JS_TM_BYTE_DEF] >> 4; i++) axes[0][i] = data[js_tm_byte_a[i]];
-
- switch (info->mode) {
-
- case JS_TM_MODE_M3DI:
-
- axes[0][4] = ((data[js_tm_byte_d[0]] >> 3) & 1) - ((data[js_tm_byte_d[0]] >> 1) & 1);
- axes[0][5] = ((data[js_tm_byte_d[0]] >> 2) & 1) - ( data[js_tm_byte_d[0]] & 1);
-
- buttons[0][0] = ((data[js_tm_byte_d[0]] >> 6) & 0x01) | ((data[js_tm_byte_d[0]] >> 3) & 0x06)
- | ((data[js_tm_byte_d[0]] >> 4) & 0x08) | ((data[js_tm_byte_d[1]] >> 2) & 0x30);
-
- return 0;
-
- case JS_TM_MODE_3DRP:
- case JS_TM_MODE_FGP:
-
- buttons[0][0] = (data[js_tm_byte_d[0]] & 0x3f) | ((data[js_tm_byte_d[1]] << 6) & 0xc0)
- | (( ((int) data[js_tm_byte_d[0]]) << 2) & 0x300);
-
- return 0;
-
- default:
-
- buttons[0][0] = 0;
-
- for (i = 0; i < (data[JS_TM_BYTE_DEF] & 0xf); i++)
- buttons[0][0] |= ((int) data[js_tm_byte_d[i]]) << (i << 3);
-
- return 0;
-
- }
-
- return -1;
-}
-
-/*
- * js_tm_init_corr() initializes the correction values for
- * ThrustMaster joysticks.
- */
-
-static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
-{
- int j = 0;
-
- for (; j < num_axes; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 127 - 2;
- corr[0][j].coef[1] = 128 + 2;
- corr[0][j].coef[2] = (1 << 29) / (127 - 4);
- corr[0][j].coef[3] = (1 << 29) / (127 - 4);
- }
-
- switch (mode) {
- case JS_TM_MODE_M3DI: j = 4; break;
- default: break;
- }
-
- for (; j < num_axes; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 0;
- corr[0][j].coef[0] = 0;
- corr[0][j].coef[1] = 0;
- corr[0][j].coef[2] = (1 << 29);
- corr[0][j].coef[3] = (1 << 29);
- }
-
-}
-
-/*
- * js_tm_probe() probes for ThrustMaster type joysticks.
- */
-
-static struct js_port __init *js_tm_probe(int io, struct js_port *port)
-{
- struct js_tm_info info;
- struct js_rm_models {
- unsigned char id;
- char *name;
- char axes;
- char buttons;
- } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 6 },
- { 3, "ThrustMaster Rage 3D Gamepad", 2, 10 },
- { 163, "Thrustmaster Fusion GamePad", 2, 10 },
- { 0, NULL, 0, 0 }};
- char name[64];
- unsigned char data[JS_TM_MAX_LENGTH];
- unsigned char a, b;
- int i;
-
- if (check_region(io, 1)) return port;
-
- if (js_tm_read_packet(io, data)) return port;
-
- info.io = io;
- info.mode = data[JS_TM_BYTE_ID];
-
- if (!info.mode) return port;
-
- for (i = 0; models[i].id && models[i].id != info.mode; i++);
-
- if (models[i].id != info.mode) {
- a = data[JS_TM_BYTE_DEF] >> 4;
- b = (data[JS_TM_BYTE_DEF] & 0xf) << 3;
- sprintf(name, "Unknown %d-axis, %d-button TM device %d", a, b, info.mode);
- } else {
- sprintf(name, models[i].name);
- a = models[i].axes;
- b = models[i].buttons;
- }
-
- request_region(io, 1, "joystick (thrustmaster)");
- port = js_register_port(port, &info, 1, sizeof(struct js_tm_info), js_tm_read);
- printk(KERN_INFO "js%d: %s revision %d at %#x\n",
- js_register_device(port, 0, a, b, name, THIS_MODULE, NULL, NULL), name, data[JS_TM_BYTE_REV], io);
- js_tm_init_corr(a, info.mode, port->axes, port->corr);
-
- return port;
-}
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_tm_init(void)
-#endif
-{
- int *p;
-
- for (p = js_tm_port_list; *p; p++) js_tm_port = js_tm_probe(*p, js_tm_port);
- if (js_tm_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-thrustmaster: no joysticks found\n");
-#endif
-
- return -ENODEV;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_tm_info *info;
-
- while (js_tm_port) {
- js_unregister_device(js_tm_port->devs[0]);
- info = js_tm_port->info;
- release_region(info->io, 1);
- js_tm_port = js_unregister_port(js_tm_port);
- }
-}
-#endif
diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c
deleted file mode 100644
index c138a99d0..000000000
--- a/drivers/char/joystick/joy-turbografx.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * joy-turbografx.c Version 1.2
- *
- * Copyright (c) 1998-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * Steffen Schwenke's <schwenke@burg-halle.de> TurboGraFX parallel port
- * interface.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/ioport.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/string.h>
-#include <linux/delay.h>
-#include <linux/init.h>
-
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_PARM(js_tg, "2-8i");
-MODULE_PARM(js_tg_2, "2-8i");
-MODULE_PARM(js_tg_3, "2-8i");
-
-#define JS_TG_BUTTON1 0x08
-#define JS_TG_UP 0x10
-#define JS_TG_DOWN 0x20
-#define JS_TG_LEFT 0x40
-#define JS_TG_RIGHT 0x80
-
-#define JS_TG_BUTTON2 0x02
-#define JS_TG_BUTTON3 0x04
-#define JS_TG_BUTTON4 0x01
-#define JS_TG_BUTTON5 0x08
-
-static struct js_port* js_tg_port __initdata = NULL;
-
-static int js_tg[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int js_tg_2[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-static int js_tg_3[] __initdata = { -1, 0, 0, 0, 0, 0, 0, 0 };
-
-struct js_tg_info {
- struct pardevice *port; /* parport device */
- int sticks; /* joysticks connected */
-};
-
-/*
- * js_tg_read() reads and analyzes tg joystick data.
- */
-
-static int js_tg_read(void *xinfo, int **axes, int **buttons)
-{
- struct js_tg_info *info = xinfo;
- int data1, data2, i;
-
- for (i = 0; i < 7; i++)
- if ((info->sticks >> i) & 1) {
-
- JS_PAR_DATA_OUT(~(1 << i), info->port);
- data1 = JS_PAR_STATUS(info->port) ^ ~JS_PAR_STATUS_INVERT;
- data2 = JS_PAR_CTRL_IN(info->port) ^ JS_PAR_CTRL_INVERT;
-
- axes[i][0] = ((data1 & JS_TG_RIGHT) ? 1 : 0) - ((data1 & JS_TG_LEFT) ? 1 : 0);
- axes[i][1] = ((data1 & JS_TG_DOWN ) ? 1 : 0) - ((data1 & JS_TG_UP ) ? 1 : 0);
-
- buttons[i][0] = ((data1 & JS_TG_BUTTON1) ? 0x01 : 0) | ((data2 & JS_TG_BUTTON2) ? 0x02 : 0)
- | ((data2 & JS_TG_BUTTON3) ? 0x04 : 0) | ((data2 & JS_TG_BUTTON4) ? 0x08 : 0)
- | ((data2 & JS_TG_BUTTON5) ? 0x10 : 0);
-
- }
-
- return 0;
-}
-
-/*
- * open callback: claim parport.
- * FIXME: race possible here.
- */
-
-int js_tg_open(struct js_dev *dev)
-{
- struct js_tg_info *info = dev->port->info;
-
- if (!MOD_IN_USE) {
- if (parport_claim(info->port)) return -EBUSY;
- JS_PAR_CTRL_OUT(0x04, info->port);
- }
- MOD_INC_USE_COUNT;
- return 0;
-}
-
-/*
- * close callback: release parport
- */
-
-int js_tg_close(struct js_dev *dev)
-{
- struct js_tg_info *info = dev->port->info;
-
- MOD_DEC_USE_COUNT;
- if (!MOD_IN_USE) {
- JS_PAR_CTRL_OUT(0x00, info->port);
- parport_release(info->port);
- }
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- struct js_tg_info *info;
- int i;
-
- while (js_tg_port) {
- for (i = 0; i < js_tg_port->ndevs; i++)
- if (js_tg_port->devs[i])
- js_unregister_device(js_tg_port->devs[i]);
- info = js_tg_port->info;
- parport_unregister_device(info->port);
- js_tg_port = js_unregister_port(js_tg_port);
- }
-}
-#endif
-
-/*
- * js_tg_init_corr() initializes correction values of
- * tg gamepads.
- */
-
-static void __init js_tg_init_corr(int sticks, struct js_corr **corr)
-{
- int i, j;
-
- for (i = 0; i < 7; i++)
- if ((sticks >> i) & 1)
- for (j = 0; j < 2; j++) {
- corr[i][j].type = JS_CORR_BROKEN;
- corr[i][j].prec = 0;
- corr[i][j].coef[0] = 0;
- corr[i][j].coef[1] = 0;
- corr[i][j].coef[2] = (1 << 29);
- corr[i][j].coef[3] = (1 << 29);
- }
-}
-
-/*
- * js_tg_probe() probes for tg gamepads.
- */
-
-static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
-{
- struct js_tg_info iniinfo;
- struct js_tg_info *info = &iniinfo;
- struct parport *pp;
- int i;
-
- if (config[0] < 0) return port;
-
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp && (config[0]>0); pp=pp->next) config[0]--;
-
- if (!pp) {
- printk(KERN_ERR "joy-tg: no such parport\n");
- return port;
- }
-
- info->port = parport_register_device(pp, "joystick (turbografx)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info->port)
- return port;
-
- port = js_register_port(port, info, 7, sizeof(struct js_tg_info), js_tg_read);
- info = port->info;
-
- info->sticks = 0;
-
- for (i = 0; i < 7; i++)
- if (config[i+1] > 0 && config[i+1] < 6) {
- printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
- js_register_device(port, i, 2, config[i+1], "Multisystem joystick", NULL, js_tg_open, js_tg_close),
- info->port->port->name);
- info->sticks |= (1 << i);
- }
-
- if (!info->sticks) {
- parport_unregister_device(info->port);
- return port;
- }
-
- js_tg_init_corr(info->sticks, port->corr);
-
- return port;
-}
-
-#ifndef MODULE
-int __init js_tg_setup(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
- return 1;
-}
-int __init js_tg_setup_2(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
- return 1;
-}
-int __init js_tg_setup_3(SETUP_PARAM)
-{
- int i;
- SETUP_PARSE(2);
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
- return 1;
-}
-__setup("js_tg=", js_tg_setup);
-__setup("js_tg_2=", js_tg_setup_2);
-__setup("js_tg_3=", js_tg_setup_3);
-#endif
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_tg_init(void)
-#endif
-{
- js_tg_port = js_tg_probe(js_tg, js_tg_port);
- js_tg_port = js_tg_probe(js_tg_2, js_tg_port);
- js_tg_port = js_tg_probe(js_tg_3, js_tg_port);
-
- if (js_tg_port) return 0;
-
-#ifdef MODULE
- printk(KERN_WARNING "joy-tg: no joysticks specified\n");
-#endif
- return -ENODEV;
-}
diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c
deleted file mode 100644
index 232699859..000000000
--- a/drivers/char/joystick/joy-warrior.c
+++ /dev/null
@@ -1,301 +0,0 @@
-/*
- * joy-warrior.c Version 0.1
- *
- * Copyright (c) 1998 David Thompson
- * Copyright (c) 1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is a module for the Linux joystick driver, supporting
- * the Logitech WingMan Warrior joystick.
- */
-
-/*
- * 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@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/delay.h>
-#include <linux/tty.h>
-#include <linux/init.h>
-
-/*
- * Constants.
- */
-
-#define N_JOYSTICK_WAR 13
-#define JS_WAR_MAX_LENGTH 16
-
-/*
- * List of Warriors.
- */
-
-static struct js_port* js_war_port = NULL;
-
-static char js_war_lengths[] = { 0, 4, 12, 3, 4, 4, 0, 0 };
-
-/*
- * Per-Warrior data.
- */
-
-struct js_war_info {
- struct tty_struct* tty;
- struct js_port* port;
- int idx;
- int len;
- unsigned char data[JS_WAR_MAX_LENGTH];
- char used;
-};
-
-/*
- * js_war_process_packet() decodes packets the driver receives from the
- * Warrior. It updates the data accordingly.
- */
-
-static void js_war_process_packet(struct js_war_info* info)
-{
- int **axes = info->port->axes;
- int **buttons = info->port->buttons;
- unsigned char *data = info->data;
- int i;
-
- if (!info->idx) return;
-
- switch ((data[0] >> 4) & 7) {
-
- case 1: /* Button data */
- if (!info->port->devs[0]) return;
- buttons[0][0] = ((data[3] & 0xa) >> 1) | ((data[3] & 0x5) << 1);
- return;
- case 3: /* XY-axis info->data */
- if (!info->port->devs[0]) return;
- axes[0][0] = ((data[0] & 8) << 5) - (data[2] | ((data[0] & 4) << 5));
- axes[0][1] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
- return;
- break;
- case 5: /* Throttle, spinner, hat info->data */
- if (!info->port->devs[0]) return;
- axes[0][2] = (data[1] | ((data[0] & 1) << 7)) - ((data[0] & 2) << 7);
- axes[0][3] = (data[3] & 2 ? 1 : 0) - (info->data[3] & 1 ? 1 : 0);
- axes[0][4] = (data[3] & 8 ? 1 : 0) - (info->data[3] & 4 ? 1 : 0);
- axes[0][5] = (data[2] | ((data[0] & 4) << 5)) - ((data[0] & 8) << 5);
- return;
- case 2: /* Static status (Send !S to get one) */
- case 4: /* Dynamic status */
- return;
- default:
- printk("joy-warrior: Unknown packet %d length %d:", (data[0] >> 4) & 7, info->idx);
- for (i = 0; i < info->idx; i++)
- printk(" %02x", data[i]);
- printk("\n");
- return;
- }
-}
-
-/*
- * js_war_open() is a callback from the joystick device open routine.
- */
-
-static int js_war_open(struct js_dev *jd)
-{
- struct js_war_info *info = jd->port->info;
- info->used++;
- return 0;
-}
-
-/*
- * js_war_close() is a callback from the joystick device release routine.
- */
-
-static int js_war_close(struct js_dev *jd)
-{
- struct js_war_info *info = jd->port->info;
- if (!--info->used) {
- js_unregister_device(jd->port->devs[0]);
- js_war_port = js_unregister_port(jd->port);
- }
- return 0;
-}
-
-/*
- * js_war_init_corr() initializes the correction values for the Warrior.
- */
-
-static void __init js_war_init_corr(struct js_corr **corr)
-{
- int i;
-
- for (i = 0; i < 6; i++) {
- corr[0][i].type = JS_CORR_BROKEN;
- corr[0][i].prec = 0;
- corr[0][i].coef[0] = -8;
- corr[0][i].coef[1] = 8;
- corr[0][i].coef[2] = (1 << 29) / (128 - 64);
- corr[0][i].coef[3] = (1 << 29) / (128 - 64);
- }
-
- corr[0][2].coef[2] = (1 << 29) / (128 - 16);
- corr[0][2].coef[3] = (1 << 29) / (128 - 16);
-
- for (i = 3; i < 5; i++) {
- corr[0][i].coef[0] = 0;
- corr[0][i].coef[1] = 0;
- corr[0][i].coef[2] = (1 << 29);
- corr[0][i].coef[3] = (1 << 29);
- }
-
- corr[0][5].prec = -1;
- corr[0][5].coef[0] = 0;
- corr[0][5].coef[1] = 0;
- corr[0][5].coef[2] = (1 << 29) / 128;
- corr[0][5].coef[3] = (1 << 29) / 128;
-}
-
-/*
- * js_war_ldisc_open() is the routine that is called upon setting our line
- * discipline on a tty.
- */
-
-static int js_war_ldisc_open(struct tty_struct *tty)
-{
- struct js_war_info iniinfo;
- struct js_war_info *info = &iniinfo;
-
- MOD_INC_USE_COUNT;
-
- info->tty = tty;
- info->idx = 0;
- info->len = 0;
- info->used = 1;
-
- js_war_port = js_register_port(js_war_port, info, 1, sizeof(struct js_war_info), NULL);
-
- info = js_war_port->info;
- info->port = js_war_port;
- tty->disc_data = info;
-
- printk(KERN_INFO "js%d: WingMan Warrior on %s%d\n",
- js_register_device(js_war_port, 0, 6, 4, "WingMan Warrior", THIS_MODULE, js_war_open, js_war_close),
- tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
-
- js_war_init_corr(js_war_port->corr);
-
- return 0;
-}
-
-/*
- * js_war_ldisc_close() is the opposite of js_war_ldisc_open()
- */
-
-static void js_war_ldisc_close(struct tty_struct *tty)
-{
- struct js_war_info* info = (struct js_war_info*) tty->disc_data;
- if (!--info->used) {
- js_unregister_device(info->port->devs[0]);
- js_war_port = js_unregister_port(info->port);
- }
- MOD_DEC_USE_COUNT;
-}
-
-/*
- * js_war_ldisc_receive() 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 js_war_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
-{
- struct js_war_info* info = (struct js_war_info*) tty->disc_data;
- int i;
-
- for (i = 0; i < count; i++) {
- if (cp[i] & 0x80) {
- if (info->idx)
- js_war_process_packet(info);
- info->idx = 0;
- info->len = js_war_lengths[(cp[i] >> 4) & 7];
- }
-
- if (info->idx < JS_WAR_MAX_LENGTH)
- info->data[info->idx++] = cp[i];
-
- if (info->idx == info->len) {
- if (info->idx)
- js_war_process_packet(info);
- info->idx = 0;
- info->len = 0;
- }
- }
-}
-
-/*
- * js_war_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, so why not the size of our packet buffer. It's big anyway.
- */
-
-static int js_war_ldisc_room(struct tty_struct *tty)
-{
- return JS_WAR_MAX_LENGTH;
-}
-
-/*
- * The line discipline structure.
- */
-
-static struct tty_ldisc js_war_ldisc = {
- magic: TTY_LDISC_MAGIC,
- name: "warrior",
- open: js_war_ldisc_open,
- close: js_war_ldisc_close,
- receive_buf: js_war_ldisc_receive,
- receive_room: js_war_ldisc_room,
-};
-
-/*
- * The functions for inserting/removing us as a module.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_war_init(void)
-#endif
-{
- if (tty_register_ldisc(N_JOYSTICK_WAR, &js_war_ldisc)) {
- printk(KERN_ERR "joy-warrior: Error registering line discipline.\n");
- return -ENODEV;
- }
-
- return 0;
-}
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- tty_register_ldisc(N_JOYSTICK_WAR, NULL);
-}
-#endif
diff --git a/drivers/char/joystick/joystick.c b/drivers/char/joystick/joystick.c
deleted file mode 100644
index c9bd56ce3..000000000
--- a/drivers/char/joystick/joystick.c
+++ /dev/null
@@ -1,864 +0,0 @@
-/*
- * joystick.c Version 1.2
- *
- * Copyright (c) 1996-1999 Vojtech Pavlik
- *
- * Sponsored by SuSE
- */
-
-/*
- * This is the main joystick driver for Linux. It doesn't support any
- * devices directly, rather is lets you use sub-modules to do that job. See
- * Documentation/joystick.txt for more info.
- */
-
-/*
- * This program is free software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation; either version 2 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- *
- * Should you need to contact me, the author, you can do so either by
- * e-mail - mail your message to <vojtech@suse.cz>, or by paper mail:
- * Vojtech Pavlik, Ucitelska 1576, Prague 8, 182 00 Czech Republic
- */
-
-#include <asm/io.h>
-#include <asm/system.h>
-#include <asm/segment.h>
-#include <linux/delay.h>
-#include <linux/errno.h>
-#include <linux/joystick.h>
-#include <linux/devfs_fs_kernel.h>
-#include <linux/kernel.h>
-#include <linux/major.h>
-#include <linux/malloc.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/poll.h>
-#include <linux/config.h>
-#include <linux/init.h>
-
-/*
- * Configurable parameters.
- */
-
-#define JS_REFRESH_TIME HZ/50 /* Time between two reads of joysticks (20ms) */
-
-/*
- * Exported symbols.
- */
-
-EXPORT_SYMBOL(js_register_port);
-EXPORT_SYMBOL(js_unregister_port);
-EXPORT_SYMBOL(js_register_device);
-EXPORT_SYMBOL(js_unregister_device);
-
-/*
- * Buffer macros.
- */
-
-#define ROT(A,B,C) ((((A)<(C))&&(((B)>(A))&&((B)<(C))))||(((A)>(C))&&(((B)>(A))||((B)<(C)))))
-#define GOF(X) (((X)==JS_BUFF_SIZE-1)?0:(X)+1)
-#define GOB(X) ((X)?(X)-1:JS_BUFF_SIZE-1)
-#define DIFF(X,Y) ((X)>(Y)?(X)-(Y):(Y)-(X))
-
-/*
- * Global variables.
- */
-
-static struct JS_DATA_SAVE_TYPE js_comp_glue;
-static struct js_port *js_port = NULL;
-static struct js_dev *js_dev = NULL;
-static struct timer_list js_timer;
-spinlock_t js_lock = SPIN_LOCK_UNLOCKED;
-static int js_use_count = 0;
-
-/*
- * Module info.
- */
-
-MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
-MODULE_SUPPORTED_DEVICE("js");
-
-/*
- * js_correct() performs correction of raw joystick data.
- */
-
-static int js_correct(int value, struct js_corr *corr)
-{
- switch (corr->type) {
- case JS_CORR_NONE:
- break;
- case JS_CORR_BROKEN:
- value = value > corr->coef[0] ? (value < corr->coef[1] ? 0 :
- ((corr->coef[3] * (value - corr->coef[1])) >> 14)) :
- ((corr->coef[2] * (value - corr->coef[0])) >> 14);
- break;
-
- default:
- return 0;
- }
-
- if (value < -32767) return -32767;
- if (value > 32767) return 32767;
-
- return value;
-}
-
-/*
- * js_button() returns value of button number i.
- */
-
-static inline int js_button(int *buttons, int i)
-{
- return (buttons[i >> 5] >> (i & 0x1f)) & 1;
-}
-
-/*
- * js_add_event() adds an event to the buffer. This requires additional
- * queue post-processing done by js_sync_buff.
- */
-
-static void js_add_event(struct js_dev *jd, __u32 time, __u8 type, __u8 number, __s16 value)
-{
- jd->buff[jd->ahead].time = time;
- jd->buff[jd->ahead].type = type;
- jd->buff[jd->ahead].number = number;
- jd->buff[jd->ahead].value = value;
- if (++jd->ahead == JS_BUFF_SIZE) jd->ahead = 0;
-}
-
-/*
- * js_flush_data() does the same as js_process_data, except for that it doesn't
- * generate any events - it just copies the data from new to cur.
- */
-
-static void js_flush_data(struct js_dev *jd)
-{
- int i;
-
- for (i = 0; i < ((jd->num_buttons - 1) >> 5) + 1; i++)
- jd->cur.buttons[i] = jd->new.buttons[i];
- for (i = 0; i < jd->num_axes; i++)
- jd->cur.axes[i] = jd->new.axes[i];
-}
-
-/*
- * js_process_data() finds changes in button states and axis positions and adds
- * them as events to the buffer.
- */
-
-static void js_process_data(struct js_dev *jd)
-{
- int i, t;
-
- for (i = 0; i < jd->num_buttons; i++)
- if ((t = js_button(jd->new.buttons, i)) != js_button(jd->cur.buttons, i)) {
- js_add_event(jd, jiffies, JS_EVENT_BUTTON, i, t);
- jd->cur.buttons[i >> 5] ^= (1 << (i & 0x1f));
- }
-
- for (i = 0; i < jd->num_axes; i++) {
- t = js_correct(jd->new.axes[i], &jd->corr[i]);
- if (((jd->corr[i].prec == -1) && t) ||
- ((DIFF(jd->new.axes[i], jd->cur.axes[i]) > jd->corr[i].prec) &&
- (t != js_correct(jd->cur.axes[i], &jd->corr[i])))) {
- js_add_event(jd, jiffies, JS_EVENT_AXIS, i, t);
- jd->cur.axes[i] = jd->new.axes[i];
- }
- }
-}
-
-/*
- * js_sync_buff() checks for all overflows caused by recent additions to the buffer.
- * These happen only if some process is reading the data too slowly. It
- * wakes up any process waiting for data.
- */
-
-static void js_sync_buff(struct js_dev *jd)
-{
- struct js_list *curl = jd->list;
-
- if (jd->bhead != jd->ahead) {
- if(ROT(jd->bhead, jd->tail, jd->ahead) || (jd->tail == jd->bhead)) {
- while (curl) {
- if (ROT(jd->bhead, curl->tail, jd->ahead) || (curl->tail == jd->bhead)) {
- curl->tail = jd->ahead;
- curl->startup = 0;
- }
- curl = curl->next;
- }
- jd->tail = jd->ahead;
- }
- jd->bhead = jd->ahead;
- wake_up_interruptible(&jd->wait);
- }
-}
-
-/*
- * js_do_timer() acts as an interrupt replacement. It reads the data
- * from all ports and then generates events for all devices.
- */
-
-static void js_do_timer(unsigned long data)
-{
- struct js_port *curp = js_port;
- struct js_dev *curd = js_dev;
- unsigned long flags;
-
- while (curp) {
- if (curp->read)
- if (curp->read(curp->info, curp->axes, curp->buttons))
- curp->fail++;
- curp->total++;
- curp = curp->next;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (curd) {
- if (data) {
- js_process_data(curd);
- js_sync_buff(curd);
- } else {
- js_flush_data(curd);
- }
- curd = curd->next;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- js_timer.expires = jiffies + JS_REFRESH_TIME;
- add_timer(&js_timer);
-}
-
-/*
- * js_read() copies one or more entries from jsd[].buff to user
- * space.
- */
-
-static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-{
- DECLARE_WAITQUEUE(wait, current);
- struct js_event *buff = (void *) buf;
- struct js_list *curl;
- struct js_dev *jd;
- unsigned long blocks = count / sizeof(struct js_event);
- int written = 0;
- int new_tail, orig_tail;
- int retval = 0;
- unsigned long flags;
-
- curl = file->private_data;
- jd = curl->dev;
- orig_tail = curl->tail;
-
-/*
- * Check user data.
- */
-
- if (!blocks)
- return -EINVAL;
-
-/*
- * Lock it.
- */
-
- spin_lock_irqsave(&js_lock, flags);
-
-/*
- * Handle (non)blocking i/o.
- */
- if (count != sizeof(struct JS_DATA_TYPE)) {
-
- if (GOF(curl->tail) == jd->bhead && curl->startup == jd->num_axes + jd->num_buttons) {
-
- __set_current_state(TASK_INTERRUPTIBLE);
- add_wait_queue(&jd->wait, &wait);
-
- while (GOF(curl->tail) == jd->bhead) {
-
- if (file->f_flags & O_NONBLOCK) {
- retval = -EAGAIN;
- break;
- }
- if (signal_pending(current)) {
- retval = -ERESTARTSYS;
- break;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
- schedule();
- spin_lock_irqsave(&js_lock, flags);
-
- }
-
- current->state = TASK_RUNNING;
- remove_wait_queue(&jd->wait, &wait);
- }
-
- if (retval) {
- spin_unlock_irqrestore(&js_lock, flags);
- return retval;
- }
-
-/*
- * Initial state.
- */
-
- while (curl->startup < jd->num_axes + jd->num_buttons && written < blocks && !retval) {
-
- struct js_event tmpevent;
-
- if (curl->startup < jd->num_buttons) {
- tmpevent.type = JS_EVENT_BUTTON | JS_EVENT_INIT;
- tmpevent.value = js_button(jd->cur.buttons, curl->startup);
- tmpevent.number = curl->startup;
- } else {
- tmpevent.type = JS_EVENT_AXIS | JS_EVENT_INIT;
- tmpevent.value = js_correct(jd->cur.axes[curl->startup - jd->num_buttons],
- &jd->corr[curl->startup - jd->num_buttons]);
- tmpevent.number = curl->startup - jd->num_buttons;
- }
-
- tmpevent.time = jiffies * (1000/HZ);
-
- if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event)))
- retval = -EFAULT;
-
- curl->startup++;
- written++;
- }
-
-/*
- * Buffer data.
- */
-
- while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) {
-
- if (copy_to_user(&buff[written], &jd->buff[new_tail], sizeof(struct js_event)))
- retval = -EFAULT;
- if (put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time))
- retval = -EFAULT;
-
- curl->tail = new_tail;
- written++;
- }
- }
-
- else
-
-/*
- * Handle version 0.x compatibility.
- */
-
- {
- struct JS_DATA_TYPE data;
-
- data.buttons = jd->new.buttons[0];
- data.x = jd->num_axes < 1 ? 0 :
- ((js_correct(jd->new.axes[0], &jd->corr[0]) / 256) + 128) >> js_comp_glue.JS_CORR.x;
- data.y = jd->num_axes < 2 ? 0 :
- ((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y;
-
- retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
-
- curl->startup = jd->num_axes + jd->num_buttons;
- curl->tail = GOB(jd->bhead);
- if (!retval) retval = sizeof(struct JS_DATA_TYPE);
- }
-
-/*
- * Check main tail and move it.
- */
-
- if (orig_tail == jd->tail) {
- new_tail = curl->tail;
- curl = jd->list;
- while (curl && curl->tail != jd->tail) {
- if (ROT(jd->bhead, new_tail, curl->tail) ||
- (jd->bhead == curl->tail)) new_tail = curl->tail;
- curl = curl->next;
- }
- if (!curl) jd->tail = new_tail;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- return retval ? retval : written * sizeof(struct js_event);
-}
-
-/*
- * js_poll() does select() support.
- */
-
-static unsigned int js_poll(struct file *file, poll_table *wait)
-{
- struct js_list *curl = file->private_data;
- unsigned long flags;
- int retval = 0;
- poll_wait(file, &curl->dev->wait, wait);
- spin_lock_irqsave(&js_lock, flags);
- if (GOF(curl->tail) != curl->dev->bhead ||
- curl->startup < curl->dev->num_axes + curl->dev->num_buttons) retval = POLLIN | POLLRDNORM;
- spin_unlock_irqrestore(&js_lock, flags);
- return retval;
-}
-
-/*
- * js_ioctl handles misc ioctl calls.
- */
-
-static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, unsigned long arg)
-{
- struct js_list *curl;
- struct js_dev *jd;
- int len;
-
- curl = file->private_data;
- jd = curl->dev;
-
- switch (cmd) {
-
-/*
- * 0.x compatibility
- */
-
- case JS_SET_CAL:
- return copy_from_user(&js_comp_glue.JS_CORR, (struct JS_DATA_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_GET_CAL:
- return copy_to_user((struct JS_DATA_TYPE *) arg, &js_comp_glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
- case JS_SET_TIMEOUT:
- return get_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
- case JS_GET_TIMEOUT:
- return put_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
- case JS_SET_TIMELIMIT:
- return get_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
- case JS_GET_TIMELIMIT:
- return put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
- case JS_SET_ALL:
- return copy_from_user(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
- case JS_GET_ALL:
- return copy_to_user((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue,
- sizeof(struct JS_DATA_SAVE_TYPE)) ? -EFAULT : 0;
-
-/*
- * 1.x ioctl calls
- */
-
- case JSIOCGVERSION:
- return put_user(JS_VERSION, (__u32 *) arg);
- case JSIOCGAXES:
- return put_user(jd->num_axes, (__u8 *) arg);
- case JSIOCGBUTTONS:
- return put_user(jd->num_buttons, (__u8 *) arg);
- case JSIOCSCORR:
- return copy_from_user(jd->corr, (struct js_corr *) arg,
- sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
- case JSIOCGCORR:
- return copy_to_user((struct js_corr *) arg, jd->corr,
- sizeof(struct js_corr) * jd->num_axes) ? -EFAULT : 0;
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- len = strlen(jd->name) + 1;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- if (copy_to_user((char *) arg, jd->name, len)) return -EFAULT;
- return len;
- }
- }
-
- return -EINVAL;
-}
-
-/*
- * js_open() performs necessary initialization and adds
- * an entry to the linked list.
- */
-
-static int js_open(struct inode *inode, struct file *file)
-{
- struct js_list *curl, *new;
- struct js_dev *jd = js_dev;
- int i = MINOR(inode->i_rdev);
- unsigned long flags;
- int result;
-
- if (MAJOR(inode->i_rdev) != JOYSTICK_MAJOR)
- return -EINVAL;
-
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (i > 0 && jd) {
- jd = jd->next;
- i--;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- if (!jd) return -ENODEV;
-
- if (jd->owner)
- __MOD_INC_USE_COUNT(jd->owner);
- if (jd->open && (result = jd->open(jd))) {
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
- return result;
- }
-
- new = kmalloc(sizeof(struct js_list), GFP_KERNEL);
- if (!new) {
- if (jd->close)
- jd->close(jd);
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
-
- return -ENOMEM;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- curl = jd->list;
-
- jd->list = new;
- jd->list->next = curl;
- jd->list->dev = jd;
- jd->list->startup = 0;
- jd->list->tail = GOB(jd->bhead);
- file->private_data = jd->list;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- if (!js_use_count++) js_do_timer(0);
-
- return 0;
-}
-
-/*
- * js_release() removes an entry from list and deallocates memory
- * used by it.
- */
-
-static int js_release(struct inode *inode, struct file *file)
-{
- struct js_list *curl = file->private_data;
- struct js_dev *jd = curl->dev;
- struct js_list **curp = &jd->list;
- int new_tail;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*curp && (*curp != curl)) curp = &((*curp)->next);
- *curp = (*curp)->next;
-
- if (jd->list)
- if (curl->tail == jd->tail) {
- curl = jd->list;
- new_tail = curl->tail;
- while (curl && curl->tail != jd->tail) {
- if (ROT(jd->bhead, new_tail, curl->tail) ||
- (jd->bhead == curl->tail)) new_tail = curl->tail;
- curl = curl->next;
- }
- if (!curl) jd->tail = new_tail;
- }
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- kfree(file->private_data);
-
- if (!--js_use_count) del_timer(&js_timer);
-
- if (jd->close)
- jd->close(jd);
- if (jd->owner)
- __MOD_DEC_USE_COUNT(jd->owner);
-
- return 0;
-}
-
-/*
- * js_dump_mem() dumps all data structures in memory.
- * It's used for debugging only.
- */
-
-struct js_port *js_register_port(struct js_port *port,
- void *info, int devs, int infos, js_read_func read)
-{
- struct js_port **ptrp = &js_port;
- struct js_port *curp;
- void *all;
- int i;
- unsigned long flags;
-
- if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)))
- return NULL;
-
- curp = all;
-
- curp->next = NULL;
- curp->prev = port;
- curp->read = read;
- curp->ndevs = devs;
- curp->fail = 0;
- curp->total = 0;
-
- curp->devs = all += sizeof(struct js_port);
- for (i = 0; i < devs; i++) curp->devs[i] = NULL;
-
- curp->axes = all += devs * sizeof(void*);
- curp->buttons = (void*) all += devs * sizeof(void*);
- curp->corr = all += devs * sizeof(void*);
-
- if (infos) {
- curp->info = all += devs * sizeof(void*);
- memcpy(curp->info, info, infos);
- } else {
- curp->info = NULL;
- }
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*ptrp) ptrp=&((*ptrp)->next);
- *ptrp = curp;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- return curp;
-}
-
-struct js_port *js_unregister_port(struct js_port *port)
-{
- struct js_port **curp = &js_port;
- struct js_port *prev;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- printk("js: There were %d failures out of %d read attempts.\n", port->fail, port->total);
-
- while (*curp && (*curp != port)) curp = &((*curp)->next);
- *curp = (*curp)->next;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- prev = port->prev;
- kfree(port);
-
- return prev;
-}
-
-extern struct file_operations js_fops;
-
-static devfs_handle_t devfs_handle = NULL;
-
-int js_register_device(struct js_port *port, int number, int axes,
- int buttons, char *name, struct module *owner,
- js_ops_func open, js_ops_func close)
-{
- struct js_dev **ptrd = &js_dev;
- struct js_dev *curd;
- void *all;
- int i = 0;
- unsigned long flags;
- char devfs_name[8];
-
- if (!(all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
- 2 * (((buttons - 1) >> 5) + 1) * sizeof(int) +
- axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)))
- return -1;
-
- curd = all;
-
- curd->next = NULL;
- curd->list = NULL;
- curd->port = port;
- curd->open = open;
- curd->close = close;
- curd->owner = owner;
-
- init_waitqueue_head(&curd->wait);
-
- curd->ahead = 0;
- curd->bhead = 0;
- curd->tail = JS_BUFF_SIZE - 1;
- curd->num_axes = axes;
- curd->num_buttons = buttons;
-
- curd->cur.axes = all += sizeof(struct js_dev);
- curd->cur.buttons = all += axes * sizeof(int);
- curd->new.axes = all += (((buttons - 1) >> 5) + 1) * sizeof(int);
- curd->new.buttons = all += axes * sizeof(int);
- curd->corr = all += (((buttons -1 ) >> 5) + 1) * sizeof(int);
-
- curd->name = all += axes * sizeof(struct js_corr);
- strcpy(curd->name, name);
-
- port->devs[number] = curd;
- port->axes[number] = curd->new.axes;
- port->buttons[number] = curd->new.buttons;
- port->corr[number] = curd->corr;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*ptrd) { ptrd=&(*ptrd)->next; i++; }
- *ptrd = curd;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- sprintf(devfs_name, "js%d", i);
- curd->devfs_handle = devfs_register(devfs_handle, devfs_name, 0,
- DEVFS_FL_DEFAULT,
- JOYSTICK_MAJOR, i,
- S_IFCHR | S_IRUGO | S_IWUSR, 0, 0,
- &js_fops, NULL);
-
- return i;
-}
-
-void js_unregister_device(struct js_dev *dev)
-{
- struct js_dev **curd = &js_dev;
- unsigned long flags;
-
- spin_lock_irqsave(&js_lock, flags);
-
- while (*curd && (*curd != dev)) curd = &((*curd)->next);
- *curd = (*curd)->next;
-
- spin_unlock_irqrestore(&js_lock, flags);
-
- devfs_unregister(dev->devfs_handle);
- kfree(dev);
-}
-
-/*
- * The operations structure.
- */
-
-static struct file_operations js_fops =
-{
- owner: THIS_MODULE,
- read: js_read,
- poll: js_poll,
- ioctl: js_ioctl,
- open: js_open,
- release: js_release,
-};
-
-/*
- * js_init() registers the driver and calls the probe function.
- * also initializes some crucial variables.
- */
-
-#ifdef MODULE
-int init_module(void)
-#else
-int __init js_init(void)
-#endif
-{
-
- if (devfs_register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
- printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
- return -EBUSY;
- }
- devfs_handle = devfs_mk_dir(NULL, "joysticks", 9, NULL);
-
- printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
- JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
-
- spin_lock_init(&js_lock);
-
- init_timer(&js_timer);
- js_timer.function = js_do_timer;
- js_timer.data = 1;
-
- memset(&js_comp_glue, 0, sizeof(struct JS_DATA_SAVE_TYPE));
- js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT;
- js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT;
-
-#ifndef MODULE
-#ifdef CONFIG_JOY_PCI
- js_pci_init();
-#endif
-#ifdef CONFIG_JOY_LIGHTNING
- js_l4_init();
-#endif
-#ifdef CONFIG_JOY_SIDEWINDER
- js_sw_init();
-#endif
-#ifdef CONFIG_JOY_ASSASSIN
- js_as_init();
-#endif
-#ifdef CONFIG_JOY_LOGITECH
- js_lt_init();
-#endif
-#ifdef CONFIG_JOY_THRUSTMASTER
- js_tm_init();
-#endif
-#ifdef CONFIG_JOY_GRAVIS
- js_gr_init();
-#endif
-#ifdef CONFIG_JOY_CREATIVE
- js_cr_init();
-#endif
-#ifdef CONFIG_JOY_ANALOG
- js_an_init();
-#endif
-#ifdef CONFIG_JOY_CONSOLE
- js_console_init();
-#endif
-#ifdef CONFIG_JOY_DB9
- js_db9_init();
-#endif
-#ifdef CONFIG_JOY_TURBOGRAFX
- js_tg_init();
-#endif
-#ifdef CONFIG_JOY_AMIGA
- js_am_init();
-#endif
-#ifdef CONFIG_JOY_MAGELLAN
- js_mag_init();
-#endif
-#ifdef CONFIG_JOY_WARRIOR
- js_war_init();
-#endif
-#ifdef CONFIG_JOY_SPACEORB
- js_orb_init();
-#endif
-#ifdef CONFIG_JOY_SPACEBALL
- js_sball_init();
-#endif
-#endif
-
- return 0;
-}
-
-/*
- * cleanup_module() handles module removal.
- */
-
-#ifdef MODULE
-void cleanup_module(void)
-{
- del_timer(&js_timer);
- devfs_unregister(devfs_handle);
- if (devfs_unregister_chrdev(JOYSTICK_MAJOR, "js"))
- printk(KERN_ERR "js: can't unregister device\n");
-}
-#endif
-
diff --git a/drivers/char/joystick/lightning.c b/drivers/char/joystick/lightning.c
new file mode 100644
index 000000000..69dfd1112
--- /dev/null
+++ b/drivers/char/joystick/lightning.c
@@ -0,0 +1,300 @@
+/*
+ * $Id: lightning.c,v 1.7 2000/05/24 19:36:03 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 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/malloc.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>");
+
+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->driver;
+ 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->driver;
+ 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->driver;
+
+ 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->driver = l4;
+ gameport->open = l4_open;
+ gameport->cooked_read = l4_cooked_read;
+ gameport->calibrate = l4_calibrate;
+ gameport->type = GAMEPORT_EXT;
+
+ if (!i && !j) {
+ gameport->io = L4_PORT;
+ gameport->size = 1;
+ }
+
+ 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
new file mode 100644
index 000000000..e8c77f48e
--- /dev/null
+++ b/drivers/char/joystick/magellan.c
@@ -0,0 +1,210 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/joystick/ns558.c b/drivers/char/joystick/ns558.c
new file mode 100644
index 000000000..f34a18640
--- /dev/null
+++ b/drivers/char/joystick/ns558.c
@@ -0,0 +1,366 @@
+/*
+ * $Id: ns558.c,v 1.11 2000/06/20 23:35:03 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 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/malloc.h>
+#include <linux/isapnp.h>
+
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@ucw.cz>");
+
+#define NS558_ISA 1
+#define NS558_PNP 2
+#define NS558_PCI 3
+
+static int ns558_isa_portlist[] = { 0x201, 0x202, 0x203, 0x204, 0x205, 0x207, 0x209,
+ 0x20b, 0x20c, 0x20e, 0x20f, 0x211, 0x219, 0x101, 0 };
+
+struct ns558 {
+ int type;
+ struct pci_dev *dev;
+ struct ns558 *next;
+ struct gameport gameport;
+};
+
+static struct ns558 *ns558 = NULL;
+
+/*
+ * 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 "Memory allocation failed.\n");
+ return next;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_ISA;
+ port->gameport.io = io;
+ port->gameport.size = (1 << i);
+
+ request_region(port->gameport.io, port->gameport.size, "ns558-isa");
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 ISA at %#x", port->gameport.number, port->gameport.io);
+ if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return port;
+}
+
+#ifdef CONFIG_PCI
+static struct pci_device_id ns558_pci_tbl[] __devinitdata = {
+ { 0x1102, 0x7002, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, /* SB Live! gameport */
+ { 0x125d, 0x1969, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* ESS Solo 1 */
+ { 0x5333, 0xca00, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, /* S3 SonicVibes */
+ { 0, }
+};
+MODULE_DEVICE_TABLE(pci, ns558_pci_tbl);
+
+static int __devinit ns558_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+ int ioport, iolen;
+ int rc;
+ struct ns558 *port;
+
+ rc = pci_enable_device(pdev);
+ if (rc) {
+ printk(KERN_ERR "ns558: Cannot enable PCI gameport (bus %d, devfn %d) error=%d\n",
+ pdev->bus->number, pdev->devfn, rc);
+ return rc;
+ }
+
+ ioport = pci_resource_start(pdev, ent->driver_data);
+ iolen = pci_resource_len(pdev, ent->driver_data);
+
+ if (!request_region(ioport, iolen, "ns558-pci"))
+ return -EBUSY;
+
+ if (!(port = kmalloc(sizeof(struct ns558), GFP_KERNEL))) {
+ printk(KERN_ERR "Memory allocation failed.\n");
+ return -ENOMEM;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = ns558;
+ port->type = NS558_PCI;
+ port->gameport.io = ioport;
+ port->gameport.size = iolen;
+ port->dev = pdev;
+ ns558 = port;
+
+ pdev->driver_data = port;
+
+ gameport_register_port(&port->gameport);
+
+ printk(KERN_INFO "gameport%d: NS558 PCI at %#x", port->gameport.number, port->gameport.io);
+ if (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ printk(" speed %d kHz\n", port->gameport.speed);
+
+ return 0;
+}
+
+static void __devexit ns558_pci_remove(struct pci_dev *pdev)
+{
+ struct ns558 *port = (struct ns558 *)pdev->driver_data;
+ release_region(port->gameport.io, port->gameport.size);
+}
+
+static struct pci_driver ns558_pci_driver = {
+ name: "PCI Gameport",
+ id_table: ns558_pci_tbl,
+ probe: ns558_pci_probe,
+ remove: ns558_pci_remove,
+};
+#endif /* CONFIG_PCI */
+
+
+#ifdef CONFIG_ISAPNP
+/*
+ * PnP IDs:
+ *
+ * CTL00c1 - SB AWE32 PnP
+ * CTL00c3 - SB AWE64 PnP
+ * CTL00f0 - SB16 PnP / Vibra 16x
+ * CTL7001 - SB Vibra16C PnP
+ * CSC0b35 - Crystal ** doesn't have compatibility ID **
+ * TER1141 - Terratec AD1818
+ * YMM0800 - Yamaha OPL3-SA3
+ *
+ * PNPb02f - Generic gameport
+ */
+
+static struct pnp_devid {
+ unsigned int vendor, device;
+} pnp_devids[] = {
+ { ISAPNP_VENDOR('C','T','L'), ISAPNP_DEVICE(0x7002) },
+ { ISAPNP_VENDOR('C','S','C'), ISAPNP_DEVICE(0x0b35) },
+ { ISAPNP_VENDOR('P','N','P'), ISAPNP_DEVICE(0xb02f) },
+ { 0, },
+};
+
+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 "No i/o ports on a gameport? Weird\n");
+ return next;
+ }
+
+ if (dev->activate && dev->activate(dev) < 0) {
+ printk(KERN_ERR "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 "Memory allocation failed.\n");
+ goto deactivate;
+ }
+ memset(port, 0, sizeof(struct ns558));
+
+ port->next = next;
+ port->type = NS558_PNP;
+ port->gameport.io = ioport;
+ port->gameport.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 (port->gameport.size > 1) printk(" size %d", port->gameport.size);
+ 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 CONFIG_ISAPNP
+ struct pci_dev *dev = NULL;
+ struct pnp_devid *devid;
+#endif
+
+/*
+ * Probe for ISA ports.
+ */
+
+ while (ns558_isa_portlist[i])
+ ns558 = ns558_isa_probe(ns558_isa_portlist[i++], ns558);
+
+/*
+ * Probe for PCI ports.
+ */
+#ifdef CONFIG_PCI
+ pci_register_driver(&ns558_pci_driver);
+#endif
+
+/*
+ * Probe for PnP ports.
+ */
+
+#ifdef CONFIG_ISAPNP
+ for (devid = pnp_devids; devid->vendor; devid++) {
+ while ((dev = isapnp_find_dev(NULL, devid->vendor, devid->device, dev))) {
+ ns558 = ns558_pnp_probe(dev, ns558);
+ }
+ }
+#endif
+
+ return -!ns558;
+}
+
+void __exit ns558_exit(void)
+{
+ struct ns558 *port = ns558;
+
+ while (port) {
+ gameport_unregister_port(&port->gameport);
+ switch (port->type) {
+
+#ifdef CONFIG_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->gameport.size);
+ break;
+
+ default:
+ break;
+ }
+
+ port = port->next;
+ }
+
+#ifdef CONFIG_PCI
+ pci_unregister_driver(&ns558_pci_driver);
+#endif
+}
+
+module_init(ns558_init);
+module_exit(ns558_exit);
diff --git a/drivers/char/joystick/pcigame.c b/drivers/char/joystick/pcigame.c
new file mode 100644
index 000000000..0348ba08b
--- /dev/null
+++ b/drivers/char/joystick/pcigame.c
@@ -0,0 +1,198 @@
+/*
+ * $Id: pcigame.c,v 1.6 2000/05/25 12:05:24 vojtech Exp $
+ *
+ * Copyright (c) 2000 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/pci_ids.h>
+#include <linux/init.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->driver;
+ return readb(pcigame->base + pcigame->data->legacy);
+}
+
+static void pcigame_trigger(struct gameport *gameport)
+{
+ struct pcigame *pcigame = gameport->driver;
+ writeb(0xff, pcigame->base + pcigame->data->legacy);
+}
+
+static int pcigame_cooked_read(struct gameport *gameport, int *axes, int *buttons)
+{
+ struct pcigame *pcigame = gameport->driver;
+ 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->driver;
+
+ 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;
+ dev->driver_data = pcigame;
+
+ pcigame->gameport.driver = pcigame;
+ pcigame->gameport.type = GAMEPORT_EXT;
+ 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 = dev->driver_data;
+ 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);
diff --git a/drivers/char/joystick/serio.c b/drivers/char/joystick/serio.c
new file mode 100644
index 000000000..9595f0a6c
--- /dev/null
+++ b/drivers/char/joystick/serio.c
@@ -0,0 +1,132 @@
+/*
+ * $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>");
+
+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 = NULL;
+static struct serio_dev *serio_dev = NULL;
+static int serio_number = 0;
+
+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
new file mode 100644
index 000000000..453e674d7
--- /dev/null
+++ b/drivers/char/joystick/serport.c
@@ -0,0 +1,220 @@
+/*
+ * $Id: serport.c,v 1.4 2000/05/29 10:54:53 vojtech Exp $
+ *
+ * Copyright (c) 1999-2000 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/malloc.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];
+
+ sprintf(name, tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+
+ 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);
diff --git a/drivers/char/joystick/sidewinder.c b/drivers/char/joystick/sidewinder.c
new file mode 100644
index 000000000..861966b4e
--- /dev/null
+++ b/drivers/char/joystick/sidewinder.c
@@ -0,0 +1,756 @@
+/*
+ * $Id: sidewinder.c,v 1.14 2000/05/29 11:27:55 vojtech Exp $
+ *
+ * Copyright (c) 1998-2000 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/malloc.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 }};
+
+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_key(dev + i, ABS_X, GB(i*15+3,1) - GB(i*15+2,1));
+ input_report_key(dev + i, ABS_Y, GB(i*15+0,1) - GB(i*15+1,1));
+
+ for (j = 0; j < 10; j++)
+ input_report_key(dev, 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;
+
+ 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);
diff --git a/drivers/char/joystick/spaceball.c b/drivers/char/joystick/spaceball.c
new file mode 100644
index 000000000..4f5059330
--- /dev/null
+++ b/drivers/char/joystick/spaceball.c
@@ -0,0 +1,231 @@
+/*
+ * $Id: spaceball.c,v 1.6 2000/05/29 11:19:51 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/malloc.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_Y, ABS_Z, ABS_RX, ABS_RY, ABS_RZ };
+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, d;
+
+ if (spaceball->idx < 2) return;
+
+ 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 != 16) return;
+ for (i = 0; i < 6; i++) {
+ d = ((data[2 * i + 3] << 8) | data[2 * i + 2]);
+ input_report_abs(dev, spaceball_axes[i], d - ((d & 0x8000) ? 0x10000 : 0));
+ }
+ break;
+
+ case '.': /* Button data, part2 */
+ if (spaceball->idx != 4) return;
+ input_report_key(dev, BTN_LEFT, data[2] & 1);
+ input_report_key(dev, BTN_RIGHT, 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 0x0d characters which can
+ * occur in the axis values. ^M, ^Q and ^S all mean 0x0d, depending (I think)
+ * on whether the axis value is increasing, decreasing, or same as before.
+ * (I don't see why this is useful).
+ */
+
+static void spaceball_interrupt(struct serio *serio, unsigned char data, unsigned int flags)
+{
+ struct spaceball *spaceball = serio->private;
+
+ switch (data) {
+ case 0xd:
+ if (spaceball->idx)
+ spaceball_process_packet(spaceball);
+ spaceball->idx = 0;
+ spaceball->escape = 0;
+ return;
+ case 'M':
+ case 'Q':
+ case 'S':
+ if (spaceball->escape)
+ data = 0xd;
+ case '^':
+ spaceball->escape ^= 1;
+ default:
+ if (spaceball->escape) {
+ printk(KERN_WARNING "spaceball.c: Unknown escaped character: %#x\n", data);
+ spaceball->escape = 0;
+ }
+ 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_LEFT)] = BIT(BTN_LEFT) | BIT(BTN_RIGHT);
+
+ for (i = 0; i < 6; i++) {
+ t = spaceball_axes[i];
+ set_bit(t, spaceball->dev.absbit);
+ spaceball->dev.absmin[t] = i < 3 ? -10000 : -2000;
+ spaceball->dev.absmax[t] = i < 3 ? 10000 : 2000;
+ spaceball->dev.absflat[t] = i < 3 ? 50 : 10;
+ spaceball->dev.absfuzz[t] = i < 3 ? 12 : 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);
diff --git a/drivers/char/joystick/spaceorb.c b/drivers/char/joystick/spaceorb.c
new file mode 100644
index 000000000..866e1ba50
--- /dev/null
+++ b/drivers/char/joystick/spaceorb.c
@@ -0,0 +1,225 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/joystick/tmdc.c b/drivers/char/joystick/tmdc.c
new file mode 100644
index 000000000..f356f7dd5
--- /dev/null
+++ b/drivers/char/joystick/tmdc.c
@@ -0,0 +1,348 @@
+/*
+ * $Id: tmdc.c,v 1.18 2000/06/08 19:59:59 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/malloc.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_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_PAD 10
+#define TMDC_BTN_JOY 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 unsigned char tmdc_abs[TMDC_ABS] =
+ { ABS_X, ABS_Y, ABS_RUDDER, ABS_THROTTLE, ABS_RX, ABS_RY, ABS_RZ };
+static unsigned char tmdc_abs_hat[TMDC_ABS_HAT] =
+ { ABS_HAT0X, ABS_HAT0Y, ABS_HAT1X, ABS_HAT1Y };
+static unsigned short tmdc_btn_pad[TMDC_BTN_PAD] =
+ { BTN_A, BTN_B, BTN_C, BTN_X, BTN_Y, BTN_Z, BTN_START, BTN_SELECT, BTN_TL, BTN_TR };
+static unsigned short tmdc_btn_joy[TMDC_BTN_JOY] =
+ { 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 };
+
+struct tmdc {
+ struct gameport *gameport;
+ struct timer_list timer;
+ struct input_dev dev[2];
+ char name[2][64];
+ int mode[2];
+ 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;
+
+ 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 < data[j][TMDC_BYTE_DEF] >> 4; i++)
+ input_report_abs(dev, tmdc_abs[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));
+
+ for (i = 0; i < 4; i++)
+ input_report_key(dev, tmdc_btn_joy[i],
+ (data[j][tmdc_byte_d[0]] >> (i + 4)) & 1);
+ for (i = 0; i < 2; i++)
+ input_report_key(dev, tmdc_btn_joy[i + 4],
+ (data[j][tmdc_byte_d[1]] >> (i + 6)) & 1);
+
+ break;
+
+ case TMDC_MODE_3DRP:
+ case TMDC_MODE_FGP:
+
+ for (i = 0; i < 10; i++)
+ input_report_key(dev, tmdc_btn_pad[i],
+ (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
+
+ break;
+
+ default:
+
+ for (i = 0; i < ((data[j][TMDC_BYTE_DEF] & 0xf) << 3) && i < TMDC_BTN_JOY; i++)
+ input_report_key(dev, tmdc_btn_joy[i],
+ (data[j][tmdc_byte_d[i >> 3]] >> (i & 7)) & 1);
+
+ break;
+
+ }
+ }
+
+ 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 tmdc *tmdc;
+ struct js_tm_models {
+ unsigned char id;
+ char *name;
+ char abs;
+ char hats;
+ char joybtn;
+ char padbtn;
+ } models[] = { { 1, "ThrustMaster Millenium 3D Inceptor", 6, 0, 6, 0 },
+ { 3, "ThrustMaster Rage 3D Gamepad", 2, 0, 0, 10 },
+ { 163, "Thrustmaster Fusion GamePad", 2, 0, 0, 10 },
+ { 0, "Unknown %d-axis, %d-button TM device %d", 0, 0, 0, 0 }};
+ unsigned char data[2][TMDC_MAX_LENGTH];
+ int i, j, 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++);
+
+ if (!models[m].id) {
+ models[m].abs = data[j][TMDC_BYTE_DEF] >> 4;
+ models[m].joybtn = (data[j][TMDC_BYTE_DEF] & 0xf) << 3;
+ }
+
+ sprintf(tmdc->name[j], models[m].name, models[m].abs, models[m].joybtn, 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++) {
+ set_bit(tmdc_abs[i], tmdc->dev[j].absbit);
+ tmdc->dev[j].absmin[tmdc_abs[i]] = 8;
+ tmdc->dev[j].absmax[tmdc_abs[i]] = 248;
+ tmdc->dev[j].absfuzz[tmdc_abs[i]] = 2;
+ tmdc->dev[j].absflat[tmdc_abs[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 (i = 0; i < models[m].joybtn && i < TMDC_BTN_JOY; i++)
+ set_bit(tmdc_btn_joy[i], tmdc->dev[j].keybit);
+
+ for (i = 0; i < models[m].padbtn && i < TMDC_BTN_PAD; i++)
+ set_bit(tmdc_btn_pad[i], tmdc->dev[j].keybit);
+
+ 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);
diff --git a/drivers/char/joystick/turbografx.c b/drivers/char/joystick/turbografx.c
new file mode 100644
index 000000000..0e2dedcd0
--- /dev/null
+++ b/drivers/char/joystick/turbografx.c
@@ -0,0 +1,258 @@
+/*
+ * $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_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
new file mode 100644
index 000000000..7000b8560
--- /dev/null
+++ b/drivers/char/joystick/warrior.c
@@ -0,0 +1,212 @@
+/*
+ * $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/malloc.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);
diff --git a/drivers/char/lp.c b/drivers/char/lp.c
index c2df7ea18..bbbcad9a7 100644
--- a/drivers/char/lp.c
+++ b/drivers/char/lp.c
@@ -675,9 +675,9 @@ static int lp_register(int nr, struct parport *port)
lp_reset(nr);
sprintf (name, "%d", nr);
- devfs_register (devfs_handle, name, 0,
+ devfs_register (devfs_handle, name,
DEVFS_FL_DEFAULT, LP_MAJOR, nr,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&lp_fops, NULL);
printk(KERN_INFO "lp%d: using %s (%s).\n", nr, port->name,
diff --git a/drivers/char/mem.c b/drivers/char/mem.c
index 40e6c7ba6..3b5a2c497 100644
--- a/drivers/char/mem.c
+++ b/drivers/char/mem.c
@@ -18,7 +18,6 @@
#include <linux/mman.h>
#include <linux/random.h>
#include <linux/init.h>
-#include <linux/joystick.h>
#include <linux/raw.h>
#include <linux/capability.h>
@@ -608,9 +607,9 @@ void __init memory_devfs_register (void)
int i;
for (i=0; i<(sizeof(list)/sizeof(*list)); i++)
- devfs_register (NULL, list[i].name, 0, DEVFS_FL_NONE,
+ devfs_register (NULL, list[i].name, DEVFS_FL_NONE,
MEM_MAJOR, list[i].minor,
- list[i].mode | S_IFCHR, 0, 0,
+ list[i].mode | S_IFCHR,
list[i].fops, NULL);
}
@@ -654,13 +653,6 @@ int __init chr_dev_init(void)
#ifdef CONFIG_SPARCAUDIO
sparcaudio_init();
#endif
-#ifdef CONFIG_JOYSTICK
- /*
- * Some joysticks only appear when the sound card they are
- * connected to is configured. Keep the sound/joystick ordering.
- */
- js_init();
-#endif
#if CONFIG_QIC02_TAPE
qic02_tape_init();
#endif
diff --git a/drivers/char/misc.c b/drivers/char/misc.c
index df1e97494..c26a58eea 100644
--- a/drivers/char/misc.c
+++ b/drivers/char/misc.c
@@ -193,9 +193,9 @@ int misc_register(struct miscdevice * misc)
if (!devfs_handle)
devfs_handle = devfs_mk_dir (NULL, "misc", 4, NULL);
misc->devfs_handle =
- devfs_register (devfs_handle, misc->name, 0, DEVFS_FL_NONE,
+ devfs_register (devfs_handle, misc->name, DEVFS_FL_NONE,
MISC_MAJOR, misc->minor,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP,
misc->fops, NULL);
/*
diff --git a/drivers/char/ppdev.c b/drivers/char/ppdev.c
index 819ed0b1a..af52cf98f 100644
--- a/drivers/char/ppdev.c
+++ b/drivers/char/ppdev.c
@@ -665,7 +665,7 @@ static int __init ppdev_init (void)
devfs_handle = devfs_mk_dir (NULL, "parports", 0, NULL);
devfs_register_series (devfs_handle, "%u", PARPORT_MAX,
DEVFS_FL_DEFAULT, PP_MAJOR, 0,
- S_IFCHR | S_IRUGO | S_IWUGO, 0, 0,
+ S_IFCHR | S_IRUGO | S_IWUGO,
&pp_fops, NULL);
printk (KERN_INFO PP_VERSION "\n");
diff --git a/drivers/char/stallion.c b/drivers/char/stallion.c
index fdaeeaea0..ba1b9caa9 100644
--- a/drivers/char/stallion.c
+++ b/drivers/char/stallion.c
@@ -3194,7 +3194,7 @@ int __init stl_init(void)
devfs_handle = devfs_mk_dir (NULL, "staliomem", 9, NULL);
devfs_register_series (devfs_handle, "%u", 4, DEVFS_FL_DEFAULT,
STL_SIOMEMMAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&stl_fsiomem, NULL);
/*
diff --git a/drivers/char/tpqic02.c b/drivers/char/tpqic02.c
index 133f19aac..09b502a72 100644
--- a/drivers/char/tpqic02.c
+++ b/drivers/char/tpqic02.c
@@ -2905,37 +2905,37 @@ int __init qic02_tape_init(void)
#endif
return -ENODEV;
}
- devfs_register (NULL, "ntpqic11", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic11", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 2,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic11", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic11", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 3,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic24", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic24", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 4,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic24", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic24", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 5,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic120", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic120", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 6,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic120", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic120", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 7,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "ntpqic150", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "ntpqic150", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 8,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
- devfs_register (NULL, "tpqic150", 0, DEVFS_FL_NONE,
+ devfs_register (NULL, "tpqic150", DEVFS_FL_DEFAULT,
QIC02_TAPE_MAJOR, 9,
- S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR | S_IRGRP | S_IWGRP,
&qic02_tape_fops, NULL);
init_waitqueue_head(&qic02_tape_transfer);
/* prepare timer */
diff --git a/drivers/char/tty_io.c b/drivers/char/tty_io.c
index 8a03fed26..613b2f967 100644
--- a/drivers/char/tty_io.c
+++ b/drivers/char/tty_io.c
@@ -1971,8 +1971,6 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
{
#ifdef CONFIG_DEVFS_FS
umode_t mode = S_IFCHR | S_IRUSR | S_IWUSR;
- uid_t uid = 0;
- gid_t gid = 0;
struct tty_struct tty;
char buf[32];
@@ -1996,14 +1994,11 @@ void tty_register_devfs (struct tty_driver *driver, unsigned int flags,
}
# ifdef CONFIG_UNIX98_PTYS
if ( (driver->major >= UNIX98_PTY_SLAVE_MAJOR) &&
- (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) ) {
- uid = current->uid;
- gid = current->gid;
- }
+ (driver->major < UNIX98_PTY_SLAVE_MAJOR + UNIX98_NR_MAJORS) )
+ flags |= DEVFS_FL_CURRENT_OWNER;
# endif
- devfs_register (NULL, tty_name (&tty, buf), 0,flags | DEVFS_FL_DEFAULT,
- driver->major, minor, mode, uid, gid,
- &tty_fops, NULL);
+ devfs_register (NULL, tty_name (&tty, buf), flags | DEVFS_FL_DEFAULT,
+ driver->major, minor, mode, &tty_fops, NULL);
#endif /* CONFIG_DEVFS_FS */
}
diff --git a/drivers/char/vc_screen.c b/drivers/char/vc_screen.c
index 5138c76b8..67ff8d856 100644
--- a/drivers/char/vc_screen.c
+++ b/drivers/char/vc_screen.c
@@ -476,12 +476,12 @@ void vcs_make_devfs (unsigned int index, int unregister)
}
else
{
- devfs_register (devfs_handle, name + 1, 0, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, name + 1, DEVFS_FL_DEFAULT,
VCS_MAJOR, index + 1,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
- devfs_register (devfs_handle, name, 0, DEVFS_FL_DEFAULT,
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
+ devfs_register (devfs_handle, name, DEVFS_FL_DEFAULT,
VCS_MAJOR, index + 129,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
}
#endif /* CONFIG_DEVFS_FS */
}
@@ -496,12 +496,12 @@ int __init vcs_init(void)
printk("unable to get major %d for vcs device", VCS_MAJOR);
devfs_handle = devfs_mk_dir (NULL, "vcc", 3, NULL);
- devfs_register (devfs_handle, "0", 1, DEVFS_FL_DEFAULT,
+ devfs_register (devfs_handle, "0", DEVFS_FL_DEFAULT,
VCS_MAJOR, 0,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
- devfs_register (devfs_handle, "a", 1, DEVFS_FL_DEFAULT,
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
+ devfs_register (devfs_handle, "a", DEVFS_FL_DEFAULT,
VCS_MAJOR, 128,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0, &vcs_fops, NULL);
+ S_IFCHR | S_IRUSR | S_IWUSR, &vcs_fops, NULL);
return error;
}
diff --git a/drivers/char/videodev.c b/drivers/char/videodev.c
index ababd833f..4a3bfb859 100644
--- a/drivers/char/videodev.c
+++ b/drivers/char/videodev.c
@@ -62,7 +62,7 @@ LIST_HEAD(videodev_proc_list);
#ifdef CONFIG_VIDEO_BT848
-extern int tuner_init_module(struct video_init *);
+extern int i2c_tuner_init(struct video_init *);
#endif
#ifdef CONFIG_VIDEO_BWQCAM
extern int init_bw_qcams(struct video_init *);
@@ -79,7 +79,7 @@ extern int init_zoran_cards(struct video_init *);
static struct video_init video_init_list[]={
#ifdef CONFIG_VIDEO_BT848
- {"i2c-tuner", tuner_init_module},
+ {"i2c-tuner", i2c_tuner_init},
#endif
#ifdef CONFIG_VIDEO_BWQCAM
{"bw-qcam", init_bw_qcams},
@@ -286,6 +286,14 @@ static int videodev_proc_read(char *page, char **start, off_t off,
PRINT_VID_TYPE(VID_TYPE_MJPEG_ENCODER);
out += sprintf (out, "\n");
out += sprintf (out, "hardware : 0x%x\n", vfd->hardware);
+#if 0
+ out += sprintf (out, "channels : %d\n", d->vcap.channels);
+ out += sprintf (out, "audios : %d\n", d->vcap.audios);
+ out += sprintf (out, "maxwidth : %d\n", d->vcap.maxwidth);
+ out += sprintf (out, "maxheight : %d\n", d->vcap.maxheight);
+ out += sprintf (out, "minwidth : %d\n", d->vcap.minwidth);
+ out += sprintf (out, "minheight : %d\n", d->vcap.minheight);
+#endif
skip:
len = out - page;
@@ -351,6 +359,8 @@ static void videodev_proc_create_dev (struct video_device *vfd, char *name)
d->vdev = vfd;
strcpy (d->name, name);
+ /* How can I get capability information ? */
+
list_add (&d->proc_list, &videodev_proc_list);
}
@@ -459,9 +469,9 @@ int video_register_device(struct video_device *vfd, int type)
* has serious privacy issues.
*/
vfd->devfs_handle =
- devfs_register (NULL, name, 0, DEVFS_FL_DEFAULT,
+ devfs_register (NULL, name, DEVFS_FL_DEFAULT,
VIDEO_MAJOR, vfd->minor,
- S_IFCHR | S_IRUSR | S_IWUSR, 0, 0,
+ S_IFCHR | S_IRUSR | S_IWUSR,
&video_fops, NULL);
#if defined(CONFIG_PROC_FS) && defined(CONFIG_VIDEO_PROC_FS)
@@ -564,4 +574,3 @@ EXPORT_SYMBOL(video_unregister_device);
MODULE_AUTHOR("Alan Cox");
MODULE_DESCRIPTION("Device registrar for Video4Linux drivers");
-