summaryrefslogtreecommitdiffstats
path: root/drivers/char/joystick
diff options
context:
space:
mode:
authorRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
committerRalf Baechle <ralf@linux-mips.org>2000-02-04 07:40:19 +0000
commit33263fc5f9ac8e8cb2b22d06af3ce5ac1dd815e4 (patch)
tree2d1b86a40bef0958a68cf1a2eafbeb0667a70543 /drivers/char/joystick
parent216f5f51aa02f8b113aa620ebc14a9631a217a00 (diff)
Merge with Linux 2.3.32.
Diffstat (limited to 'drivers/char/joystick')
-rw-r--r--drivers/char/joystick/Config.in45
-rw-r--r--drivers/char/joystick/Makefile69
-rw-r--r--drivers/char/joystick/joy-amiga.c18
-rw-r--r--drivers/char/joystick/joy-analog.c189
-rw-r--r--drivers/char/joystick/joy-analog.h48
-rw-r--r--drivers/char/joystick/joy-assassin.c (renamed from drivers/char/joystick/joy-assasin.c)89
-rw-r--r--drivers/char/joystick/joy-console.c470
-rw-r--r--drivers/char/joystick/joy-creative.c287
-rw-r--r--drivers/char/joystick/joy-db9.c182
-rw-r--r--drivers/char/joystick/joy-gravis.c56
-rw-r--r--drivers/char/joystick/joy-lightning.c33
-rw-r--r--drivers/char/joystick/joy-logitech.c539
-rw-r--r--drivers/char/joystick/joy-magellan.c397
-rw-r--r--drivers/char/joystick/joy-pci.c273
-rw-r--r--drivers/char/joystick/joy-sidewinder.c797
-rw-r--r--drivers/char/joystick/joy-spaceball.c347
-rw-r--r--drivers/char/joystick/joy-spaceorb.c305
-rw-r--r--drivers/char/joystick/joy-thrustmaster.c163
-rw-r--r--drivers/char/joystick/joy-turbografx.c95
-rw-r--r--drivers/char/joystick/joy-warrior.c318
-rw-r--r--drivers/char/joystick/joystick.c526
21 files changed, 3862 insertions, 1384 deletions
diff --git a/drivers/char/joystick/Config.in b/drivers/char/joystick/Config.in
index 810decada..3e371744e 100644
--- a/drivers/char/joystick/Config.in
+++ b/drivers/char/joystick/Config.in
@@ -1,19 +1,34 @@
#
-# Joystick lowlevel driver configuration
+# Joystick driver
#
-dep_tristate ' Classic PC analog joysticks and gamepads' CONFIG_JOY_ANALOG $CONFIG_JOYSTICK
-dep_tristate ' FPGaming and MadCatz A3D controllers' CONFIG_JOY_ASSASIN $CONFIG_JOYSTICK
-dep_tristate ' Gravis GrIP joysticks and gamepads' CONFIG_JOY_GRAVIS $CONFIG_JOYSTICK
-dep_tristate ' Logitech Digital joysticks and gamepads' CONFIG_JOY_LOGITECH $CONFIG_JOYSTICK
-dep_tristate ' Microsoft SideWinder, Genius Digital joysticks and gamepads' CONFIG_JOY_SIDEWINDER $CONFIG_JOYSTICK
-dep_tristate ' ThrustMaster DirectConnect joysticks and gamepads' CONFIG_JOY_THRUSTMASTER $CONFIG_JOYSTICK
-dep_tristate ' PDPI Lightning 4 gamecards' CONFIG_JOY_LIGHTNING $CONFIG_JOYSTICK
-if [ "$CONFIG_PARPORT" != "n" ]; then
- dep_tristate ' NES, SNES, PSX, Multisystem joysticks and gamepads' CONFIG_JOY_CONSOLE $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' Sega, Multisystem joysticks and gamepads' CONFIG_JOY_DB9 $CONFIG_JOYSTICK $CONFIG_PARPORT
- dep_tristate ' TurboGraFX Multisystem joystick interface' CONFIG_JOY_TURBOGRAFX $CONFIG_JOYSTICK $CONFIG_PARPORT
-fi
-if [ "$CONFIG_AMIGA" = "y" ]; then
- dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+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
+ 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
+ if [ "$CONFIG_AMIGA" = "y" ]; then
+ dep_tristate ' Amiga joysticks' CONFIG_JOY_AMIGA $CONFIG_JOYSTICK
+ fi
fi
+
+endmenu
diff --git a/drivers/char/joystick/Makefile b/drivers/char/joystick/Makefile
index 3339fc83f..2bb5870b0 100644
--- a/drivers/char/joystick/Makefile
+++ b/drivers/char/joystick/Makefile
@@ -1,23 +1,18 @@
#
# Makefile for the joystick drivers.
#
-# Note! Dependencies are done automagically by 'make dep', which also
-# removes any old dependencies. DON'T put your own dependencies here
-# unless it's something special (ie not a .c file).
-#
-# Note 2! The CFLAGS definitions are now inherited from the
-# parent makes..
-#
O_TARGET := js.o
+OX_OBJS :=
O_OBJS :=
+MX_OBJS :=
M_OBJS :=
ifeq ($(CONFIG_JOYSTICK),y)
-O_OBJS += joystick.o
+OX_OBJS += joystick.o
else
ifeq ($(CONFIG_JOYSTICK),m)
- M_OBJS += joystick.o
+ MX_OBJS += joystick.o
endif
endif
@@ -37,11 +32,11 @@ else
endif
endif
-ifeq ($(CONFIG_JOY_ASSASIN),y)
-O_OBJS += joy-assasin.o
+ifeq ($(CONFIG_JOY_ASSASSIN),y)
+O_OBJS += joy-assassin.o
else
- ifeq ($(CONFIG_JOY_ASSASIN),m)
- M_OBJS += joy-assasin.o
+ ifeq ($(CONFIG_JOY_ASSASSIN),m)
+ M_OBJS += joy-assassin.o
endif
endif
@@ -53,6 +48,14 @@ else
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
@@ -85,6 +88,22 @@ else
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
@@ -93,6 +112,22 @@ else
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
@@ -109,4 +144,12 @@ else
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
+
include $(TOPDIR)/Rules.make
diff --git a/drivers/char/joystick/joy-amiga.c b/drivers/char/joystick/joy-amiga.c
index 918025040..5e3198f70 100644
--- a/drivers/char/joystick/joy-amiga.c
+++ b/drivers/char/joystick/joy-amiga.c
@@ -1,7 +1,9 @@
/*
* joy-amiga.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -36,13 +38,14 @@
#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 js_am[]={0,0};
+static int __initdata js_am[] = { 0, 0 };
/*
* js_am_read() reads and Amiga joystick data.
@@ -69,7 +72,7 @@ static int js_am_read(void *info, int **axes, int **buttons)
axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
data = ~(data ^ (data << 1));
- axes[0][0] = ((data >> 1) & 1) - ((data >> 9) & 1);
+ axes[0][1] = ((data >> 1) & 1) - ((data >> 9) & 1);
return 0;
}
@@ -114,11 +117,14 @@ static void __init js_am_init_corr(struct js_corr **corr)
}
#ifndef MODULE
-void __init js_am_setup(char *str, int *ints)
+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
@@ -148,8 +154,8 @@ int __init js_am_init(void)
#ifdef MODULE
void cleanup_module(void)
{
- while (js_am_port != NULL) {
- if (js_am_port->devs[0] != NULL)
+ 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);
}
diff --git a/drivers/char/joystick/joy-analog.c b/drivers/char/joystick/joy-analog.c
index 7c1c9719d..a4a7b9849 100644
--- a/drivers/char/joystick/joy-analog.c
+++ b/drivers/char/joystick/joy-analog.c
@@ -1,7 +1,9 @@
/*
* joy-analog.c Version 1.2
*
- * Copyright (c) 1996-1998 Vojtech Pavlik
+ * Copyright (c) 1996-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -30,15 +32,21 @@
*/
#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
+#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;
@@ -46,53 +54,102 @@ static struct js_port* js_an_port __initdata = NULL;
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_an, "2-24i");
-static int 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,-1,0,0};
+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_an_info *info = xinfo;
+ struct js_ax_info *info = xinfo;
+ struct js_an_info *an = &info->an;
+ int io = info->io;
+ unsigned long flags;
unsigned char buf[4];
- int time[4];
- unsigned char u, v, a;
- unsigned int t, t1;
+ unsigned int time[4];
+ unsigned char u, v, w;
+ unsigned int p, q, r, s, t;
int i, j;
- int timeout;
- int io = info->io;
- timeout = (JS_AN_MAX_TIME * js_time_speed_a) >> 10;
-
- info->buttons = (~inb(io) & JS_AN_BUTTONS_STD) >> 4;
+ an->buttons = ~inb(io) >> 4;
i = 0;
- u = a = ((info->mask[0] | info->mask[1]) & JS_AN_AXES_STD) | (info->extensions & JS_AN_HAT_FCS)
- | ((info->extensions & JS_AN_BUTTONS_PXY_XY) >> 2) | ((info->extensions & JS_AN_BUTTONS_PXY_UV) >> 4);
-
+ 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);
- t = js_get_time_a();
+ GET_TIME(r);
+ __restore_flags(flags);
+ t = r;
+ v = w;
do {
- v = inb(io) & a;
- t1 = js_get_time_a();
- if (u ^ v) {
- time[i] = js_delta_a(t1,t);
+ 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;
- u = v;
i++;
}
- } while (v && js_delta_a(t1,t) < timeout);
+ } while (v && (i < 4) && (DELTA(t,r) < q));
- for (--i; i >= 0; i--)
+ v <<= 4;
+
+ for (--i; i >= 0; i--) {
+ v |= buf[i];
for (j = 0; j < 4; j++)
- if (buf[i] & (1 << j)) info->axes[j] = (time[i] << 10) / js_time_speed_a;
+ if (buf[i] & (1 << j)) an->axes[j] = (DELTA(time[i],r) << 10) / info->speed;
+ }
- js_an_decode(info, axes, buttons);
+ js_an_decode(an, axes, buttons);
- return 0;
+ return -(v != w);
}
/*
@@ -116,12 +173,53 @@ static int js_an_close(struct js_dev *jd)
}
/*
+ * 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_an_info info;
+ struct js_ax_info info, *ax;
int i, numdev;
unsigned char u;
@@ -129,7 +227,6 @@ static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct j
if (check_region(io, 1)) return port;
- if (((u = inb(io)) & 3) == 3) return port;
outb(0xff,io);
u = inb(io);
udelay(JS_AN_MAX_TIME);
@@ -138,31 +235,41 @@ static struct js_port __init *js_an_probe(int io, int mask0, int mask1, struct j
if (!u) return port;
if (u & 0xf0) return port;
- if ((numdev = js_an_probe_devs(&info, u, mask0, mask1, port)) <= 0)
+ 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_an_info), js_an_read);
+ 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\n",
- js_register_device(port, i, js_an_axes(i, &info), js_an_buttons(i, &info),
- js_an_name(i, &info), js_an_open, js_an_close),
- js_an_name(i, &info), info.io);
-
- js_an_read(port->info, port->axes, port->buttons);
- js_an_init_corr(port->info, port->axes, port->corr, 8);
+ printk(KERN_INFO "js%d: %s at %#x ["TIME_NAME" timer, %d %sHz clock, %d ns res]\n",
+ js_register_device(port, i, js_an_axes(i, &ax->an), js_an_buttons(i, &ax->an),
+ js_an_name(i, &ax->an), js_an_open, js_an_close),
+ js_an_name(i, &ax->an),
+ ax->io,
+ ax->speed > 10000 ? (ax->speed + 800) / 1000 : ax->speed,
+ ax->speed > 10000 ? "M" : "k",
+ ax->loop * 1000000000 / JS_AN_LOOP_TIME / ax->speed);
+
+ js_an_read(ax, port->axes, port->buttons);
+ js_an_init_corr(&ax->an, port->axes, port->corr, 8);
return port;
}
#ifndef MODULE
-void __init js_an_setup(char *str, int *ints)
+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
@@ -193,11 +300,11 @@ int __init js_an_init(void)
void cleanup_module(void)
{
int i;
- struct js_an_info *info;
+ struct js_ax_info *info;
- while (js_an_port != NULL) {
+ while (js_an_port) {
for (i = 0; i < js_an_port->ndevs; i++)
- if (js_an_port->devs[i] != NULL)
+ if (js_an_port->devs[i])
js_unregister_device(js_an_port->devs[i]);
info = js_an_port->info;
release_region(info->io, 1);
diff --git a/drivers/char/joystick/joy-analog.h b/drivers/char/joystick/joy-analog.h
index 84479fcd1..a1644350c 100644
--- a/drivers/char/joystick/joy-analog.h
+++ b/drivers/char/joystick/joy-analog.h
@@ -1,13 +1,15 @@
/*
* joy-analog.h Version 1.2
*
- * Copyright (c) 1996-1998 Vojtech Pavlik
+ * 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-assasin.c, and joy-lightning.c
+ * is: joy-analog.c, joy-assassin.c, and joy-lightning.c
*/
/*
@@ -30,6 +32,8 @@
* 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
@@ -53,7 +57,6 @@ static struct {
} js_an_hat_to_axis[] = {{ 0, 0}, { 0,-1}, { 1, 0}, { 0, 1}, {-1, 0}};
struct js_an_info {
- int io;
unsigned char mask[2];
unsigned int extensions;
int axes[4];
@@ -75,7 +78,7 @@ static void js_an_decode(struct js_an_info *info, int **axes, int **buttons)
if (info->mask[1] & JS_AN_BUTTONS_STD) buttons[1][0] = 0;
if (info->extensions & JS_AN_ANY_CHF) {
- switch (info->buttons) {
+ 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;
@@ -134,19 +137,6 @@ static void js_an_decode(struct js_an_info *info, int **axes, int **buttons)
}
}
-/*
- * js_an_count_bits() counts set bits in a byte.
- */
-
-static inline int js_an_count_bits(unsigned long c)
-{
- int i = 0;
- while (c) {
- i += c & 1;
- c >>= 1;
- }
- return i;
-}
/*
* js_an_init_corr() initializes the correction values for
@@ -158,7 +148,7 @@ static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct j
int i, j, t;
for (i = 0; i < 2; i++)
- for (j = 0; j < js_an_count_bits(info->mask[i] & 0xf); j++) {
+ 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)) {
@@ -175,9 +165,9 @@ static void __init js_an_init_corr(struct js_an_info *info, int **axes, struct j
corr[i][j].coef[3] = (1 << 29) / (t - (t >> 2) + 1);
}
- i = js_an_count_bits(info->mask[0] & 0xf);
+ i = hweight8(info->mask[0] & 0xf);
- for (j = i; j < i + (js_an_count_bits(info->extensions & JS_AN_HATS_ALL) << 1); j++) {
+ 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;
@@ -204,6 +194,7 @@ static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0
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);
@@ -212,7 +203,7 @@ static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0
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_U);
+ info->extensions &= ~(JS_AN_BUTTON_PXY_Y | JS_AN_BUTTON_PXY_V);
}
if (info->extensions & JS_AN_ANY_CHF) {
info->mask[0] |= 0xf0;
@@ -233,8 +224,7 @@ static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0
info->mask[0] = 0xcc; /* joystick 1 */
break;
case 0xf:
- info->mask[0] = 0x33; /* joysticks 0 and 1 */
- info->mask[1] = 0xcc;
+ info->mask[0] = 0xff; /* 4-axis 4-button joystick */
break;
default:
printk(KERN_WARNING "joy-analog: Unknown joystick device detected "
@@ -252,7 +242,7 @@ static int __init js_an_probe_devs(struct js_an_info *info, int exist, int mask0
static inline int js_an_axes(int i, struct js_an_info *info)
{
- return js_an_count_bits(info->mask[i] & 0x0f) + js_an_count_bits(info->extensions & JS_AN_HATS_ALL) * 2;
+ return hweight8(info->mask[i] & 0x0f) + hweight8(info->extensions & JS_AN_HATS_ALL) * 2;
}
/*
@@ -261,9 +251,9 @@ static inline int js_an_axes(int i, struct js_an_info *info)
static inline int js_an_buttons(int i, struct js_an_info *info)
{
- return js_an_count_bits(info->mask[i] & 0xf0) +
+ return hweight8(info->mask[i] & 0xf0) +
(info->extensions & JS_AN_BUTTONS_CHF) * 2 +
- js_an_count_bits(info->extensions & JS_AN_BUTTONS_PXY);
+ hweight8(info->extensions & JS_AN_BUTTONS_PXY);
}
/*
@@ -276,13 +266,13 @@ static char __init *js_an_name(int i, struct js_an_info *info)
{
sprintf(js_an_name_buf, "Analog %d-axis %d-button",
- js_an_count_bits(info->mask[i] & 0x0f),
+ 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,
- js_an_count_bits(info->extensions & JS_AN_HATS_ALL));
+ hweight8(info->extensions & JS_AN_HATS_ALL));
strcat(js_an_name_buf, " joystick");
@@ -291,7 +281,7 @@ static char __init *js_an_name(int i, struct js_an_info *info)
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-button" : "");
+ info->extensions & JS_AN_BUTTONS_PXY ? " XY/UV" : "");
return js_an_name_buf;
}
diff --git a/drivers/char/joystick/joy-assasin.c b/drivers/char/joystick/joy-assassin.c
index 731c6e56a..b76ba8e36 100644
--- a/drivers/char/joystick/joy-assasin.c
+++ b/drivers/char/joystick/joy-assassin.c
@@ -1,12 +1,14 @@
/*
- * joy-assasin.c Version 1.2
+ * joy-assassin.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
* This is a module for the Linux joystick driver, supporting
- * joysticks using FP-Gaming's Assasin 3D protocol.
+ * joysticks using FP-Gaming's Assassin 3D protocol.
*/
/*
@@ -38,13 +40,13 @@
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/string.h>
+#include <linux/init.h>
-#define JS_AS_MAX_START 250
-#define JS_AS_MAX_STROBE 50
-#define JS_AS_MAX_TIME 2400
+#define JS_AS_MAX_START 1000
+#define JS_AS_DELAY_READ 3000
#define JS_AS_MAX_LENGTH 40
-#define JS_AS_MODE_A3D 1 /* Assasin 3D */
+#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 */
@@ -52,7 +54,7 @@
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_as, "2-24i");
-static int 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,-1,0,0};
+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;
@@ -67,44 +69,33 @@ struct js_as_info {
};
/*
- * js_as_read_packet() reads an Assasin 3D packet.
+ * 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, t1;
+ unsigned int t, p;
unsigned long flags;
- int start = (js_time_speed * JS_AS_MAX_START) >> 10;
- int strobe = (js_time_speed * JS_AS_MAX_STROBE) >> 10;
-
i = 0;
__save_flags(flags);
__cli();
- outb(0xff,io);
- u = inb(io);
- t = js_get_time();
-
- do {
- v = inb(io);
- t1 = js_get_time();
- } while (u == v && js_delta(t1, t) < start);
-
- t = t1;
+ outb(0xff,io);
+ v = inb(io);
+ t = p = JS_AS_MAX_START;
- do {
- v = inb(io);
- t1 = js_get_time();
- if ((u ^ v) & u & 0x10) {
+ while (t > 0 && i < length) {
+ t--;
+ u = v; v = inb(io);
+ if (~v & u & 0x10) {
data[i++] = v >> 5;
- t = t1;
+ p = t = (p - t) << 3;
}
- u = v;
- } while (i < length && js_delta(t1,t) < strobe);
+ }
__restore_flags(flags);
@@ -181,11 +172,8 @@ static int js_as_read(void *xinfo, int **axes, int **buttons)
if (info->rudder) axes[1][0] = info->an.axes[0];
return 0;
-
- default:
- printk("Error.\n");
- return -1;
}
+ return -1;
}
/*
@@ -254,7 +242,7 @@ static void __init js_as_pxl_init_corr(struct js_corr **corr, int **axes)
/*
* js_as_as_init_corr() initializes the correction values for
- * the Panther and Assasin.
+ * the Panther and Assassin.
*/
static void __init js_as_as_init_corr(struct js_corr **corr)
@@ -305,25 +293,27 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
if (io < 0) return port;
if (check_region(io, 1)) return port;
- if (((u = inb(io)) & 3) == 3) return port;
- outb(0xff,io);
- if (!((inb(io) ^ u) & ~u & 0xf)) return port;
- if (js_as_read_packet(io, 1, data) != 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 (assasin)");
+ 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-assasin: unknown joystick device detected "
+ 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_MAX_TIME);
+ udelay(JS_AS_DELAY_READ);
if (info->mode == JS_AS_MODE_PXL) {
printk(KERN_INFO "js%d: MadCatz Panther XL at %#x\n",
@@ -342,9 +332,9 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
}
switch (info->mode) {
- case JS_AS_MODE_A3D: name = "FP-Gaming Assasin 3D"; break;
+ 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 Assasin 3D"; break;
+ case JS_AS_MODE_OEM: name = "OEM Assassin 3D"; break;
default: name = "This cannot happen"; break;
}
@@ -374,11 +364,14 @@ static struct js_port __init *js_as_probe(int io, int mask0, int mask1, struct j
}
#ifndef MODULE
-void __init js_as_setup(char *str, int *ints)
+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
@@ -398,7 +391,7 @@ int __init js_as_init(void)
if (js_as_port) return 0;
#ifdef MODULE
- printk(KERN_WARNING "joy-assasin: no joysticks found\n");
+ printk(KERN_WARNING "joy-assassin: no joysticks found\n");
#endif
return -ENODEV;
@@ -410,9 +403,9 @@ void cleanup_module(void)
int i;
struct js_as_info *info;
- while (js_as_port != NULL) {
+ while (js_as_port) {
for (i = 0; i < js_as_port->ndevs; i++)
- if (js_as_port->devs[i] != NULL)
+ if (js_as_port->devs[i])
js_unregister_device(js_as_port->devs[i]);
info = js_as_port->info;
release_region(info->io, 1);
diff --git a/drivers/char/joystick/joy-console.c b/drivers/char/joystick/joy-console.c
index ad4be3076..58392f839 100644
--- a/drivers/char/joystick/joy-console.c
+++ b/drivers/char/joystick/joy-console.c
@@ -1,14 +1,19 @@
/*
- * joy-console.c Version 0.11V
+ * joy-console.c Version 0.14V
*
- * Copyright (c) 1998 Andree Borrmann
+ * 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, Multi1, Multi2, PSX) gamepads connected
- * via parallel port. Up to five such controllers can be
- * connected to one parallel port.
+ * console (NES, SNES, N64, Multi1, Multi2, PSX) gamepads
+ * connected via parallel port. Up to five such controllers
+ * can be connected to one parallel port.
*/
/*
@@ -25,6 +30,10 @@
* 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>
@@ -36,12 +45,13 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/init.h>
-MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_console, "2-6i");
-MODULE_PARM(js_console2,"2-6i");
-MODULE_PARM(js_console3,"2-6i");
+MODULE_PARM(js_console_2,"2-6i");
+MODULE_PARM(js_console_3,"2-6i");
#define JS_NO_PAD 0
@@ -51,29 +61,29 @@ MODULE_PARM(js_console3,"2-6i");
#define JS_MULTI_STICK 4
#define JS_MULTI2_STICK 5
#define JS_PSX_PAD 6
-
-#define JS_MAX_PAD JS_PSX_PAD
+#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 {
-#ifdef USE_PARPORT
struct pardevice *port; /* parport device */
-#else
- int port; /* hw port */
-#endif
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; /* Normal PSX controllers */
- int negcon; /* PSX NEGCON controllers */
+ 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_console2[] __initdata = { -1, 0, 0, 0, 0, 0 };
-static int js_console3[] __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 };
@@ -109,7 +119,7 @@ static int status_bit[] = { 0x40, 0x80, 0x20, 0x10, 0x08 };
#define JS_SNES_L 10
#define JS_SNES_R 11
-#define JS_NES_POWER 0xf8
+#define JS_NES_POWER 0xfc
#define JS_NES_CLOCK 0x01
#define JS_NES_LATCH 0x02
@@ -123,17 +133,99 @@ static void js_nes_read_packet(struct js_console_info *info, int length, unsigne
{
int i;
- JS_PAR_DATA_OUT(JS_NES_POWER + JS_NES_CLOCK + JS_NES_LATCH, info->port);
+ 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);
+ 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);
+ 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.
+ */
+
}
/*
@@ -161,7 +253,9 @@ static void js_multi_read_packet(struct js_console_info *info, int length, unsig
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");
}
/*
@@ -169,27 +263,28 @@ static void js_multi_read_packet(struct js_console_info *info, int length, unsig
*/
#define JS_PSX_DELAY 10
+#define JS_PSX_LENGTH 8 /* talk to the controller in bytes */
-#define JS_PSX_LENGTH 8
+#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_NORMAL 0x41
-#define JS_PSX_NEGCON 0x23
-#define JS_PSX_MOUSE 0x12
-
-#define JS_PSX_SELBUT 0x01
+#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
+#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 0x01
-#define JS_PSX_COMMAND 0x02
-#define JS_PSX_POWER 0xf8
-#define JS_PSX_NOPOWER 0x04
-#define JS_PSX_SELECT 0x08
-
-#define JS_PSX_CTRL_OUT(X,Y) JS_PAR_CTRL_OUT((X)^0x0f, Y)
+#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
@@ -202,11 +297,11 @@ static int js_psx_command(struct js_console_info *info, int b)
cmd = (b&1)?JS_PSX_COMMAND:0;
for (i=0; i<8; i++) {
- JS_PSX_CTRL_OUT(cmd, info->port);
+ 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_PSX_CTRL_OUT(JS_PSX_CLOCK | cmd, info->port);
+ JS_PAR_DATA_OUT(cmd | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
udelay(JS_PSX_DELAY);
b >>= 1;
}
@@ -228,7 +323,7 @@ static int js_psx_read_packet(struct js_console_info *info, int length, unsigned
JS_PAR_DATA_OUT(JS_PSX_POWER, info->port);
- JS_PSX_CTRL_OUT(JS_PSX_CLOCK | JS_PSX_SELECT, info->port); /* Select pad */
+ 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 */
@@ -237,7 +332,7 @@ static int js_psx_read_packet(struct js_console_info *info, int length, unsigned
data[i]=js_psx_command(info, 0);
else ret = -1;
- JS_PSX_CTRL_OUT(JS_PSX_SELECT | JS_PSX_CLOCK, info->port);
+ JS_PAR_DATA_OUT(JS_PSX_SELECT | JS_PSX_CLOCK | JS_PSX_POWER, info->port);
__restore_flags(flags);
return ret;
@@ -248,14 +343,14 @@ static int js_psx_read_packet(struct js_console_info *info, int length, unsigned
* js_console_read() reads and analyzes console pads data.
*/
-#define JS_MAX_LENGTH JS_SNES_LENGTH
+#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, s;
+ int i, j, s;
int n = 0;
/*
@@ -268,24 +363,68 @@ static int js_console_read(void *xinfo, int **axes, int **buttons)
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);
-
- n++;
+ 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);
- n++;
+ 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];
+
}
}
}
@@ -300,21 +439,18 @@ static int js_console_read(void *xinfo, int **axes, int **buttons)
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;
-
- n++;
} 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;
-
- n++;
}
}
}
@@ -323,18 +459,44 @@ static int js_console_read(void *xinfo, int **axes, int **buttons)
* PSX controllers
*/
- if (info->psx && (js_psx_read_packet(info, 2, data) == JS_PSX_NORMAL)) { /* FIXME? >1 PSX pads? */
+ 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);
- 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);
+ case JS_PSX_ANALOGG:
+
+ axes[n][2] = data[2];
+ axes[n][3] = data[3];
+ axes[n][4] = data[4];
+ axes[n][5] = data[5];
- 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);
+ case JS_PSX_NORMAL:
+ case JS_PSX_NEGCON:
- n++;
+ 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 -(n != info->pads);
+ return 0;
}
/*
@@ -343,10 +505,8 @@ static int js_console_read(void *xinfo, int **axes, int **buttons)
int js_console_open(struct js_dev *dev)
{
-#ifdef USE_PARPORT
struct js_console_info *info = dev->port->info;
if (!MOD_IN_USE && parport_claim(info->port)) return -EBUSY;
-#endif
MOD_INC_USE_COUNT;
return 0;
}
@@ -357,13 +517,9 @@ int js_console_open(struct js_dev *dev)
int js_console_close(struct js_dev *dev)
{
-#ifdef USE_PARPORT
struct js_console_info *info = dev->port->info;
-#endif
MOD_DEC_USE_COUNT;
-#ifdef USE_PARPORT
if (!MOD_IN_USE) parport_release(info->port);
-#endif
return 0;
}
@@ -373,16 +529,12 @@ void cleanup_module(void)
struct js_console_info *info;
int i;
- while (js_console_port != NULL) {
+ while (js_console_port) {
for (i = 0; i < js_console_port->ndevs; i++)
- if (js_console_port->devs[i] != NULL)
+ if (js_console_port->devs[i])
js_unregister_device(js_console_port->devs[i]);
info = js_console_port->info;
-#ifdef USE_PARPORT
parport_unregister_device(info->port);
-#else
- release_region(info->port, 3);
-#endif
js_console_port = js_unregister_port(js_console_port);
}
}
@@ -393,7 +545,7 @@ void cleanup_module(void)
* console gamepads.
*/
-static void __init js_console_init_corr(int num_axes, struct js_corr *corr)
+static void __init js_console_init_corr(int num_axes, int type, struct js_corr *corr)
{
int i;
@@ -405,6 +557,28 @@ static void __init js_console_init_corr(int num_axes, struct js_corr *corr)
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);
+ }
+ }
}
/*
@@ -415,45 +589,40 @@ static void __init js_console_init_corr(int num_axes, struct js_corr *corr)
static struct js_port __init *js_console_probe(int *config, struct js_port *port)
{
char *name[5];
- int i, psx, axes[5], buttons[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;
-#ifdef USE_PARPORT
- {
- struct parport *pp;
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
-
- if (pp == NULL) {
- printk(KERN_ERR "joy-console: no such parport\n");
- 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]--;
- info.port = parport_register_device(pp, "joystick (console)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
- if (!info.port)
- return port;
+ 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;
}
-#else
- info.port = config[0];
- if (check_region(info.port, 3)) return port;
- request_region(info.port, 3, "joystick (console pad)");
-#endif
- for (i = 0; i < 5; i++)
+ 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:
@@ -478,6 +647,23 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
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;
@@ -497,31 +683,58 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
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 controller";
+ 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:
- printk(KERN_WARNING "joy-console: NegCon not yet supported...\n");
+ 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-console: PSX mouse not supported...\n");
+ printk(KERN_WARNING "joy-psx: PSX mouse not supported...\n");
break;
+
case -1:
- printk(KERN_ERR "joy-console: no PSX controller found...\n");
+ printk(KERN_ERR "joy-psx: no PSX controller found...\n");
break;
+
default:
- printk(KERN_WARNING "joy-console: unknown PSX controller 0x%x\n", psx);
+ printk(KERN_WARNING "joy-psx: PSX controller unknown: 0x%x,"
+ " please report to <vojtech@suse.cz>.\n", psx);
}
break;
@@ -529,52 +742,53 @@ static struct js_port __init *js_console_probe(int *config, struct js_port *port
printk(KERN_WARNING "joy-console: pad type %d unknown\n", config[i+1]);
}
+ }
if (!info.pads) {
-#ifdef USE_PARPORT
parport_release(info.port);
parport_unregister_device(info.port);
-#else
- release_region(info.port, 3);
-#endif
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++) {
-#ifdef USE_PARPORT
printk(KERN_INFO "js%d: %s on %s\n",
js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
name[i], info.port->port->name);
-#else
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, i, axes[i], buttons[i], name[i], js_console_open, js_console_close),
- name[i], info.port);
-#endif
- js_console_init_corr(axes[i], port->corr[i]);
+ js_console_init_corr(axes[i], type[i], port->corr[i]);
}
-#ifdef USE_PARPORT
parport_release(info.port);
-#endif
return port;
}
#ifndef MODULE
-void __init js_console_setup(char *str, int *ints)
+int __init js_console_setup(SETUP_PARAM)
{
int i;
-
- if (!strcmp(str,"js_console"))
- for (i = 0; i <= ints[0] && i < 6; i++) js_console[i] = ints[i+1];
- if (!strcmp(str,"js_console2"))
- for (i = 0; i <= ints[0] && i < 6; i++) js_console2[i] = ints[i+1];
- if (!strcmp(str,"js_console3"))
- for (i = 0; i <= ints[0] && i < 6; i++) js_console3[i] = ints[i+1];
-
+ 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
@@ -584,8 +798,8 @@ 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_console2, js_console_port);
- js_console_port = js_console_probe(js_console3, 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;
diff --git a/drivers/char/joystick/joy-creative.c b/drivers/char/joystick/joy-creative.c
new file mode 100644
index 000000000..7e97a677d
--- /dev/null
+++ b/drivers/char/joystick/joy-creative.c
@@ -0,0 +1,287 @@
+/*
+ * 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_open() is a callback from the file open routine.
+ */
+
+static int js_cr_open(struct js_dev *jd)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * js_cr_close() is a callback from the file release routine.
+ */
+
+static int js_cr_close(struct js_dev *jd)
+{
+ MOD_DEC_USE_COUNT;
+ 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]], js_cr_open, js_cr_close),
+ 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
index b459b91f5..d5b6565ee 100644
--- a/drivers/char/joystick/joy-db9.c
+++ b/drivers/char/joystick/joy-db9.c
@@ -1,7 +1,10 @@
/*
- * joy-db9.c Version 0.5V
+ * joy-db9.c Version 0.6V
*
- * Copyright (c) 1998 Andree Borrmann
+ * Copyright (c) 1998 Andree Borrmann
+ * Copyright (c) 1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -24,6 +27,10 @@
* 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>
@@ -35,8 +42,9 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/init.h>
-MODULE_AUTHOR("Andree Borrmann <A.Borrmann@tu-bs.de>");
+MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_db9, "2i");
MODULE_PARM(js_db9_2, "2i");
MODULE_PARM(js_db9_3, "2i");
@@ -48,7 +56,8 @@ MODULE_PARM(js_db9_3, "2i");
#define JS_GENESIS6_PAD 0x06
#define JS_SATURN_PAD 0x07
#define JS_MULTI_0802 0x08
-#define JS_MAX_PAD 0x09
+#define JS_MULTI_0802_2 0x09
+#define JS_MAX_PAD 0x0A
#define JS_DB9_UP 0x01
#define JS_DB9_DOWN 0x02
@@ -59,8 +68,8 @@ MODULE_PARM(js_db9_3, "2i");
#define JS_DB9_FIRE3 0x40
#define JS_DB9_FIRE4 0x80
-#define JS_DB9_NORMAL 0x22
-#define JS_DB9_NOSELECT 0x20
+#define JS_DB9_NORMAL 0x2a
+#define JS_DB9_NOSELECT 0x28
#define JS_DB9_SATURN0 0x20
#define JS_DB9_SATURN1 0x22
@@ -76,11 +85,7 @@ static int js_db9_2[] __initdata = { -1, 0 };
static int js_db9_3[] __initdata = { -1, 0 };
struct js_db9_info {
-#ifdef USE_PARPORT
struct pardevice *port; /* parport device */
-#else
- int port; /* hw port */
-#endif
int mode; /* pad mode */
};
@@ -95,6 +100,15 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons)
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;
@@ -185,11 +199,12 @@ static int js_db9_read(void *xinfo, int **axes, int **buttons)
udelay(JS_GENESIS6_DELAY);
JS_PAR_CTRL_OUT(JS_DB9_NOSELECT, info->port); /* 3 */
udelay(JS_GENESIS6_DELAY);
- JS_PAR_CTRL_OUT(JS_DB9_NORMAL, info->port);
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);
+ 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);
@@ -236,11 +251,11 @@ int js_db9_open(struct js_dev *dev)
struct js_db9_info *info = dev->port->info;
if (!MOD_IN_USE) {
-#ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY;
-#endif
- JS_PAR_ECTRL_OUT(0x35,info->port); /* enable PS/2 mode: */
+ 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 */
}
@@ -260,12 +275,11 @@ int js_db9_close(struct js_dev *dev)
if (!MOD_IN_USE) {
- JS_PAR_CTRL_OUT(0x00,info->port); /* normal direction */
- JS_PAR_ECTRL_OUT(0x15,info->port); /* enable normal mode */
+ 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 */
-#ifdef USE_PARPORT
parport_release(info->port);
-#endif
}
return 0;
}
@@ -274,16 +288,15 @@ int js_db9_close(struct js_dev *dev)
void cleanup_module(void)
{
struct js_db9_info *info;
+ int i;
- while (js_db9_port != NULL) {
- js_unregister_device(js_db9_port->devs[0]);
+ while (js_db9_port) {
info = js_db9_port->info;
-#ifdef USE_PARPORT
+
+ 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);
-#else
- release_region(info->port, 3);
- release_region(info->port+0x402, 1);
-#endif
js_db9_port = js_unregister_port(js_db9_port);
}
@@ -295,17 +308,17 @@ void cleanup_module(void)
* db9 gamepads.
*/
-static void __init js_db9_init_corr(struct js_corr **corr)
+static void __init js_db9_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);
+ 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);
}
}
@@ -316,75 +329,76 @@ static void __init js_db9_init_corr(struct js_corr **corr)
static struct js_port __init *js_db9_probe(int *config, struct js_port *port)
{
struct js_db9_info info;
- char buttons[JS_MAX_PAD] = {0,1,2,4,0,6,7,8,1};
+ 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"};
+ 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;
-#ifdef USE_PARPORT
- {
- struct parport *pp;
-
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
-
- if (pp == NULL) {
- printk(KERN_ERR "joy-db9: no such parport\n");
- return port;
- }
-
- if (!(pp->modes & PARPORT_MODE_TRISTATE)) {
- 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;
+ 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;
}
-#else
- info.port = config[0];
- if (check_region(info.port, 3) || check_region(info.port+0x402,1)) return port;
- request_region(info.port, 3, "joystick (db9)");
- request_region(info.port+0x402, 1, "joystick (db9)");
-#endif
- info.mode = config[1];
+ 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;
+ }
- port = js_register_port(port, &info, 1, sizeof(struct js_db9_info), js_db9_read);
+ info.port = parport_register_device(pp, "joystick (db9)", NULL, NULL, NULL, PARPORT_DEV_EXCL, NULL);
+ if (!info.port)
+ return port;
-#ifdef USE_PARPORT
- printk(KERN_INFO "js%d: %s on %s\n",
- js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
- name[info.mode], info.port->port->name);
-#else
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, 0, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
- name[info.mode], info.port);
-#endif
+ port = js_register_port(port, &info, 1 + (info.mode == JS_MULTI_0802_2), sizeof(struct js_db9_info), js_db9_read);
+
+ for (i = 0; i < 1 + (info.mode == JS_MULTI_0802_2); i++) {
+ printk(KERN_INFO "js%d: %s on %s\n",
+ js_register_device(port, i, 2, buttons[info.mode], name[info.mode], js_db9_open, js_db9_close),
+ name[info.mode], info.port->port->name);
+
+ js_db9_init_corr(port->corr[i]);
+ }
- js_db9_init_corr(port->corr);
return port;
}
#ifndef MODULE
-void __init js_db9_setup(char *str, int *ints)
+int __init js_db9_setup(SETUP_PARAM)
{
int i;
-
- if (!strcmp(str,"js_db9"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9[i] = ints[i+1];
- if (!strcmp(str,"js_db9_2"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_2[i] = ints[i+1];
- if (!strcmp(str,"js_db9_3"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_db9_3[i] = ints[i+1];
-
+ 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
diff --git a/drivers/char/joystick/joy-gravis.c b/drivers/char/joystick/joy-gravis.c
index 7416527e4..3863d161f 100644
--- a/drivers/char/joystick/joy-gravis.c
+++ b/drivers/char/joystick/joy-gravis.c
@@ -1,7 +1,9 @@
/*
* joy-gravis.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -37,15 +39,16 @@
#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 75
+#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 30
+#define JS_GR_STROBE_XT 200
#define JS_GR_MAX_CHUNKS_XT 10
#define JS_GR_MAX_BITS_XT 30
@@ -63,37 +66,36 @@ struct js_gr_info {
static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
{
- unsigned int t, t1;
+ unsigned long flags;
unsigned char u, v;
+ unsigned int t, p;
int i;
- unsigned long flags;
-
- int strobe = (js_time_speed * JS_GR_STROBE_GPP) >> 10;
i = 0;
data[0] = 0;
+ p = t = JS_GR_STROBE_GPP;
+ p += JS_GR_STROBE_GPP;
__save_flags(flags);
__cli();
- u = inb(io) >> shift;
- t = js_get_time();
+
+ v = inb(io) >> shift;
do {
- v = (inb(io) >> shift) & 3;
- t1 = js_get_time();
- if ((u ^ v) & u & 1) {
+ t--;
+ u = v; v = (inb(io) >> shift) & 3;
+ if (~v & u & 1) {
data[0] |= (v >> 1) << i++;
- t = t1;
+ p = t = (p - t) << 1;
}
- u = v;
- } while (i < JS_GR_LENGTH_GPP && js_delta(t1,t) < strobe);
+ } 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) << 23;
+ data[0] = data[0] >> 1 | (data[0] & 1) << (JS_GR_LENGTH_GPP - 1);
return -(i == JS_GR_LENGTH_GPP);
}
@@ -104,35 +106,36 @@ static int js_gr_gpp_read_packet(int io, int shift, unsigned int *data)
static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
{
- unsigned int t, t1;
- unsigned char u, v, w;
unsigned int i, j, buf, crc;
+ unsigned char u, v, w;
unsigned long flags;
+ unsigned int t, p;
char status;
- int strobe = (js_time_speed * JS_GR_STROBE_XT) >> 10;
-
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;
- t = js_get_time();
do {
+ t--;
u = (inb(io) >> shift) & 3;
- t1 = js_get_time();
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)) {
@@ -145,12 +148,11 @@ static int js_gr_xt_read_packet(int io, int shift, unsigned int *data)
i = 0;
}
- t = t1;
w = v;
v = u;
}
- } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && js_delta(t1,t) < strobe);
+ } while (status != 0xf && i < JS_GR_MAX_BITS_XT && j < JS_GR_MAX_CHUNKS_XT && t > 0);
__restore_flags(flags);
@@ -320,7 +322,7 @@ static void __init js_gr_init_corr(int mode, struct js_corr *corr)
}
/*
- * js_gr_probe() probes fro GrIP joysticks.
+ * js_gr_probe() probes for GrIP joysticks.
*/
static struct js_port __init *js_gr_probe(int io, struct js_port *port)
@@ -389,9 +391,9 @@ void cleanup_module(void)
int i;
struct js_gr_info *info;
- while (js_gr_port != NULL) {
+ while (js_gr_port) {
for (i = 0; i < js_gr_port->ndevs; i++)
- if (js_gr_port->devs[i] != NULL)
+ if (js_gr_port->devs[i])
js_unregister_device(js_gr_port->devs[i]);
info = js_gr_port->info;
release_region(info->io, 1);
diff --git a/drivers/char/joystick/joy-lightning.c b/drivers/char/joystick/joy-lightning.c
index 3b337fd9f..038d33a3c 100644
--- a/drivers/char/joystick/joy-lightning.c
+++ b/drivers/char/joystick/joy-lightning.c
@@ -1,7 +1,9 @@
/*
* joy-lightning.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -38,6 +40,7 @@
#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
@@ -55,7 +58,7 @@ static struct js_port* __initdata js_l4_port = NULL;
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_PARM(js_l4, "2-24i");
-static int 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,-1,0,0};
+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"
@@ -70,11 +73,10 @@ struct js_l4_info {
static int js_l4_wait_ready(void)
{
- unsigned int t, t1, timeout;
- timeout = (JS_L4_TIMEOUT * js_time_speed) >> 10;
- t = t1 = js_get_time();
- while ((inb(JS_L4_PORT) & JS_L4_BUSY) && (js_delta(t1 = js_get_time(), t) < timeout));
- return -(js_delta(t1, t) >= timeout);
+ unsigned int t;
+ t = JS_L4_TIMEOUT;
+ while ((inb(JS_L4_PORT) & JS_L4_BUSY) && t > 0) t--;
+ return -(t<=0);
}
/*
@@ -255,14 +257,14 @@ static struct js_port __init *js_l4_probe(unsigned char *cards, int l4port, int
port = js_register_port(port, info, numdev, sizeof(struct js_l4_info), js_l4_read);
+ info = port->info;
+
for (i = 0; i < numdev; i++)
printk(KERN_INFO "js%d: %s on L4 port %d\n",
js_register_device(port, i, js_an_axes(i, &info->an), js_an_buttons(i, &info->an),
js_an_name(i, &info->an), js_l4_open, js_l4_close),
js_an_name(i, &info->an), info->port);
- info = port->info;
-
js_l4_calibrate(info);
js_l4_read(info, port->axes, port->buttons);
js_an_init_corr(&info->an, port->axes, port->corr, 0);
@@ -300,18 +302,21 @@ static void __init js_l4_card_probe(unsigned char *cards)
cards[i] = rev;
- printk(KERN_INFO "js: PDPI Lightning 4 %s card (ports %d-%d) firmware v%d.%d found at %#x\n",
+ 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
-void __init js_l4_setup(char *str, int *ints)
+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
@@ -333,7 +338,7 @@ int __init js_l4_init(void)
js_l4_port = js_l4_probe(cards, i, 0, 0, js_l4_port);
}
- if (js_l4_port == NULL) {
+ if (!js_l4_port) {
#ifdef MODULE
printk(KERN_WARNING "joy-lightning: no joysticks found\n");
#endif
@@ -352,9 +357,9 @@ void cleanup_module(void)
int cal[4] = {59, 59, 59, 59};
struct js_l4_info *info;
- while (js_l4_port != NULL) {
+ while (js_l4_port) {
for (i = 0; i < js_l4_port->ndevs; i++)
- if (js_l4_port->devs[i] != NULL)
+ 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);
diff --git a/drivers/char/joystick/joy-logitech.c b/drivers/char/joystick/joy-logitech.c
index 064ecade4..daea89c8b 100644
--- a/drivers/char/joystick/joy-logitech.c
+++ b/drivers/char/joystick/joy-logitech.c
@@ -1,12 +1,14 @@
/*
* joy-logitech.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
* This is a module for the Linux joystick driver, supporting
- * Logitech Digital joystick family.
+ * Logitech ADI joystick family.
*/
/*
@@ -38,113 +40,175 @@
#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_START 250
-#define JS_LT_MAX_STROBE 25
-#define JS_LT_MAX_LENGTH 72
+#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_MAX_DELAY 12000
+#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_MODE_WMED 1
-#define JS_LT_MODE_CM2 2
-#define JS_LT_MODE_TPD 3
+#define JS_LT_FLAG_HAT 0x04
+#define JS_LT_FLAG_10BIT 0x08
-static int js_lt_seq_init[] __initdata = { 6000, 11000, 7000, 9000, 6000, 11000, 7000, 9000, 0 };
-static int js_lt_seq_reset[] __initdata = { 2000, 3000, 2000, 3000, 0 };
+#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
-static int js_lt_port_list[] __initdata = {0x201, 0};
+#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;
- unsigned char mode;
+ 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 packet.
+ * js_lt_read_packet() reads a Logitech ADI packet.
*/
-static int js_lt_read_packet(int io, __u64 *data)
+static void js_lt_read_packet(struct js_lt_info *info)
{
-
- static unsigned char buf[JS_LT_MAX_LENGTH];
- unsigned char u, v, w, mask = 0;
- int i;
+ unsigned char u, v, w, x, z;
+ int t[2], s[2], p[2], i;
unsigned long flags;
- unsigned int t, t1;
-
- int start = (js_time_speed * JS_LT_MAX_START) >> 10;
- int strobe = (js_time_speed * JS_LT_MAX_STROBE) >> 10;
- u = inb(io) >> 4;
-
- if (u == 0xc) mask = 0x10;
- if (u == 0x0) mask = 0x50;
- if (!mask) return 0;
-
- i = 0;
+ 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,io);
+ outb(0xff, info->io);
+ v = z = inb(info->io);
- u = inb(io);
- t = js_get_time();
+ 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);
- if ((u & 0xc) != 0xc) mask = 0x10;
+ __restore_flags(flags);
- do {
- u = inb(io);
- t1 = js_get_time();
- } while ((((u >> 1) ^ u) & mask) != mask && js_delta(t1,t) < start);
+ 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
- t = t1;
+ return;
+}
- do {
- v = inb(io);
- t1 = js_get_time();
- w = u ^ v;
- if ((((w >> 1) ^ w) & mask) == mask) {
- buf[i++] = w;
- t = t1;
- u = v;
- }
- } while (i < JS_LT_MAX_LENGTH && js_delta(t1,t) < strobe);
+/*
+ * js_lt_move_bits() detects a possible 2-stream mode, and moves
+ * the bits accordingly.
+ */
- __restore_flags(flags);
+static void js_lt_move_bits(struct js_lt_info *info, int length)
+{
+ int i;
- t = i;
- *data = 0;
+ info->idx[0] = info->idx[1] = 0;
- if (mask == 0x10) {
- for (i = 0; i < t; i++)
- *data = ((buf[i] >> 5) & 1) | (*data << 1);
- return t;
- }
- if (mask == 0x50) {
- for (i = 0; i < t; i++)
- *data = ((__u64)(buf[i] & 0x20) << (t - 5)) | (buf[i] >> 7) | (*data << 1);
- return t << 1;
- }
- return 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_reverse() reverses the order of bits in a byte.
+ * js_lt_get_bits() gathers bits from the data packet.
*/
-static unsigned char js_lt_reverse(unsigned char u)
+static inline int js_lt_get_bits(struct js_lt_info *info, int device, int count)
{
- u = ((u & 0x0f) << 4) | ((u >> 4) & 0x0f);
- u = ((u & 0x33) << 2) | ((u >> 2) & 0x33);
- u = ((u & 0x55) << 1) | ((u >> 1) & 0x55);
- return u;
+ 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;
}
/*
@@ -154,54 +218,61 @@ static unsigned char js_lt_reverse(unsigned char u)
static int js_lt_read(void *xinfo, int **axes, int **buttons)
{
struct js_lt_info *info = xinfo;
- __u64 data;
- int hat;
-
- switch (info->mode) {
-
- case JS_LT_MODE_TPD:
+ int i, j, k, l, t;
+ int ret = 0;
- if (js_lt_read_packet(info->io, &data) != 20) return -1;
+ js_lt_read_packet(info);
+ js_lt_move_bits(info, info->length[0]);
- axes[0][0] = ((data >> 6) & 1) - ((data >> 4) & 1);
- axes[0][1] = ((data >> 5) & 1) - ((data >> 7) & 1);
+ for (i = 0; i < 2; i++) {
- buttons[0][0] = js_lt_reverse((data & 0x0f) | ((data >> 4) & 0xf0));
-
- return 0;
-
- case JS_LT_MODE_WMED:
-
- if (js_lt_read_packet(info->io, &data) != 42) return -1;
- if ((hat = data & 0xf) > 8) return -1;
-
- axes[0][0] = (data >> 26) & 0xff;
- axes[0][1] = (data >> 18) & 0xff;
- axes[0][2] = (data >> 10) & 0xff;
- axes[0][3] = js_lt_hat_to_axis[hat].x;
- axes[0][4] = js_lt_hat_to_axis[hat].y;
+ 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;
+ }
- buttons[0][0] = js_lt_reverse((data >> 2) & 0xfc);
+ if (info->length[i] < info->ret[i])
+ info->bugs[i] |= JS_LT_BUG_LONGDATA;
+
+ k = l = 0;
- return 0;
+ for (j = 0; j < info->axes10[i]; j++)
+ axes[i][k++] = js_lt_get_bits(info, i, 10);
- case JS_LT_MODE_CM2:
+ for (j = 0; j < info->axes8[i]; j++)
+ axes[i][k++] = js_lt_get_bits(info, i, 8);
- if (js_lt_read_packet(info->io, &data) != 64) return -1;
+ for (j = 0; j <= (info->buttons[i] - 1) >> 5; j++) buttons[i][j] = 0;
- axes[0][0] = (data >> 48) & 0xff;
- axes[0][1] = (data >> 40) & 0xff;
- axes[0][2] = (data >> 32) & 0xff;
- axes[0][3] = (data >> 24) & 0xff;
- axes[0][4] = (data >> 16) & 0xff;
- axes[0][5] = (data >> 8) & 0xff;
+ 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++;
+ }
- buttons[0][0] = js_lt_reverse(data & 0xff);
+ 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;
+ }
- return 0;
+ for (j = 63; j < info->buttons[i]; j++) {
+ buttons[i][l >> 5] |= js_lt_get_bits(info, i, 1) << (l & 0x1f);
+ l++;
+ }
}
- return -1;
+ return ret;
}
/*
@@ -225,15 +296,18 @@ static int js_lt_close(struct js_dev *jd)
}
/*
- * js_lt_trigger_sequence() sends a trigger & delay sequence
- * to reset/initialize a Logitech joystick.
+ * js_lt_init_digital() sends a trigger & delay sequence
+ * to reset and initialize a Logitech joystick into digital mode.
*/
-static void __init js_lt_trigger_sequence(int io, int *seq)
+static void __init js_lt_init_digital(int io)
{
- while (*seq) {
+ int seq[] = { 3, 2, 3, 10, 6, 11, 7, 9, 11, 0 };
+ int i;
+
+ for (i = 0; seq[i]; i++) {
outb(0xff,io);
- udelay(*seq++);
+ mdelay(seq[i]);
}
}
@@ -242,35 +316,45 @@ static void __init js_lt_trigger_sequence(int io, int *seq)
* Logitech joysticks.
*/
-static void __init js_lt_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
+static void __init js_lt_init_corr(int id, int naxes10, int naxes8, int naxes1, int *axes, struct js_corr *corr)
{
int j;
-
- for (j = 0; j < num_axes; j++) {
- corr[0][j].type = JS_CORR_BROKEN;
- corr[0][j].prec = 2;
- corr[0][j].coef[0] = axes[0][j] - 8;
- corr[0][j].coef[1] = axes[0][j] + 8;
- corr[0][j].coef[2] = (1 << 29) / (127 - 32);
- corr[0][j].coef[3] = (1 << 29) / (127 - 32);
+
+ 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;
}
- switch (mode) {
- case JS_LT_MODE_TPD: j = 0; break;
- case JS_LT_MODE_WMED: j = 3; break;
- case JS_LT_MODE_CM2: j = 6; break;
- default: j = 0; break;
+ 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 < 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);
+ 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);
+ }
}
/*
@@ -279,61 +363,157 @@ static void __init js_lt_init_corr(int num_axes, int mode, int **axes, struct js
static struct js_port __init *js_lt_probe(int io, struct js_port *port)
{
- struct js_lt_info info;
- char *name;
- int axes, buttons, i;
- __u64 data;
- unsigned char u;
+ 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;
- if (((u = inb(io)) & 3) == 3) return port;
- outb(0xff,io);
- if (!((inb(io) ^ u) & ~u & 0xf)) return port;
+ js_lt_init_digital(io);
- if (!(i = js_lt_read_packet(io, &data))) {
- udelay(JS_LT_MAX_DELAY);
- js_lt_trigger_sequence(io, js_lt_seq_reset);
- js_lt_trigger_sequence(io, js_lt_seq_init);
- i = js_lt_read_packet(io, &data);
- }
+ 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]);
+ }
- switch (i) {
- case 0:
- return port;
- case 20:
- info.mode = JS_LT_MODE_TPD;
- axes = 2; buttons = 8; name = "Logitech ThunderPad Digital";
- break;
- case 42:
- info.mode = JS_LT_MODE_WMED;
- axes = 5; buttons = 6; name = "Logitech WingMan Extreme Digital";
- break;
- case 64:
- info.mode = JS_LT_MODE_CM2;
- axes = 6; buttons = 8; name = "Logitech CyberMan 2";
- break;
- case 72:
- case 144:
- return port;
- default:
- printk(KERN_WARNING "joy-logitech: unknown joystick device detected "
- "(io=%#x, count=%d, data=0x%08x%08x), contact <vojtech@suse.cz>\n",
- io, i, (int)(data >> 32), (int)(data & 0xffffffff));
- return port;
}
- info.io = io;
+ if (!info->length[0] && !info->length[1])
+ return port;
request_region(io, 1, "joystick (logitech)");
- port = js_register_port(port, &info, 1, sizeof(struct js_lt_info), js_lt_read);
- printk(KERN_INFO "js%d: %s at %#x\n",
- js_register_device(port, 0, axes, buttons, name, js_lt_open, js_lt_close), name, io);
- udelay(JS_LT_MAX_DELAY);
+ port = js_register_port(port, info, 2, sizeof(struct js_lt_info), js_lt_read);
+ info = port->info;
+
+ for (i = 0; i < 2; i++)
+ if (info->length[i] > 0) {
+ sprintf(name, info->id[i] < JS_LT_MAX_ID ?
+ js_lt_names[info->id[i]] : js_lt_names[JS_LT_MAX_ID], info->id[i]);
+ printk(KERN_INFO "js%d: %s [%s] at %#x\n",
+ js_register_device(port, i,
+ info->axes10[i] + info->axes8[i] + ((info->hats[i] + (info->pad[i] >= 0)) << 1),
+ info->buttons[i], name, js_lt_open, js_lt_close), name, info->name[i], io);
+ }
+
+ mdelay(JS_LT_INIT_DELAY);
+ if (js_lt_read(info, port->axes, port->buttons)) {
+ if (info->ret[0] < 1) info->bugs[0] |= JS_LT_BUG_IGNTRIG;
+ if (info->ret[1] < 1) info->bugs[1] |= JS_LT_BUG_IGNTRIG;
+ mdelay(JS_LT_DATA_DELAY);
+ js_lt_read(info, port->axes, port->buttons);
+ }
- js_lt_read(port->info, port->axes, port->buttons);
- js_lt_init_corr(axes, info.mode, port->axes, port->corr);
+ 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;
}
@@ -359,10 +539,13 @@ int __init js_lt_init(void)
#ifdef MODULE
void cleanup_module(void)
{
+ int i;
struct js_lt_info *info;
- while (js_lt_port != NULL) {
- js_unregister_device(js_lt_port->devs[0]);
+ 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);
diff --git a/drivers/char/joystick/joy-magellan.c b/drivers/char/joystick/joy-magellan.c
new file mode 100644
index 000000000..3a54d157e
--- /dev/null
+++ b/drivers/char/joystick/joy-magellan.c
@@ -0,0 +1,397 @@
+/*
+ * 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++;
+ MOD_INC_USE_COUNT;
+ 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);
+ }
+ MOD_DEC_USE_COUNT;
+ 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", 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
new file mode 100644
index 000000000..ae49fd8e1
--- /dev/null
+++ b/drivers/char/joystick/joy-pci.c
@@ -0,0 +1,273 @@
+/*
+ * 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;
+}
+
+/*
+ * js_pci_open() is a callback from the file open routine.
+ */
+
+static int js_pci_open(struct js_dev *jd)
+{
+ MOD_INC_USE_COUNT;
+ return 0;
+}
+
+/*
+ * js_pci_close() is a callback from the file release routine.
+ */
+
+static int js_pci_close(struct js_dev *jd)
+{
+ MOD_DEC_USE_COUNT;
+ 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), js_pci_open, js_pci_close), 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++)
+ 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
index d097471bc..37d276ba1 100644
--- a/drivers/char/joystick/joy-sidewinder.c
+++ b/drivers/char/joystick/joy-sidewinder.c
@@ -1,7 +1,9 @@
/*
* joy-sidewinder.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -38,18 +40,36 @@
#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_MAX_START 250
-#define JS_SW_MIN_STROBE 25
-#define JS_SW_EXT_STROBE 45
-#define JS_SW_MIN_TIME 1500
-#define JS_SW_MAX_TIME 4000
+#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 */
-#define JS_SW_MAX_LENGTH 72
+/*
+ * SideWinder joystick types ...
+ */
-#define JS_SW_MODE_3DP 1
-#define JS_SW_MODE_PP 2
-#define JS_SW_MODE_GP 3
+#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;
@@ -61,208 +81,398 @@ static struct {
struct js_sw_info {
int io;
- unsigned char mode;
+ int length;
+ int speed;
+ unsigned char type;
+ unsigned char bits;
unsigned char number;
- unsigned char optimize;
+ unsigned char fail;
+ unsigned char ok;
};
/*
- * js_sw_init_digital() switches a SideWinder into digital mode.
+ * Gameport speed.
+ */
+
+unsigned int js_sw_io_speed = 0;
+
+/*
+ * js_sw_measure_speed() measures the gameport i/o speed.
*/
-static void __init js_sw_init_digital(int io)
+static int __init js_sw_measure_speed(int io)
{
- unsigned int t;
- unsigned int timeout = (js_time_speed * JS_SW_MAX_TIME) >> 10;
- int delays[] = {140, 140+726, 140+300, 0};
- int i = 0;
- unsigned long flags;
+#ifdef __i386__
- __save_flags(flags);
- __cli();
- do {
- outb(0xff,io);
- t = js_get_time();
- while ((inb(io) & 1) && (js_delta(js_get_time(),t) < timeout));
- udelay(delays[i]);
- } while (delays[i++]);
- __restore_flags(flags);
+#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;
- for (i = 0; i < 4; i++) {
- udelay(300);
- outb(0xff, io);
+ 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;
+ 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() reads a SideWinder packet.
+ * 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 l1, int l2, int strobe, __u64 *data)
+static int js_sw_read_packet(int io, int speed, unsigned char *buf, int length, int id)
{
- static unsigned char buf[JS_SW_MAX_LENGTH];
- unsigned char u, v;
- int i;
unsigned long flags;
- unsigned int t, t1;
-
- int length = l1 < l2 ? l2 : l1;
- int start = (js_time_speed * JS_SW_MAX_START) >> 10;
- strobe = (js_time_speed * strobe) >> 10;
-
- i = 0;
-
- __save_flags(flags);
- __cli();
- outb(0xff,io);
-
+ 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);
- t = js_get_time();
do {
+ bitout--;
u = v;
v = inb(io);
- t1 = js_get_time();
- } while (!((u ^ v) & u & 0x10) && js_delta(t1, t) < start);
+ } while (!(~v & u & 0x10) && (bitout > 0)); /* Wait for first falling edge on clock */
- t = t1;
+ if (bitout > 0) bitout = strobe; /* Extend time if not timed out */
- do {
- v = inb(io);
- t1 = js_get_time();
- if ((u ^ v) & v & 0x10) {
- buf[i++] = v >> 5;
- t = t1;
- }
- u = v;
- } while (i < length && js_delta(t1,t) < strobe);
+ while ((timeout > 0 || bitout > 0) && (i < length)) {
- __restore_flags(flags);
+ timeout--;
+ bitout--; /* Decrement timers */
+ sched--;
- *data = 0;
+ u = v;
+ v = inb(io);
- if (i == l1) {
- t = i > 64 ? 64 : i;
- for (i = 0; i < t; i++)
- *data |= (__u64) (buf[i] & 1) << i;
- return t;
+ 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 */
+ }
}
- if (i == l2) {
- t = i > 22 ? 22 : i;
- for (i = 0; i < t; i++)
- *data |= (__u64) buf[i] << (3 * i);
- return t * 3;
+
+ __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_parity computes parity of __u64
+ * 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)
{
- t ^= t >> 32;
- t ^= t >> 16;
- t ^= t >> 8;
- t ^= t >> 4;
- t ^= t >> 2;
- t ^= t >> 1;
- return t & 1;
+ 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_csum() computes checksum of nibbles in __u64
+ * js_sw_ccheck() checks synchronization bits and computes checksum of nibbles.
*/
-static int js_sw_csum(__u64 t)
+static int js_sw_check(__u64 t)
{
char sum = 0;
- while (t) {
+
+ if ((t & 0x8080808080808080ULL) ^ 0x80) /* Sync */
+ return -1;
+
+ while (t) { /* Sum */
sum += t & 0xf;
t >>= 4;
}
+
return sum & 0xf;
}
/*
- * js_sw_read() reads and analyzes SideWinder joystick data.
+ * js_sw_parse() analyzes SideWinder joystick data, and writes the results into
+ * the axes and buttons arrays.
*/
-static int js_sw_read(void *xinfo, int **axes, int **buttons)
+static int js_sw_parse(unsigned char *buf, struct js_sw_info *info, int **axes, int **buttons)
{
- struct js_sw_info *info = xinfo;
- __u64 data;
int hat, i;
- switch (info->mode) {
-
- case JS_SW_MODE_3DP:
+ switch (info->type) {
- if (info->optimize) {
- i = js_sw_read_packet(info->io, -1, 22, JS_SW_EXT_STROBE, &data);
- } else {
- i = js_sw_read_packet(info->io, 64, 66, JS_SW_EXT_STROBE, &data);
- if (i == 198) info->optimize = 1;
- }
+ case JS_SW_TYPE_3DP:
+ case JS_SW_TYPE_F23:
- if (i < 60) {
- js_sw_init_digital(info->io);
- info->optimize = 0;
- return -1;
- }
+ if (js_sw_check(GB(0,64,0)) || (hat = GB(6,1,3) | GB(60,3,0)) > 8) return -1;
- if (((data & 0x8080808080808080ULL) ^ 0x80) || js_sw_csum(data) ||
- (hat = ((data >> 3) & 0x08) | ((data >> 60) & 0x07)) > 8) {
- info->optimize = 0;
- return -1;
- }
- axes[0][0] = ((data << 4) & 0x380) | ((data >> 16) & 0x07f);
- axes[0][1] = ((data << 7) & 0x380) | ((data >> 24) & 0x07f);
- axes[0][2] = ((data >> 28) & 0x180) | ((data >> 40) & 0x07f);
- axes[0][3] = ((data >> 25) & 0x380) | ((data >> 48) & 0x07f);
+ 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] = ((~data >> 31) & 0x80) | ((~data >> 8) & 0x7f);
+ buttons[0][0] = ~(GB(37,1,8) | GB(38,1,7) | GB(8,7,0));
return 0;
- case JS_SW_MODE_PP:
+ case JS_SW_TYPE_GP:
- if (js_sw_read_packet(info->io, 48, 16, JS_SW_EXT_STROBE, &data) != 48) return -1;
- if (!js_sw_parity(data) || (hat = (data >> 42) & 0xf) > 8) return -1;
+ for (i = 0; i < info->number * 15; i += 15) {
- axes[0][0] = (data >> 9) & 0x3ff;
- axes[0][1] = (data >> 19) & 0x3ff;
- axes[0][2] = (data >> 29) & 0x07f;
- axes[0][3] = (data >> 36) & 0x03f;
+ 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] = ~data & 0x1ff;
+ buttons[0][0] = ~GB(0,9,0);
return 0;
- case JS_SW_MODE_GP:
+ case JS_SW_TYPE_FSP:
- if (js_sw_read_packet(info->io, 15 * info->number, 5 * info->number,
- JS_SW_EXT_STROBE, &data) != 15 * info->number) return -1;
- if (js_sw_parity(data)) return -1;
+ if (!js_sw_parity(GB(0,43,0)) || (hat = GB(28,4,0)) > 8) return -1;
- for (i = 0; i < info->number; i++) {
- axes[i][0] = ((data >> 3) & 1) - ((data >> 2) & 1);
- axes[i][1] = ( data & 1) - ((data >> 1) & 1);
- buttons[i][0] = (~data >> 4) & 0x3ff;
- data >>= 15;
- }
+ 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;
- default:
- return -1;
+ 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;
}
/*
@@ -290,7 +500,7 @@ static int js_sw_close(struct js_dev *jd)
* SideWinders.
*/
-static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js_corr **corr)
+static void __init js_sw_init_corr(int num_axes, int type, int number, struct js_corr **corr)
{
int i, j;
@@ -305,9 +515,10 @@ static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js
corr[i][j].coef[3] = (1 << 29) / (511 - 32);
}
- switch (mode) {
+ switch (type) {
- case JS_SW_MODE_3DP:
+ case JS_SW_TYPE_3DP:
+ case JS_SW_TYPE_F23:
corr[i][2].type = JS_CORR_BROKEN;
corr[i][2].prec = 4;
@@ -320,33 +531,73 @@ static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js
break;
- case JS_SW_MODE_PP:
+ case JS_SW_TYPE_PP:
+ case JS_SW_TYPE_FFP:
corr[i][2].type = JS_CORR_BROKEN;
- corr[i][2].prec = 1;
- corr[i][2].coef[0] = 63 - 4;
- corr[i][2].coef[1] = 64 + 4;
- corr[i][2].coef[2] = (1 << 29) / (63 - 4);
- corr[i][2].coef[3] = (1 << 29) / (63 - 4);
+ 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 = 0;
- corr[i][3].coef[0] = 31 - 2;
- corr[i][3].coef[1] = 32 + 2;
- corr[i][3].coef[2] = (1 << 29) / (31 - 2);
- corr[i][3].coef[3] = (1 << 29) / (31 - 2);
+ 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++) {
+ 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;
@@ -358,83 +609,211 @@ static void __init js_sw_init_corr(int num_axes, int mode, int number, struct js
}
/*
+ * 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 *name;
- int i, j, axes, buttons;
- __u64 data;
- unsigned char u;
-
+ 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;
- if (((u = inb(io)) & 3) == 3) return port;
- outb(0xff,io);
- if (!((inb(io) ^ u) & ~u & 0xf)) return port;
- i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data);
+ 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);
- if (!i) {
- udelay(JS_SW_MIN_TIME);
- js_sw_init_digital(io);
- udelay(JS_SW_MAX_TIME);
- i = js_sw_read_packet(io, JS_SW_MAX_LENGTH, -1, JS_SW_EXT_STROBE, &data);
+#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 */
}
- switch (i) {
- case 0:
- return port;
- case 5:
- case 10:
- case 15:
- case 20:
- case 30:
- case 45:
- case 60:
- info.mode = JS_SW_MODE_GP;
- outb(0xff,io); /* Kick into 3-bit mode */
- udelay(JS_SW_MAX_TIME);
- i = js_sw_read_packet(io, 60, -1, JS_SW_EXT_STROBE, &data); /* Get total length */
- udelay(JS_SW_MIN_TIME);
- j = js_sw_read_packet(io, 15, -1, JS_SW_MIN_STROBE, &data); /* Get subpacket length */
- if (!i || !j) {
- printk(KERN_WARNING "joy-sidewinder: SideWinder GamePad detected (%d,%d),"
- " but not idenfitied.\n", i, j);
- return port;
+ 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;
}
- info.number = i / j;
- axes = 2; buttons = 10; name = "SideWinder GamePad";
- break;
- case 16:
- case 48:
- info.mode = JS_SW_MODE_PP; info.number = 1;
- axes = 6; buttons = 9; name = "SideWinder Precision Pro";
- break;
- case 64:
- case 66:
- info.mode = JS_SW_MODE_3DP; info.number = 1; info.optimize = 0;
- axes = 6; buttons = 8; name = "SideWinder 3D Pro";
- break;
- case 72:
- return port;
- default:
- printk(KERN_WARNING "joy-sidewinder: unknown joystick device detected "
- "(io=%#x, count=%d, data=0x%08x%08x), contact <vojtech@suse.cz>\n",
- io, i, (int)(data >> 32), (int)(data & 0xffffffff));
- return port;
+ }
+
+ } 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;
}
- info.io = io;
+#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 at %#x\n",
- js_register_device(port, i, axes, buttons, name, js_sw_open, js_sw_close), name, io);
- js_sw_init_corr(axes, info.mode, info.number, port->corr);
+ printk(KERN_INFO "js%d: %s%s at %#x [%d ns res %d-bit id %d data %d]\n",
+ js_register_device(port, i, axes[info.type], buttons[info.type],
+ names[info.type], js_sw_open, js_sw_close), names[info.type], comment, io,
+ 1000000 / speed, m, j, k);
+
+ js_sw_init_corr(axes[info.type], info.type, info.number, port->corr);
return port;
}
@@ -463,9 +842,9 @@ void cleanup_module(void)
int i;
struct js_sw_info *info;
- while (js_sw_port != NULL) {
+ while (js_sw_port) {
for (i = 0; i < js_sw_port->ndevs; i++)
- if (js_sw_port->devs[i] != NULL)
+ if (js_sw_port->devs[i])
js_unregister_device(js_sw_port->devs[i]);
info = js_sw_port->info;
release_region(info->io, 1);
diff --git a/drivers/char/joystick/joy-spaceball.c b/drivers/char/joystick/joy-spaceball.c
new file mode 100644
index 000000000..421a3cf8f
--- /dev/null
+++ b/drivers/char/joystick/joy-spaceball.c
@@ -0,0 +1,347 @@
+/*
+ * 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++;
+ MOD_INC_USE_COUNT;
+ 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);
+ }
+ MOD_DEC_USE_COUNT;
+ 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;
+
+ 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", js_sball_open, js_sball_close);
+
+ js_sball_init_corr(js_sball_port->corr);
+
+ MOD_INC_USE_COUNT;
+
+ 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,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ name: "spaceball",
+#endif
+ 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
new file mode 100644
index 000000000..464e59006
--- /dev/null
+++ b/drivers/char/joystick/joy-spaceorb.c
@@ -0,0 +1,305 @@
+/*
+ * 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++;
+ MOD_INC_USE_COUNT;
+ 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);
+ }
+ MOD_DEC_USE_COUNT;
+ 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;
+
+ 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", js_orb_open, js_orb_close);
+
+ js_orb_init_corr(js_orb_port->corr);
+
+ MOD_INC_USE_COUNT;
+
+ 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,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ name: "spaceorb",
+#endif
+ 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
index 1e79b3281..4cd3de23f 100644
--- a/drivers/char/joystick/joy-thrustmaster.c
+++ b/drivers/char/joystick/joy-thrustmaster.c
@@ -1,7 +1,9 @@
/*
* joy-thrustmaster.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -38,28 +40,15 @@
#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 25
+#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_WCS3 4
-
-#define JS_TM_MODE_MAX 5 /* Last mode + 1 */
-
-#define JS_TM_BYTE_A0 0
-#define JS_TM_BYTE_A1 1
-#define JS_TM_BYTE_A2 3
-#define JS_TM_BYTE_A3 4
-#define JS_TM_BYTE_A4 6
-#define JS_TM_BYTE_A5 7
-
-#define JS_TM_BYTE_D0 2
-#define JS_TM_BYTE_D1 5
-#define JS_TM_BYTE_D2 8
-#define JS_TM_BYTE_D3 9
+#define JS_TM_MODE_FGP 163
#define JS_TM_BYTE_ID 10
#define JS_TM_BYTE_REV 11
@@ -68,48 +57,39 @@
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;
};
-static int js_tm_id_to_def[JS_TM_MODE_MAX] = {0x00, 0x42, 0x00, 0x22, 0x00};
-
/*
* js_tm_read_packet() reads a ThrustMaster packet.
*/
static int js_tm_read_packet(int io, unsigned char *data)
{
- unsigned int t, t1;
+ unsigned int t, p;
unsigned char u, v, error;
int i, j;
unsigned long flags;
- int start = (js_time_speed * JS_TM_MAX_START) >> 10;
- int strobe = (js_time_speed * JS_TM_MAX_STROBE) >> 10;
-
error = 0;
i = j = 0;
+ p = t = JS_TM_MAX_START;
__save_flags(flags);
__cli();
outb(0xff,io);
-
- t = js_get_time();
-
- do {
- u = inb(io);
- t1 = js_get_time();
- } while ((u & 1) && js_delta(t1, t) < start);
-
- t = t1;
- u >>= 4;
+
+ v = inb(io) >> 4;
do {
- v = inb(io) >> 4;
- t1 = js_get_time();
- if ((u ^ v) & u & 2) {
+ t--;
+ u = v; v = inb(io) >> 4;
+ if (~v & u & 2) {
if (j) {
if (j < 9) { /* Data bit */
data[i] |= (~v & 1) << (j - 1);
@@ -124,10 +104,9 @@ static int js_tm_read_packet(int io, unsigned char *data)
error |= ~v & 1;
j++;
}
- t = t1;
+ p = t = (p - t) << 1;
}
- u = v;
- } while (!error && i < JS_TM_MAX_LENGTH && js_delta(t1,t) < strobe);
+ } while (!error && i < JS_TM_MAX_LENGTH && t > 0);
__restore_flags(flags);
@@ -142,46 +121,39 @@ 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)) {
- printk(KERN_WARNING "joy-thrustmaster: failed to read data packet\n");
- return -1;
- }
- if (data[JS_TM_BYTE_ID] != info->mode) {
- printk(KERN_WARNING "joy-thrustmaster: ID (%d) != mode (%d)\n",
- data[JS_TM_BYTE_ID], info->mode);
- return -1;
- }
- if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info->mode]) {
- printk(KERN_WARNING "joy-thrustmaster: DEF (%d) != def(mode) (%d)\n",
- data[JS_TM_BYTE_DEF], js_tm_id_to_def[info->mode]);
- return -1;
- }
+ 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][0] = data[JS_TM_BYTE_A0];
- axes[0][1] = data[JS_TM_BYTE_A1];
- axes[0][2] = data[JS_TM_BYTE_A2];
- axes[0][3] = data[JS_TM_BYTE_A3];
+ 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);
- axes[0][4] = ((data[JS_TM_BYTE_D0] >> 3) & 1) - ((data[JS_TM_BYTE_D0] >> 1) & 1);
- axes[0][5] = ((data[JS_TM_BYTE_D0] >> 2) & 1) - ( data[JS_TM_BYTE_D0] & 1);
-
- buttons[0][0] = ((data[JS_TM_BYTE_D0] >> 6) & 0x01) | ((data[JS_TM_BYTE_D0] >> 3) & 0x06)
- | ((data[JS_TM_BYTE_D0] >> 4) & 0x08) | ((data[JS_TM_BYTE_D1] >> 2) & 0x30);
+ 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:
- axes[0][0] = data[JS_TM_BYTE_A0];
- axes[0][1] = data[JS_TM_BYTE_A1];
+ buttons[0][0] = 0;
- buttons[0][0] = ( data[JS_TM_BYTE_D0] & 0x3f) | ((data[JS_TM_BYTE_D1] << 6) & 0xc0)
- | (( ((int) data[JS_TM_BYTE_D0]) << 2) & 0x300);
+ 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;
@@ -217,9 +189,9 @@ static int js_tm_close(struct js_dev *jd)
static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js_corr **corr)
{
- int j;
+ int j = 0;
- for (j = 0; j < num_axes; j++) {
+ for (; j < num_axes; j++) {
corr[0][j].type = JS_CORR_BROKEN;
corr[0][j].prec = 0;
corr[0][j].coef[0] = 127 - 2;
@@ -230,8 +202,7 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js
switch (mode) {
case JS_TM_MODE_M3DI: j = 4; break;
- case JS_TM_MODE_3DRP: j = 2; break;
- default: j = 0; break;
+ default: break;
}
for (; j < num_axes; j++) {
@@ -252,48 +223,46 @@ static void __init js_tm_init_corr(int num_axes, int mode, int **axes, struct js
static struct js_port __init *js_tm_probe(int io, struct js_port *port)
{
struct js_tm_info info;
- char *names[JS_TM_MODE_MAX] = { NULL, "ThrustMaster Millenium 3D Inceptor", NULL,
- "ThrustMaster Rage 3D Gamepad", "ThrustMaster WCS III" };
- char axes[JS_TM_MODE_MAX] = { 0, 6, 0, 2, 0 };
- char buttons[JS_TM_MODE_MAX] = { 0, 5, 0, 10, 0 };
-
+ 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 u;
+ unsigned char a, b;
+ int i;
if (check_region(io, 1)) return port;
- if (((u = inb(io)) & 3) == 3) return port;
- outb(0xff,io);
- if (!((inb(io) ^ u) & ~u & 0xf)) return port;
-
- if(js_tm_read_packet(io, data)) {
- printk(KERN_WARNING "joy-thrustmaster: probe - can't read packet\n");
- 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;
- if (info.mode >= JS_TM_MODE_MAX || !names[info.mode]) {
- printk(KERN_WARNING "joy-thrustmaster: unknown device detected "
- "(io=%#x, id=%d), contact <vojtech@suse.cz>\n",
- io, info.mode);
- return port;
- }
+ for (i = 0; models[i].id && models[i].id != info.mode; i++);
- if (data[JS_TM_BYTE_DEF] != js_tm_id_to_def[info.mode]) {
- printk(KERN_WARNING "joy-thrustmaster: wrong DEF (%d) for ID %d - should be %d\n",
- data[JS_TM_BYTE_DEF], info.mode, js_tm_id_to_def[info.mode]);
+ 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, axes[info.mode], buttons[info.mode],
- names[info.mode], js_tm_open, js_tm_close), names[info.mode], data[JS_TM_BYTE_REV], io);
- js_tm_init_corr(axes[info.mode], info.mode, port->axes, port->corr);
+ js_register_device(port, 0, a, b, name, js_tm_open, js_tm_close), name, data[JS_TM_BYTE_REV], io);
+ js_tm_init_corr(a, info.mode, port->axes, port->corr);
return port;
}
@@ -321,7 +290,7 @@ void cleanup_module(void)
{
struct js_tm_info *info;
- while (js_tm_port != NULL) {
+ while (js_tm_port) {
js_unregister_device(js_tm_port->devs[0]);
info = js_tm_port->info;
release_region(info->io, 1);
diff --git a/drivers/char/joystick/joy-turbografx.c b/drivers/char/joystick/joy-turbografx.c
index 6b30efe85..0211ea6f9 100644
--- a/drivers/char/joystick/joy-turbografx.c
+++ b/drivers/char/joystick/joy-turbografx.c
@@ -1,7 +1,9 @@
/*
* joy-turbografx.c Version 1.2
*
- * Copyright (c) 1998 Vojtech Pavlik
+ * Copyright (c) 1998-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -39,6 +41,7 @@
#include <linux/module.h>
#include <linux/string.h>
#include <linux/delay.h>
+#include <linux/init.h>
MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
@@ -57,18 +60,14 @@ MODULE_PARM(js_tg_3, "2-8i");
#define JS_TG_BUTTON4 0x01
#define JS_TG_BUTTON5 0x08
-static struct js_port* js_tg_port = NULL;
+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 {
-#ifdef USE_PARPORT
struct pardevice *port; /* parport device */
-#else
- int port; /* hw port */
-#endif
int sticks; /* joysticks connected */
};
@@ -109,9 +108,7 @@ int js_tg_open(struct js_dev *dev)
struct js_tg_info *info = dev->port->info;
if (!MOD_IN_USE) {
-#ifdef USE_PARPORT
if (parport_claim(info->port)) return -EBUSY;
-#endif
JS_PAR_CTRL_OUT(0x04, info->port);
}
MOD_INC_USE_COUNT;
@@ -129,9 +126,7 @@ int js_tg_close(struct js_dev *dev)
MOD_DEC_USE_COUNT;
if (!MOD_IN_USE) {
JS_PAR_CTRL_OUT(0x00, info->port);
-#ifdef USE_PARPORT
parport_release(info->port);
-#endif
}
return 0;
}
@@ -142,16 +137,12 @@ void cleanup_module(void)
struct js_tg_info *info;
int i;
- while (js_tg_port != NULL) {
+ while (js_tg_port) {
for (i = 0; i < js_tg_port->ndevs; i++)
- if (js_tg_port->devs[i] != NULL)
+ if (js_tg_port->devs[i])
js_unregister_device(js_tg_port->devs[i]);
info = js_tg_port->info;
-#ifdef USE_PARPORT
parport_unregister_device(info->port);
-#else
- release_region(info->port, 3);
-#endif
js_tg_port = js_unregister_port(js_tg_port);
}
}
@@ -186,33 +177,25 @@ 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;
-#ifdef USE_PARPORT
- {
- struct parport *pp;
- if (config[0] > 0x10)
- for (pp=parport_enumerate(); pp != NULL && (pp->base!=config[0]); pp=pp->next);
- else
- for (pp=parport_enumerate(); pp != NULL && (config[0]>0); pp=pp->next) config[0]--;
+ 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 == NULL) {
- 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;
+ if (!pp) {
+ printk(KERN_ERR "joy-tg: no such parport\n");
+ return port;
}
-#else
- info->port = config[0];
- if (check_region(info->port, 3)) return port;
- request_region(info->port, 3, "joystick (turbografx)");
-#endif
+
+ 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;
@@ -221,24 +204,14 @@ static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
for (i = 0; i < 7; i++)
if (config[i+1] > 0 && config[i+1] < 6) {
-#ifdef USE_PARPORT
printk(KERN_INFO "js%d: Multisystem joystick on %s\n",
js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
info->port->port->name);
-#else
- printk(KERN_INFO "js%d: Multisystem joystick at %#x\n",
- js_register_device(port, i, 2, config[i+1], "Multisystem joystick", js_tg_open, js_tg_close),
- info->port);
-#endif
info->sticks |= (1 << i);
}
if (!info->sticks) {
-#ifdef USE_PARPORT
parport_unregister_device(info->port);
-#else
- release_region(info->port, 3);
-#endif
return port;
}
@@ -248,18 +221,30 @@ static struct js_port __init *js_tg_probe(int *config, struct js_port *port)
}
#ifndef MODULE
-void __init js_tg_setup(char *str, int *ints)
+int __init js_tg_setup(SETUP_PARAM)
{
int i;
-
- if (!strcmp(str,"js_tg"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg[i] = ints[i+1];
- if (!strcmp(str,"js_tg_2"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_2[i] = ints[i+1];
- if (!strcmp(str,"js_tg_3"))
- for (i = 0; i <= ints[0] && i < 2; i++) js_tg_3[i] = ints[i+1];
-
+ 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
diff --git a/drivers/char/joystick/joy-warrior.c b/drivers/char/joystick/joy-warrior.c
new file mode 100644
index 000000000..fd7be5787
--- /dev/null
+++ b/drivers/char/joystick/joy-warrior.c
@@ -0,0 +1,318 @@
+/*
+ * 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 2: /* Static status (Send !S to get one) */
+#if 0
+ printk("joy-warrior: Static status:");
+ for (i = 0; i < 12; i++)
+ printk(" %02x", info->data[i]);
+ printk("\n");
+#endif
+ 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 4: /* Dynamic status */
+#if 0
+ printk("joy-warrior: Dynamic status:");
+ for (i = 0; i < 4; i++)
+ printk(" %02x", info->data[i]);
+ printk("\n");
+#endif
+ return;
+ 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;
+ 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++;
+ MOD_INC_USE_COUNT;
+ 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);
+ }
+ MOD_DEC_USE_COUNT;
+ 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;
+
+ 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", js_war_open, js_war_close),
+ tty->driver.name, MINOR(tty->device) - tty->driver.minor_start);
+
+ js_war_init_corr(js_war_port->corr);
+
+ MOD_INC_USE_COUNT;
+
+ 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,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
+ name: "warrior",
+#endif
+ 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
index 6c2abda1f..48af4c713 100644
--- a/drivers/char/joystick/joystick.c
+++ b/drivers/char/joystick/joystick.c
@@ -1,7 +1,9 @@
/*
- * joystick.c Version 1.2
+ * joystick.c Version 1.2
*
- * Copyright (c) 1996-1998 Vojtech Pavlik
+ * Copyright (c) 1996-1999 Vojtech Pavlik
+ *
+ * Sponsored by SuSE
*/
/*
@@ -33,7 +35,6 @@
#include <asm/io.h>
#include <asm/system.h>
#include <asm/segment.h>
-#include <linux/config.h>
#include <linux/delay.h>
#include <linux/errno.h>
#include <linux/joystick.h>
@@ -42,11 +43,9 @@
#include <linux/malloc.h>
#include <linux/mm.h>
#include <linux/module.h>
-#include <linux/version.h>
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-#include <linux/spinlock.h>
#include <linux/poll.h>
-#endif
+#include <linux/config.h>
+#include <linux/init.h>
/*
* Configurable parameters.
@@ -55,6 +54,15 @@
#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.
*/
@@ -75,18 +83,6 @@ spinlock_t js_lock = SPIN_LOCK_UNLOCKED;
static int js_use_count = 0;
/*
- * Exported variables.
- */
-
-unsigned int js_time_speed = 0;
-js_time_func js_get_time;
-js_delta_func js_delta;
-
-unsigned int js_time_speed_a = 0;
-js_time_func js_get_time_a;
-js_delta_func js_delta_a;
-
-/*
* Module info.
*/
@@ -94,244 +90,6 @@ MODULE_AUTHOR("Vojtech Pavlik <vojtech@suse.cz>");
MODULE_SUPPORTED_DEVICE("js");
/*
- * js_get_time_*() are different functions to get current time.
- * js_delta_*() are functions to compute time difference.
- */
-
-#ifdef __i386__
-
-static unsigned int js_get_time_rdtsc(void)
-{
- unsigned int x;
- __asm__ __volatile__ ( "rdtsc" : "=A" (x) );
- return x;
-}
-
-static unsigned int js_get_time_pit(void)
-{
- unsigned long flags;
- unsigned int x;
-
- __save_flags(flags);
- __cli();
- outb(0, 0x43);
- x = inb(0x40);
- x |= inb(0x40) << 8;
- __restore_flags(flags);
-
- return x;
-}
-
-static int js_delta_pit(unsigned int x, unsigned int y)
-{
- return y - x + ( y < x ? 1193180L / HZ : 0 );
-}
-
-static unsigned int js_get_time_counter(void)
-{
- static int time_counter = 0;
- return time_counter++;
-}
-
-#else
-#ifdef __alpha__
-
-static unsigned int js_get_time_rpcc(void)
-{
- unsigned int x;
- __asm__ __volatile__ ( "rpcc %0" : "=r" (x) );
- return x;
-}
-
-#else
-
-#ifndef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-static unsigned int js_get_time_system(void)
-{
- static struct timeval js_tv;
- get_fast_time(&js_tv);
- return js_tv.tv_sec * 1000000L + js_tv.tv_usec;
-}
-#endif
-#endif
-
-#endif
-#endif
-
-static int js_delta_normal(unsigned int x, unsigned int y)
-{
- return x - y;
-}
-
-/*
- * js_calibrate_time() calibrates a given timer.
- */
-
-static int __init js_calibrate_time(js_time_func get_time, js_delta_func delta)
-{
- unsigned int t1, t2, t3;
- unsigned long flags;
-
- __save_flags(flags);
- __cli();
- t1 = get_time();
- udelay(1000);
- t2 = get_time();
- t3 = get_time();
- __restore_flags(flags);
-
- return delta(t2, t1) - delta(t3, t2);
-}
-
-/*
- * js_calibrate_time_counter() calibrates the counter timer, which can't
- * be calibrated using the above function.
- */
-
-#ifdef __i386__
-
-static int __init js_calibrate_time_counter(void)
-{
- unsigned int i, j, t1, t2, t3;
-
- j = jiffies; do { inb(0x201); t1 = js_get_time_counter(); } while (j == jiffies);
- j = jiffies; do { inb(0x201); t2 = js_get_time_counter(); } while (j == jiffies);
-
- j = (t2 - t1) * HZ / 1000;
-
- t1 = js_get_time_pit();
- for (i = 0; i < 1000; i++) {
- inb(0x201);
- js_get_time_counter();
- }
- t2 = js_get_time_pit();
- t3 = js_get_time_pit();
-
- i = 1193180L / (js_delta_pit(t2, t1) - js_delta_pit(t3, t2));
-
- if (DIFF(i,j) > 5)
- printk(KERN_WARNING "js: Counter timer calibration unsure,"
- " pass1 (0.%d MHz) and pass2 (0.%d MHz) differ.\n", j, i);
-
- return (i + j) >> 1;
-}
-
-#endif
-
-/*
- * js_setup_time chooses the best available timers
- * on the system and calibrates them.
- */
-
-static int __init js_setup_time(void)
-{
- int t;
- char *name, *name_a;
-
- name = "";
- name_a = "";
- js_time_speed = 0;
- js_time_speed_a = 0;
-
-#ifdef __i386__
-
- t = js_calibrate_time(js_get_time_pit, js_delta_pit);
-
- if (DIFF(t, 1193) > 5)
- printk(KERN_WARNING "js: Measured PIT speed is %d.%03d MHz, but should be 1.193 MHz.\n"
- KERN_WARNING "js: This is probably caused by wrong BogoMIPS value. It is: %ld, should be: %ld.\n",
- t / 1000, t % 1000, loops_per_sec / 500000, loops_per_sec / (t * 500000 / 1193));
-
- if (JS_HAS_RDTSC && (t = js_calibrate_time(js_get_time_rdtsc, js_delta_normal)) > 0) {
-
- js_time_speed_a = t;
- js_get_time_a = js_get_time_rdtsc;
- js_delta_a = js_delta_normal;
- js_time_speed = t;
- js_get_time = js_get_time_rdtsc;
- js_delta = js_delta_normal;
- name = "RDTSC";
-
- } else {
-
- js_time_speed_a = t;
- js_get_time_a = js_get_time_pit;
- js_delta_a = js_delta_pit;
- name_a = "PIT";
-
- t = js_calibrate_time_counter();
-
- js_time_speed = t;
- js_get_time = js_get_time_counter;
- js_delta = js_delta_normal;
- name = "counter";
-
- }
-
-#else
-#ifdef __alpha__
-
- t = js_calibrate_time(js_get_time_rpcc, js_delta_normal);
-
- js_time_speed_a = t;
- js_get_time_a = js_get_time_rpcc;
- js_delta_a = js_delta_normal;
- js_time_speed = t;
- js_get_time = js_get_time_rpcc;
- js_delta = js_delta_normal;
- name = "RPCC";
-
-#else
-
-#ifndef MODULE
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
- t = js_calibrate_time(js_get_time_system, js_delta_normal);
-
- js_time_speed_a = t;
- js_get_time_a = js_get_time_system;
- js_delta_a = js_delta_normal;
- js_time_speed = t;
- js_get_time = js_get_time_system;
- js_delta = js_delta_normal;
- name = "system";
-#endif
-#endif
-
-#endif
-#endif
-
- printk(KERN_INFO "js: Version %d.%d.%d ",
- JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
-
- if (js_time_speed_a <= 0 || js_time_speed <= 0) {
- printk("\n");
- return -1;
- }
-
- printk("using ");
-
- if (js_time_speed > 10000) {
- t = js_time_speed / 1000 + (js_time_speed % 1000 >= 500);
- printk("%d MHz ", t);
- } else {
- t = js_time_speed / 10 + (js_time_speed % 10 >= 5);
- printk("%d.%02d MHz ", t / 100, t % 100);
- }
-
- if (js_get_time_a != js_get_time) {
- t = js_time_speed_a / 10 + (js_time_speed_a % 10 >= 5);
- printk("%s timer and %d.%02d MHz %s timer.\n",
- name, t / 100, t % 100, name_a);
- } else {
- printk("%s timer.\n", name);
- }
-
- return 0;
-}
-
-
-/*
* js_correct() performs correction of raw joystick data.
*/
@@ -365,7 +123,6 @@ 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.
@@ -458,14 +215,17 @@ static void js_do_timer(unsigned long data)
struct js_dev *curd = js_dev;
unsigned long flags;
- while (curp != NULL) {
- curp->read(curp->info, curp->axes, curp->buttons);
+ 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 != NULL) {
+ while (curd) {
if (data) {
js_process_data(curd);
js_sync_buff(curd);
@@ -486,11 +246,7 @@ static void js_do_timer(unsigned long data)
* space.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
static ssize_t js_read(struct file *file, char *buf, size_t count, loff_t *ppos)
-#else
-static int js_read(struct inode *inode, struct file *file, char *buf, int count)
-#endif
{
DECLARE_WAITQUEUE(wait, current);
struct js_event *buff = (void *) buf;
@@ -576,13 +332,8 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
tmpevent.time = jiffies * (1000/HZ);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
if (copy_to_user(&buff[written], &tmpevent, sizeof(struct js_event)))
retval = -EFAULT;
-#else
- if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event))))
- memcpy_tofs(&buff[written], &tmpevent, sizeof(struct js_event));
-#endif
curl->startup++;
written++;
@@ -594,17 +345,11 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
while ((jd->bhead != (new_tail = GOF(curl->tail))) && (written < blocks) && !retval) {
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
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;
-#else
- if (!(retval = verify_area(VERIFY_WRITE, &buff[written], sizeof(struct js_event)))) {
- memcpy_tofs(&buff[written], &jd->buff[new_tail], sizeof(struct js_event));
- put_user((__u32)(jd->buff[new_tail].time * (1000/HZ)), &buff[written].time);
- }
-#endif
+
curl->tail = new_tail;
written++;
}
@@ -625,15 +370,9 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
data.y = jd->num_axes < 2 ? 0 :
((js_correct(jd->new.axes[1], &jd->corr[1]) / 256) + 128) >> js_comp_glue.JS_CORR.y;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
retval = copy_to_user(buf, &data, sizeof(struct JS_DATA_TYPE)) ? -EFAULT : 0;
-#else
- if (!(retval = verify_area(VERIFY_WRITE, buf, sizeof(struct JS_DATA_TYPE)))) {
- memcpy_tofs(buf, &data, sizeof(struct JS_DATA_TYPE));
- }
-#endif
- curl->startup = 0;
+ curl->startup = jd->num_axes + jd->num_buttons;
curl->tail = GOB(jd->bhead);
if (!retval) retval = sizeof(struct JS_DATA_TYPE);
}
@@ -645,12 +384,12 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
if (orig_tail == jd->tail) {
new_tail = curl->tail;
curl = jd->list;
- while (curl != NULL && curl->tail != jd->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 == NULL) jd->tail = new_tail;
+ if (!curl) jd->tail = new_tail;
}
spin_unlock_irqrestore(&js_lock, flags);
@@ -662,8 +401,6 @@ static int js_read(struct inode *inode, struct file *file, char *buf, int count)
* js_poll() does select() support.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-
static unsigned int js_poll(struct file *file, poll_table *wait)
{
struct js_list *curl = file->private_data;
@@ -677,20 +414,6 @@ static unsigned int js_poll(struct file *file, poll_table *wait)
return retval;
}
-#else
-
-static int js_select(struct inode *inode, struct file *file, int sel_type, select_table *wait)
-{
- struct js_list *curl = file->private_data;
- if (sel_type == SEL_IN) {
- if (GOF(curl->tail) != curl->dev->bhead) return 1;
- select_wait(&curl->dev->wait, wait);
- }
- return 0;
-}
-
-#endif
-
/*
* js_ioctl handles misc ioctl calls.
*/
@@ -704,8 +427,6 @@ static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
curl = file->private_data;
jd = curl->dev;
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
-
switch (cmd) {
/*
@@ -758,95 +479,6 @@ static int js_ioctl(struct inode *inode, struct file *file, unsigned int cmd, un
}
}
-#else
-
- switch (cmd) {
-
-/*
- * 0.x compatibility
- */
-
- case JS_SET_CAL:
- if (verify_area(VERIFY_READ, (struct JS_DATA_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE))) return -EFAULT;
- memcpy_fromfs(&js_comp_glue.JS_CORR, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE));
- return 0;
- case JS_GET_CAL:
- if (verify_area(VERIFY_WRITE, (struct JS_DATA_TYPE *) arg,
- sizeof(struct JS_DATA_TYPE))) return -EFAULT;
- memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue.JS_CORR,
- sizeof(struct JS_DATA_TYPE));
- return 0;
- case JS_SET_TIMEOUT:
- if (verify_area(VERIFY_READ, (int *) arg, sizeof(int))) return -EFAULT;
- js_comp_glue.JS_TIMEOUT = get_user((int *) arg);
- return 0;
- case JS_GET_TIMEOUT:
- if (verify_area(VERIFY_WRITE, (int *) arg, sizeof(int))) return -EFAULT;
- put_user(js_comp_glue.JS_TIMEOUT, (int *) arg);
- return 0;
- case JS_SET_TIMELIMIT:
- if (verify_area(VERIFY_READ, (long *) arg, sizeof(long))) return -EFAULT;
- js_comp_glue.JS_TIMELIMIT = get_user((long *) arg);
- return 0;
- case JS_GET_TIMELIMIT:
- if (verify_area(VERIFY_WRITE, (long *) arg, sizeof(long))) return -EFAULT;
- put_user(js_comp_glue.JS_TIMELIMIT, (long *) arg);
- return 0;
- case JS_SET_ALL:
- if (verify_area(VERIFY_READ, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT;
- memcpy_fromfs(&js_comp_glue, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE));
- return 0;
- case JS_GET_ALL:
- if (verify_area(VERIFY_WRITE, (struct JS_DATA_SAVE_TYPE *) arg,
- sizeof(struct JS_DATA_SAVE_TYPE))) return -EFAULT;
- memcpy_tofs((struct JS_DATA_SAVE_TYPE *) arg, &js_comp_glue,
- sizeof(struct JS_DATA_SAVE_TYPE));
- return 0;
-
-/*
- * 1.x ioctl calls
- */
-
- case JSIOCGVERSION:
- if (verify_area(VERIFY_WRITE, (__u32 *) arg, sizeof(__u32))) return -EFAULT;
- put_user(JS_VERSION, (__u32 *) arg);
- return 0;
- case JSIOCGAXES:
- if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT;
- put_user(jd->num_axes, (__u8 *) arg);
- return 0;
- case JSIOCGBUTTONS:
- if (verify_area(VERIFY_WRITE, (__u8 *) arg, sizeof(__u8))) return -EFAULT;
- put_user(jd->num_buttons, (__u8 *) arg);
- return 0;
- case JSIOCSCORR:
- if (verify_area(VERIFY_READ, (struct js_corr *) arg,
- sizeof(struct js_corr) * jd->num_axes)) return -EFAULT;
- memcpy_fromfs(jd->corr, (struct js_corr *) arg,
- sizeof(struct js_corr) * jd->num_axes);
- return 0;
- case JSIOCGCORR:
- if (verify_area(VERIFY_WRITE, (struct js_corr *) arg,
- sizeof(struct js_corr) * jd->num_axes)) return -EFAULT;
- memcpy_tofs((struct js_corr *) arg,
- jd->corr, sizeof(struct js_corr) * jd->num_axes);
- return 0;
- default:
- if ((cmd & ~(_IOC_SIZEMASK << _IOC_SIZESHIFT)) == JSIOCGNAME(0)) {
- len = strlen(jd->name) + 1;
- if (verify_area(VERIFY_WRITE, (char *) arg, len)) return -EFAULT;
- if (len > _IOC_SIZE(cmd)) len = _IOC_SIZE(cmd);
- memcpy_tofs((char *) arg, jd->name, len);
- return len;
- }
- }
-
-#endif
-
return -EINVAL;
}
@@ -868,21 +500,20 @@ static int js_open(struct inode *inode, struct file *file)
spin_lock_irqsave(&js_lock, flags);
- while (i > 0 && jd != NULL) {
+ while (i > 0 && jd) {
jd = jd->next;
i--;
}
spin_unlock_irqrestore(&js_lock, flags);
- if (jd == NULL) return -ENODEV;
+ if (!jd) return -ENODEV;
if ((result = jd->open(jd))) return result;
- MOD_INC_USE_COUNT;
- if (!js_use_count++) js_do_timer(0);
+ if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL))) {
- if ((new = kmalloc(sizeof(struct js_list), GFP_KERNEL)) != NULL) {
+ MOD_INC_USE_COUNT;
spin_lock_irqsave(&js_lock, flags);
@@ -897,6 +528,8 @@ static int js_open(struct inode *inode, struct file *file)
spin_unlock_irqrestore(&js_lock, flags);
+ if (!js_use_count++) js_do_timer(0);
+
} else {
result = -ENOMEM;
}
@@ -909,11 +542,7 @@ static int js_open(struct inode *inode, struct file *file)
* used by it.
*/
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
static int js_release(struct inode *inode, struct file *file)
-#else
-static void js_release(struct inode *inode, struct file *file)
-#endif
{
struct js_list *curl = file->private_data;
struct js_dev *jd = curl->dev;
@@ -926,11 +555,11 @@ static void js_release(struct inode *inode, struct file *file)
while (*curp && (*curp != curl)) curp = &((*curp)->next);
*curp = (*curp)->next;
- if (jd->list != NULL)
+ if (jd->list)
if (curl->tail == jd->tail) {
curl = jd->list;
new_tail = curl->tail;
- while (curl != NULL && curl->tail != jd->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;
@@ -947,9 +576,7 @@ static void js_release(struct inode *inode, struct file *file)
jd->close(jd);
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
return 0;
-#endif
}
/*
@@ -968,7 +595,7 @@ static void js_dump_mem(void)
printk(",--- Dumping Devices:\n");
printk("| js_dev = %x\n", (int) js_dev);
- while (curd != NULL) {
+ while (curd) {
printk("| %s-device %x, next %x axes %d, buttons %d, port %x - %#x\n",
curd->next ? "|":"`",
(int) curd, (int) curd->next, curd->num_axes, curd->num_buttons, (int) curd->port, curd->port->io);
@@ -978,7 +605,7 @@ static void js_dump_mem(void)
printk(">--- Dumping ports:\n");
printk("| js_port = %x\n", (int) js_port);
- while (curp != NULL) {
+ while (curp) {
printk("| %s-port %x, next %x, io %#x, devices %d\n",
curp->next ? "|":"`",
(int) curp, (int) curp->next, curp->io, curp->ndevs);
@@ -1010,7 +637,7 @@ struct js_port *js_register_port(struct js_port *port,
int i;
unsigned long flags;
- if ((all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)) == NULL)
+ if (!(all = kmalloc(sizeof(struct js_port) + 4 * devs * sizeof(void*) + infos, GFP_KERNEL)))
return NULL;
curp = all;
@@ -1019,6 +646,8 @@ struct js_port *js_register_port(struct js_port *port,
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;
@@ -1036,7 +665,7 @@ struct js_port *js_register_port(struct js_port *port,
spin_lock_irqsave(&js_lock, flags);
- while (*ptrp != NULL) ptrp=&((*ptrp)->next);
+ while (*ptrp) ptrp=&((*ptrp)->next);
*ptrp = curp;
spin_unlock_irqrestore(&js_lock, flags);
@@ -1052,7 +681,9 @@ struct js_port *js_unregister_port(struct js_port *port)
spin_lock_irqsave(&js_lock, flags);
- while (*curp != NULL && (*curp != port)) curp = &((*curp)->next);
+ 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);
@@ -1072,9 +703,9 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
int i = 0;
unsigned long flags;
- if ((all = kmalloc(sizeof(struct js_dev) + 2 * axes * sizeof(int) +
+ 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)) == NULL)
+ axes * sizeof(struct js_corr) + strlen(name) + 1, GFP_KERNEL)))
return -1;
curd = all;
@@ -1082,10 +713,11 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
curd->next = NULL;
curd->list = NULL;
curd->port = port;
- init_waitqueue_head(&curd->wait);
curd->open = open;
curd->close = close;
+ init_waitqueue_head(&curd->wait);
+
curd->ahead = 0;
curd->bhead = 0;
curd->tail = JS_BUFF_SIZE - 1;
@@ -1108,7 +740,7 @@ int js_register_device(struct js_port *port, int number, int axes, int buttons,
spin_lock_irqsave(&js_lock, flags);
- while (*ptrd != NULL) { ptrd=&(*ptrd)->next; i++; }
+ while (*ptrd) { ptrd=&(*ptrd)->next; i++; }
*ptrd = curd;
spin_unlock_irqrestore(&js_lock, flags);
@@ -1123,7 +755,7 @@ void js_unregister_device(struct js_dev *dev)
spin_lock_irqsave(&js_lock, flags);
- while (*curd != NULL && (*curd != dev)) curd = &((*curd)->next);
+ while (*curd && (*curd != dev)) curd = &((*curd)->next);
*curd = (*curd)->next;
spin_unlock_irqrestore(&js_lock, flags);
@@ -1138,11 +770,7 @@ void js_unregister_device(struct js_dev *dev)
static struct file_operations js_fops =
{
read: js_read,
-#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,1,0)
poll: js_poll,
-#else
- select: js_select,
-#endif
ioctl: js_ioctl,
open: js_open,
release: js_release,
@@ -1159,15 +787,15 @@ int init_module(void)
int __init js_init(void)
#endif
{
- int result;
-
- js_setup_time();
if (register_chrdev(JOYSTICK_MAJOR, "js", &js_fops)) {
printk(KERN_ERR "js: unable to get major %d for joystick\n", JOYSTICK_MAJOR);
return -EBUSY;
}
+ printk(KERN_INFO "js: Joystick driver v%d.%d.%d (c) 1999 Vojtech Pavlik <vojtech@suse.cz>\n",
+ JS_VERSION >> 16 & 0xff, JS_VERSION >> 8 & 0xff, JS_VERSION & 0xff);
+
spin_lock_init(&js_lock);
init_timer(&js_timer);
@@ -1178,44 +806,61 @@ int __init js_init(void)
js_comp_glue.JS_TIMEOUT = JS_DEF_TIMEOUT;
js_comp_glue.JS_TIMELIMIT = JS_DEF_TIMELIMIT;
-#ifdef MODULE
- result = 0;
-#else
- result = -ENODEV;
+#ifndef MODULE
+#ifdef CONFIG_JOY_PCI
+ js_pci_init();
+#endif
#ifdef CONFIG_JOY_LIGHTNING
- if (!js_l4_init()) result = 0;
+ js_l4_init();
#endif
#ifdef CONFIG_JOY_SIDEWINDER
- if (!js_sw_init()) result = 0;
+ js_sw_init();
#endif
-#ifdef CONFIG_JOY_ASSASIN
- if (!js_as_init()) result = 0;
+#ifdef CONFIG_JOY_ASSASSIN
+ js_as_init();
#endif
#ifdef CONFIG_JOY_LOGITECH
- if (!js_lt_init()) result = 0;
+ js_lt_init();
#endif
#ifdef CONFIG_JOY_THRUSTMASTER
- if (!js_tm_init()) result = 0;
+ js_tm_init();
#endif
#ifdef CONFIG_JOY_GRAVIS
- if (!js_gr_init()) result = 0;
+ js_gr_init();
+#endif
+#ifdef CONFIG_JOY_CREATIVE
+ js_cr_init();
#endif
#ifdef CONFIG_JOY_ANALOG
- if (!js_an_init()) result = 0;
+ js_an_init();
#endif
#ifdef CONFIG_JOY_CONSOLE
- if (!js_console_init()) result = 0;
+ js_console_init();
#endif
#ifdef CONFIG_JOY_DB9
- if (!js_db9_init()) result = 0;
+ js_db9_init();
+#endif
+#ifdef CONFIG_JOY_TURBOGRAFX
+ js_tg_init();
#endif
#ifdef CONFIG_JOY_AMIGA
- if (!js_am_init()) result = 0;
+ 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
- if (result) printk(KERN_ERR "js: no joysticks found\n");
#endif
- return result;
+ return 0;
}
/*
@@ -1230,3 +875,4 @@ void cleanup_module(void)
printk(KERN_ERR "js: can't unregister device\n");
}
#endif
+