diff options
Diffstat (limited to 'drivers/char')
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"); - |